From e0b3ac9bb97fdfcfaa66696b3173f0dc6a386a8e Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 14 Oct 2007 06:15:56 +0000 Subject: Add network monitoring to intlclock --- gnome-panel.spec | 8 +- intlclock-changes-20071005.patch | 9697 ----------------------------- intlclock-changes-20071009.patch | 10832 -------------------------------- intlclock-changes-20071013.patch | 12214 ------------------------------------ intlclock-changes-20071014.patch | 12308 +++++++++++++++++++++++++++++++++++++ 5 files changed, 12314 insertions(+), 32745 deletions(-) delete mode 100644 intlclock-changes-20071005.patch delete mode 100644 intlclock-changes-20071009.patch delete mode 100644 intlclock-changes-20071013.patch create mode 100644 intlclock-changes-20071014.patch diff --git a/gnome-panel.spec b/gnome-panel.spec index c34adfa..7a6a43e 100644 --- a/gnome-panel.spec +++ b/gnome-panel.spec @@ -22,7 +22,7 @@ Summary: GNOME panel Name: gnome-panel Version: 2.20.0.1 -Release: 7%{?dist} +Release: 8%{?dist} URL: http://www.gnome.org Source0: http://download.gnome.org/sources/gnome-panel/2.20/%{name}-%{version}.tar.bz2 # we are upstream for this @@ -30,7 +30,7 @@ Source1: timezone.tar.gz # Novell intlclock, I don't think this has a canonical upstream location Source2: intlclock-1.0.tar.gz Patch98: timezone-changes.patch -Patch99: intlclock-changes-20071009.patch +Patch99: intlclock-changes-20071014.patch Patch100: dont-build-clock.patch Patch101: intlclock-build-fixes.patch @@ -94,6 +94,7 @@ BuildRequires: dbus-devel >= %{dbus_version} BuildRequires: PolicyKit-devel BuildRequires: gnome-applets-devel BuildRequires: librsvg2-devel +BuildRequires: NetworkManager-devel Patch0: gnome-panel-2.19.5-vendor.patch Patch1: gnome-panel-2.10.1-speak-to-us-ye-old-wise-fish.patch @@ -380,6 +381,9 @@ fi %{_datadir}/gtk-doc/html/* %changelog +* Sun Oct 14 2007 Matthias Clasen - 2.20.0.1-8 +- Add network monitoring to the intlclock + * Sat Oct 13 2007 Matthias Clasen - 2.20.0.1-7 - Another round of intlclock updates * show offsets in popup diff --git a/intlclock-changes-20071005.patch b/intlclock-changes-20071005.patch deleted file mode 100644 index 32496a1..0000000 --- a/intlclock-changes-20071005.patch +++ /dev/null @@ -1,9697 +0,0 @@ -diff --git a/configure.in b/configure.in -index 4e818da..6c75db1 100644 ---- a/configure.in -+++ b/configure.in -@@ -59,7 +59,7 @@ if test -n "$LIBECAL_REQUIREMENT"; then - fi - AM_CONDITIONAL(HAVE_LIBECAL, test -n "$LIBECAL_REQUIREMENT") - --PKG_CHECK_MODULES(INTLCLOCK, [ glib-2.0 gobject-2.0 gtk+-2.0 gdk-2.0 librsvg-2.0 libpanelapplet-2.0 libgnome-2.0 gconf-2.0 $LIBECAL_REQUIREMENT ]) -+PKG_CHECK_MODULES(INTLCLOCK, [ glib-2.0 gobject-2.0 gtk+-2.0 gdk-2.0 librsvg-2.0 libpanelapplet-2.0 libgnome-2.0 gconf-2.0 $LIBECAL_REQUIREMENT dbus-glib-1 gweather libxml-2.0 polkit polkit-dbus ]) - - AC_SUBST(INTLCLOCK_CFLAGS) - AC_SUBST(INTLCLOCK_LIBS) -diff --git a/data/GNOME_IntlClockApplet.xml b/data/GNOME_IntlClockApplet.xml -index dd2e8b8..152f26c 100644 ---- a/data/GNOME_IntlClockApplet.xml -+++ b/data/GNOME_IntlClockApplet.xml -@@ -1,9 +1,6 @@ - - - -- - - -diff --git a/data/GNOME_IntlClockApplet_Factory.server.in.in b/data/GNOME_IntlClockApplet_Factory.server.in.in -index 1446822..705fb76 100644 ---- a/data/GNOME_IntlClockApplet_Factory.server.in.in -+++ b/data/GNOME_IntlClockApplet_Factory.server.in.in -@@ -20,7 +20,7 @@ - - - -- -+ - - - 0 - - -- -+ - 6 - True - True -@@ -37,194 +37,35 @@ - False - - -- -- 6 -+ -+ 12 - True -- 4 -- 3 - False -- 6 -- 6 -+ 18 - - -- -- True -- Clock options: -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 0 -- 1 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 2 -- 3 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 3 -- 4 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 2 -- 3 -- 3 -- 4 -- fill -- -- -- -- -- -- -- True -- True -- Show s_econds -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- -- -- 1 -- 3 -- 2 -- 3 -- fill -- -- -- -- -- -- -+ - True - False - 6 - - -- -+ - True -- True -- 12 _hour format -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -+ <b>Clock Options</b> -+ False -+ True -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 - - - 0 -@@ -234,290 +75,15 @@ - - - -- -- True -- True -- 24 h_our format -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- 12hr_radio -- -- -- 0 -- False -- False -- -- -- -- -- 1 -- 2 -- 0 -- 1 -- fill -- fill -- -- -- -- -- -- True -- True -- Show the _date -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- -- -- 1 -- 2 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 2 -- 3 -- 0 -- 1 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 2 -- 3 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 1 -- 2 -- 3 -- 4 -- fill -- -- -- -- -- -- False -- True -- -- -- -- -- -- True -- General -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0.5 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- tab -- -- -- -- -- -- 6 -- True -- 8 -- 4 -- False -- 6 -- 6 -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 3 -- 4 -- 0 -- 1 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 3 -- 4 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- True -- GTK_POLICY_NEVER -- GTK_POLICY_NEVER -- GTK_SHADOW_IN -- GTK_CORNER_TOP_LEFT -- -- -- -- True -- True -- False -- False -- False -- True -- False -- False -- True -- -- -- -- -- 0 -- 3 -- 2 -- 8 -- fill -- -- -- -- -- -- True -- 0 -- 0.5 -- 0 -- 1 -- 0 -- 0 -- 0 -- 0 -- -- -- -+ - True - False -- 6 -+ 0 - - -- -+ - True -- -+ - False - False - GTK_JUSTIFY_LEFT -@@ -540,62 +106,163 @@ - - - -- -+ - True -- GTK_BUTTONBOX_START -+ False - 6 - - -- -- 24 -- 25 -+ - True -- True -- True -- gtk-add -- True -- GTK_RELIEF_NORMAL -- True -+ False -+ 13 -+ -+ -+ -+ True -+ True -+ 12 _hour format -+ True -+ GTK_RELIEF_NORMAL -+ True -+ False -+ False -+ True -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ True -+ 24 h_our format -+ True -+ GTK_RELIEF_NORMAL -+ True -+ False -+ False -+ True -+ 12hr_radio -+ -+ -+ 0 -+ False -+ False -+ -+ - -+ -+ 0 -+ True -+ True -+ - - - -- -- 24 -- 24 -+ - True -- True - True -- gtk-edit -- True -+ Show the _date -+ True - GTK_RELIEF_NORMAL - True -+ False -+ False -+ True - -+ -+ 0 -+ False -+ False -+ - - - -- -+ - True -- True - True -- gtk-remove -- True -+ Show _seconds -+ True - GTK_RELIEF_NORMAL - True -+ False -+ False -+ True - -+ -+ 0 -+ False -+ False -+ - - - - 0 -- False -- False -+ True -+ True - - -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ 0 -+ False -+ True -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ <b>Time Settings</b> -+ False -+ True -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ False -+ 0 - - -- -+ - True -- -+ - False - False - GTK_JUSTIFY_LEFT -@@ -616,115 +283,377 @@ - False - - -+ -+ -+ -+ True -+ False -+ 12 -+ -+ -+ -+ True -+ True -+ GTK_CALENDAR_SHOW_HEADING -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ Current Time: -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ Time: -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ 23:59:59 -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ False -+ 0 -+ -+ -+ -+ True -+ True -+ 1 -+ 0 -+ True -+ GTK_UPDATE_ALWAYS -+ False -+ True -+ 23 0 23 1 12 12 -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ 1 -+ 0 -+ True -+ GTK_UPDATE_ALWAYS -+ False -+ True -+ 59 0 59 1 30 30 -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ 1 -+ 0 -+ True -+ GTK_UPDATE_ALWAYS -+ False -+ True -+ 59 0 59 1 30 30 -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ 0 -+ False -+ True -+ -+ -+ -+ -+ -+ True -+ 1 -+ 1 -+ 0 -+ 0 -+ 0 -+ 0 -+ 0 -+ 0 -+ -+ -+ -+ True -+ True -+ Set System Time -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ - -+ -+ 0 -+ True -+ True -+ - - - -- 3 -- 4 -- 2 -- 8 -- -- fill -+ 0 -+ False -+ True - - -+ -+ -+ False -+ True -+ -+ - -- -- -- True -- True -- Show the world _map in the clock -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- -- -- 0 -- 1 -- 1 -- 2 -- fill -- -- -- -+ -+ -+ True -+ General -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ tab -+ -+ - -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0.5 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 2 -- 3 -- 1 -- 2 -- -- -- -+ -+ -+ 12 -+ True -+ False -+ 18 - - -- -+ - True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 1 -- 2 -- 1 -- 2 -- fill -- -- -- -+ False -+ 12 - -- -- -- True -- True -- S_how locations in the clock -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -+ -+ -+ True -+ True -+ GTK_POLICY_NEVER -+ GTK_POLICY_NEVER -+ GTK_SHADOW_IN -+ GTK_CORNER_TOP_LEFT -+ -+ -+ -+ True -+ True -+ False -+ False -+ False -+ True -+ False -+ False -+ True -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ GTK_BUTTONBOX_START -+ 6 -+ -+ -+ -+ 24 -+ 25 -+ True -+ True -+ True -+ gtk-add -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ -+ 24 -+ 24 -+ True -+ True -+ True -+ gtk-edit -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ True -+ gtk-remove -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ 0 -+ False -+ False -+ -+ - - -- 0 -- 3 -- 0 -- 1 -- fill -- -+ 0 -+ True -+ True - - - -@@ -735,7 +664,7 @@ - - - -- -+ - True - Locations - False -@@ -791,80 +720,6 @@ - 6 - - -- -- True -- True -- True -- GTK_RELIEF_NORMAL -- True -- -- -- -- True -- 0.5 -- 0.5 -- 0 -- 0 -- 0 -- 0 -- 0 -- 0 -- -- -- -- True -- False -- 2 -- -- -- -- True -- gtk-properties -- 4 -- 0.5 -- 0.5 -- 0 -- 0 -- -- -- 0 -- False -- False -- -- -- -- -- -- True -- Time _Settings -- True -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0.5 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- False -- False -- -- -- -- -- -- -- -- -- -- - - True - True -@@ -910,13 +765,13 @@ - - - -+ 12 - True - False -- 0 -+ 24 - - - -- 6 - True - 1 - 3 -@@ -926,7 +781,6 @@ - - - -- 6 - True - False - 6 -@@ -1088,27 +942,6 @@ - - - -- -- True -- True -- True -- True -- 0 -- -- True -- -- False -- -- -- 1 -- 4 -- 1 -- 2 -- -- -- -- -- - - True - Longitude: -@@ -1269,6 +1102,57 @@ South - - - -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ True -+ True -+ True -+ 0 -+ -+ True -+ -+ False -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ Find... -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 1 -+ 4 -+ 1 -+ 2 -+ fill -+ fill -+ -+ - - - 0 -@@ -1294,60 +1178,33 @@ South - - - -- -- 6 -+ - True -- False -- 0 -+ GTK_BUTTONBOX_END -+ 6 - - -- -+ - True -- GTK_BUTTONBOX_DEFAULT_STYLE -- 0 -+ True -+ True -+ gtk-cancel -+ True -+ GTK_RELIEF_NORMAL -+ True - -- -- 0 -- False -- False -- - - - -- -+ - True -- GTK_BUTTONBOX_END -- 6 -- -- -- -- True -- True -- True -- gtk-cancel -- True -- GTK_RELIEF_NORMAL -- True -- -- -- -- -- -- True -- True -- True -- gtk-ok -- True -- GTK_RELIEF_NORMAL -- True -- -- -+ True -+ True -+ gtk-ok -+ True -+ GTK_RELIEF_NORMAL -+ True - -- -- 0 -- True -- True -- - - - -@@ -1723,4 +1580,245 @@ South - - - -+ -+ -+ GTK_WINDOW_TOPLEVEL -+ GTK_WIN_POS_NONE -+ False -+ True -+ False -+ True -+ False -+ False -+ GDK_WINDOW_TYPE_HINT_NORMAL -+ GDK_GRAVITY_NORTH_WEST -+ True -+ False -+ -+ -+ -+ 12 -+ True -+ False -+ 24 -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ True -+ GTK_POLICY_AUTOMATIC -+ GTK_POLICY_AUTOMATIC -+ GTK_SHADOW_IN -+ GTK_CORNER_TOP_LEFT -+ -+ -+ -+ True -+ True -+ False -+ False -+ False -+ True -+ False -+ False -+ False -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ _Find: -+ True -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ find_location_entry -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ True -+ True -+ True -+ 0 -+ -+ True -+ -+ False -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ True -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ 0 -+ 0 -+ 0 -+ 0 -+ -+ -+ -+ True -+ False -+ 2 -+ -+ -+ -+ True -+ gtk-find -+ 4 -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ Find _Next -+ True -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ GTK_BUTTONBOX_END -+ 0 -+ -+ -+ -+ True -+ True -+ True -+ gtk-cancel -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ True -+ gtk-ok -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ - -diff --git a/data/intlclock.schemas.in b/data/intlclock.schemas.in -index 2ab6772..00fee4f 100644 ---- a/data/intlclock.schemas.in -+++ b/data/intlclock.schemas.in -@@ -89,41 +89,54 @@ - - - -- /schemas/apps/intlclock_applet/prefs/show_locations -+ /schemas/apps/intlclock_applet/prefs/cities -+ clock-applet -+ list -+ string -+ [] -+ -+ List of cities for the clock. -+ -+ List of cities to display in the international clock. -+ -+ -+ -+ -+ -+ /schemas/apps/intlclock_applet/prefs/expand_locations - clock-applet - bool - true - -- Show other locations in clock -+ Expand the location section in clock - -- If true, show a list of locations in the international clock. -+ If true, expand the list of locations in the international clock. - - - - - -- /schemas/apps/intlclock_applet/prefs/show_map -+ /schemas/apps/intlclock_applet/prefs/expand_tasks - clock-applet - bool - true - -- Show world map in clock -+ Expand the tasks section in clock - -- If true, show the world map in the international clock. -+ If true, expand the list of tasks in the international clock. - - - - - -- /schemas/apps/intlclock_applet/prefs/cities -+ /schemas/apps/intlclock_applet/prefs/expand_appointments - clock-applet -- list -- string -- [] -+ bool -+ true - -- List of cities for the clock. -+ Expand the appointments section in clock - -- List of cities to display in the international clock. -+ If true, expand the list of appointments in the international clock. - - - -diff --git a/intltool-extract.in b/intltool-extract.in -deleted file mode 100755 -index bb6c368..340fc8d ---- a/intltool-extract.in -+++ /dev/null -@@ -1,841 +0,0 @@ --#!@INTLTOOL_PERL@ -w --# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- -- --# --# The Intltool Message Extractor --# --# Copyright (C) 2000-2001, 2003 Free Software Foundation. --# --# Intltool 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. --# --# Intltool 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., 675 Mass Ave, Cambridge, MA 02139, USA. --# --# As a special exception to the GNU General Public License, if you --# distribute this file as part of a program that contains a --# configuration script generated by Autoconf, you may include it under --# the same distribution terms that you use for the rest of that program. --# --# Authors: Kenneth Christiansen --# Darin Adler --# -- --## Release information --my $PROGRAM = "intltool-extract"; --my $PACKAGE = "intltool"; --my $VERSION = "0.35.0"; -- --## Loaded modules --use strict; --use File::Basename; --use Getopt::Long; -- --## Scalars used by the option stuff --my $TYPE_ARG = "0"; --my $LOCAL_ARG = "0"; --my $HELP_ARG = "0"; --my $VERSION_ARG = "0"; --my $UPDATE_ARG = "0"; --my $QUIET_ARG = "0"; --my $SRCDIR_ARG = "."; -- --my $FILE; --my $OUTFILE; -- --my $gettext_type = ""; --my $input; --my %messages = (); --my %loc = (); --my %count = (); --my %comments = (); --my $strcount = 0; -- --my $XMLCOMMENT = ""; -- --## Use this instead of \w for XML files to handle more possible characters. --my $w = "[-A-Za-z0-9._:]"; -- --## Always print first --$| = 1; -- --## Handle options --GetOptions ( -- "type=s" => \$TYPE_ARG, -- "local|l" => \$LOCAL_ARG, -- "help|h" => \$HELP_ARG, -- "version|v" => \$VERSION_ARG, -- "update" => \$UPDATE_ARG, -- "quiet|q" => \$QUIET_ARG, -- "srcdir=s" => \$SRCDIR_ARG, -- ) or &error; -- --&split_on_argument; -- -- --## Check for options. --## This section will check for the different options. -- --sub split_on_argument { -- -- if ($VERSION_ARG) { -- &version; -- -- } elsif ($HELP_ARG) { -- &help; -- -- } elsif ($LOCAL_ARG) { -- &place_local; -- &extract; -- -- } elsif ($UPDATE_ARG) { -- &place_normal; -- &extract; -- -- } elsif (@ARGV > 0) { -- &place_normal; -- &message; -- &extract; -- -- } else { -- &help; -- -- } --} -- --sub place_normal { -- $FILE = $ARGV[0]; -- $OUTFILE = "$FILE.h"; --} -- --sub place_local { -- $FILE = $ARGV[0]; -- $OUTFILE = fileparse($FILE, ()); -- if (!-e "tmp/") { -- system("mkdir tmp/"); -- } -- $OUTFILE = "./tmp/$OUTFILE.h" --} -- --sub determine_type { -- if ($TYPE_ARG =~ /^gettext\/(.*)/) { -- $gettext_type=$1 -- } --} -- --## Sub for printing release information --sub version{ -- print <<_EOF_; --${PROGRAM} (${PACKAGE}) $VERSION --Copyright (C) 2000, 2003 Free Software Foundation, Inc. --Written by Kenneth Christiansen, 2000. -- --This is free software; see the source for copying conditions. There is NO --warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. --_EOF_ -- exit; --} -- --## Sub for printing usage information --sub help { -- print <<_EOF_; --Usage: ${PROGRAM} [OPTION]... [FILENAME] --Generates a header file from an XML source file. -- --It grabs all strings between <_translatable_node> and its end tag in --XML files. Read manpage (man ${PROGRAM}) for more info. -- -- --type=TYPE Specify the file type of FILENAME. Currently supports: -- "gettext/glade", "gettext/ini", "gettext/keys" -- "gettext/rfc822deb", "gettext/schemas", -- "gettext/scheme", "gettext/xml" -- -l, --local Writes output into current working directory -- (conflicts with --update) -- --update Writes output into the same directory the source file -- reside (conflicts with --local) -- --srcdir Root of the source tree -- -v, --version Output version information and exit -- -h, --help Display this help and exit -- -q, --quiet Quiet mode -- --Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE") --or send email to . --_EOF_ -- exit; --} -- --## Sub for printing error messages --sub error{ -- print STDERR "Try `${PROGRAM} --help' for more information.\n"; -- exit; --} -- --sub message { -- print "Generating C format header file for translation.\n" unless $QUIET_ARG; --} -- --sub extract { -- &determine_type; -- -- &convert; -- -- open OUT, ">$OUTFILE"; -- binmode (OUT) if $^O eq 'MSWin32'; -- &msg_write; -- close OUT; -- -- print "Wrote $OUTFILE\n" unless $QUIET_ARG; --} -- --sub convert { -- -- ## Reading the file -- { -- local (*IN); -- local $/; #slurp mode -- open (IN, "<$SRCDIR_ARG/$FILE") || die "can't open $SRCDIR_ARG/$FILE: $!"; -- $input = ; -- } -- -- &type_ini if $gettext_type eq "ini"; -- &type_keys if $gettext_type eq "keys"; -- &type_xml if $gettext_type eq "xml"; -- &type_glade if $gettext_type eq "glade"; -- &type_scheme if $gettext_type eq "scheme"; -- &type_schemas if $gettext_type eq "schemas"; -- &type_rfc822deb if $gettext_type eq "rfc822deb"; --} -- --sub entity_decode_minimal --{ -- local ($_) = @_; -- -- s/'/'/g; # ' -- s/"/"/g; # " -- s/&/&/g; -- -- return $_; --} -- --sub entity_decode --{ -- local ($_) = @_; -- -- s/'/'/g; # ' -- s/"/"/g; # " -- s/&/&/g; -- s/<//g; -- -- return $_; --} -- --sub escape_char --{ -- return '\"' if $_ eq '"'; -- return '\n' if $_ eq "\n"; -- return '\\' if $_ eq '\\'; -- -- return $_; --} -- --sub escape --{ -- my ($string) = @_; -- return join "", map &escape_char, split //, $string; --} -- --sub type_ini { -- ### For generic translatable desktop files ### -- while ($input =~ /^_.*=(.*)$/mg) { -- $messages{$1} = []; -- } --} -- --sub type_keys { -- ### For generic translatable mime/keys files ### -- while ($input =~ /^\s*_\w+=(.*)$/mg) { -- $messages{$1} = []; -- } --} -- --sub type_xml { -- ### For generic translatable XML files ### -- my $tree = readXml($input); -- parseTree(0, $tree); --} -- --sub print_var { -- my $var = shift; -- my $vartype = ref $var; -- -- if ($vartype =~ /ARRAY/) { -- my @arr = @{$var}; -- print "[ "; -- foreach my $el (@arr) { -- print_var($el); -- print ", "; -- } -- print "] "; -- } elsif ($vartype =~ /HASH/) { -- my %hash = %{$var}; -- print "{ "; -- foreach my $key (keys %hash) { -- print "$key => "; -- print_var($hash{$key}); -- print ", "; -- } -- print "} "; -- } else { -- print $var; -- } --} -- --# Same syntax as getAttributeString in intltool-merge.in.in, similar logic (look for ## differences comment) --sub getAttributeString --{ -- my $sub = shift; -- my $do_translate = shift || 1; -- my $language = shift || ""; -- my $translate = shift; -- my $result = ""; -- foreach my $e (reverse(sort(keys %{ $sub }))) { -- my $key = $e; -- my $string = $sub->{$e}; -- my $quote = '"'; -- -- $string =~ s/^[\s]+//; -- $string =~ s/[\s]+$//; -- -- if ($string =~ /^'.*'$/) -- { -- $quote = "'"; -- } -- $string =~ s/^['"]//g; -- $string =~ s/['"]$//g; -- -- ## differences from intltool-merge.in.in -- if ($key =~ /^_/) { -- $comments{entity_decode($string)} = $XMLCOMMENT if $XMLCOMMENT; -- $messages{entity_decode($string)} = []; -- $$translate = 2; -- } -- ## differences end here from intltool-merge.in.in -- $result .= " $key=$quote$string$quote"; -- } -- return $result; --} -- --# Verbatim copy from intltool-merge.in.in --sub getXMLstring --{ -- my $ref = shift; -- my $spacepreserve = shift || 0; -- my @list = @{ $ref }; -- my $result = ""; -- -- my $count = scalar(@list); -- my $attrs = $list[0]; -- my $index = 1; -- -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); -- -- while ($index < $count) { -- my $type = $list[$index]; -- my $content = $list[$index+1]; -- if (! $type ) { -- # We've got CDATA -- if ($content) { -- # lets strip the whitespace here, and *ONLY* here -- $content =~ s/\s+/ /gs if (!$spacepreserve); -- $result .= $content; -- } -- } elsif ( "$type" ne "1" ) { -- # We've got another element -- $result .= "<$type"; -- $result .= getAttributeString(@{$content}[0], 0); # no nested translatable elements -- if ($content) { -- my $subresult = getXMLstring($content, $spacepreserve); -- if ($subresult) { -- $result .= ">".$subresult . ""; -- } else { -- $result .= "/>"; -- } -- } else { -- $result .= "/>"; -- } -- } -- $index += 2; -- } -- return $result; --} -- --# Verbatim copy from intltool-merge.in.in, except for MULTIPLE_OUTPUT handling removed --# Translate list of nodes if necessary --sub translate_subnodes --{ -- my $fh = shift; -- my $content = shift; -- my $language = shift || ""; -- my $singlelang = shift || 0; -- my $spacepreserve = shift || 0; -- -- my @nodes = @{ $content }; -- -- my $count = scalar(@nodes); -- my $index = 0; -- while ($index < $count) { -- my $type = $nodes[$index]; -- my $rest = $nodes[$index+1]; -- traverse($fh, $type, $rest, $language, $spacepreserve); -- $index += 2; -- } --} -- --# Based on traverse() in intltool-merge.in.in --sub traverse --{ -- my $fh = shift; # unused, to allow us to sync code between -merge and -extract -- my $nodename = shift; -- my $content = shift; -- my $language = shift || ""; -- my $spacepreserve = shift || 0; -- -- if ($nodename && "$nodename" eq "1") { -- $XMLCOMMENT = $content; -- } elsif ($nodename) { -- # element -- my @all = @{ $content }; -- my $attrs = shift @all; -- my $translate = 0; -- my $outattr = getAttributeString($attrs, 1, $language, \$translate); -- -- if ($nodename =~ /^_/) { -- $translate = 1; -- $nodename =~ s/^_//; -- } -- my $lookup = ''; -- -- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- -- if ($translate) { -- $lookup = getXMLstring($content, $spacepreserve); -- if (!$spacepreserve) { -- $lookup =~ s/^\s+//s; -- $lookup =~ s/\s+$//s; -- } -- -- if ($lookup && $translate != 2) { -- $comments{$lookup} = $XMLCOMMENT if $XMLCOMMENT; -- $messages{$lookup} = []; -- } elsif ($translate == 2) { -- translate_subnodes($fh, \@all, $language, 1, $spacepreserve); -- } -- } else { -- $XMLCOMMENT = ""; -- my $count = scalar(@all); -- if ($count > 0) { -- my $index = 0; -- while ($index < $count) { -- my $type = $all[$index]; -- my $rest = $all[$index+1]; -- traverse($fh, $type, $rest, $language, $spacepreserve); -- $index += 2; -- } -- } -- } -- $XMLCOMMENT = ""; -- } --} -- -- --# Verbatim copy from intltool-merge.in.in, $fh for compatibility --sub parseTree --{ -- my $fh = shift; -- my $ref = shift; -- my $language = shift || ""; -- -- my $name = shift @{ $ref }; -- my $cont = shift @{ $ref }; -- -- while (!$name || "$name" eq "1") { -- $name = shift @{ $ref }; -- $cont = shift @{ $ref }; -- } -- -- my $spacepreserve = 0; -- my $attrs = @{$cont}[0]; -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- -- traverse($fh, $name, $cont, $language, $spacepreserve); --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_comment --{ -- my $expat = shift; -- my $data = $expat->original_string(); -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- $data =~ s/^$//s; -- push @$clist, 1 => $data; --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_cdatastart --{ -- my $expat = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- push @$clist, 0 => $expat->original_string(); --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_cdataend --{ -- my $expat = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- $clist->[$pos] .= $expat->original_string(); --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_char --{ -- my $expat = shift; -- my $text = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- # Use original_string so that we retain escaped entities -- # in CDATA sections. -- # -- if ($pos > 0 and $clist->[$pos - 1] eq '0') { -- $clist->[$pos] .= $expat->original_string(); -- } else { -- push @$clist, 0 => $expat->original_string(); -- } --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_start --{ -- my $expat = shift; -- my $tag = shift; -- my @origlist = (); -- -- # Use original_string so that we retain escaped entities -- # in attribute values. We must convert the string to an -- # @origlist array to conform to the structure of the Tree -- # Style. -- # -- my @original_array = split /\x/, $expat->original_string(); -- my $source = $expat->original_string(); -- -- # Remove leading tag. -- # -- $source =~ s|^\s*<\s*(\S+)||s; -- -- # Grab attribute key/value pairs and push onto @origlist array. -- # -- while ($source) -- { -- if ($source =~ /^\s*([\w:-]+)\s*[=]\s*["]/) -- { -- $source =~ s|^\s*([\w:-]+)\s*[=]\s*["]([^"]*)["]||s; -- push @origlist, $1; -- push @origlist, '"' . $2 . '"'; -- } -- elsif ($source =~ /^\s*([\w:-]+)\s*[=]\s*[']/) -- { -- $source =~ s|^\s*([\w:-]+)\s*[=]\s*[']([^']*)[']||s; -- push @origlist, $1; -- push @origlist, "'" . $2 . "'"; -- } -- else -- { -- last; -- } -- } -- -- my $ol = [ { @origlist } ]; -- -- push @{ $expat->{Lists} }, $expat->{Curlist}; -- push @{ $expat->{Curlist} }, $tag => $ol; -- $expat->{Curlist} = $ol; --} -- --# Copied from intltool-merge.in.in and added comment handler. --sub readXml --{ -- my $xmldoc = shift || return; -- my $ret = eval 'require XML::Parser'; -- if(!$ret) { -- die "You must have XML::Parser installed to run $0\n\n"; -- } -- my $xp = new XML::Parser(Style => 'Tree'); -- $xp->setHandlers(Char => \&intltool_tree_char); -- $xp->setHandlers(Start => \&intltool_tree_start); -- $xp->setHandlers(CdataStart => \&intltool_tree_cdatastart); -- $xp->setHandlers(CdataEnd => \&intltool_tree_cdataend); -- -- ## differences from intltool-merge.in.in -- $xp->setHandlers(Comment => \&intltool_tree_comment); -- ## differences end here from intltool-merge.in.in -- -- my $tree = $xp->parse($xmldoc); -- #print_var($tree); -- --# Hello thereHowdydo --# would be: --# [foo, [{}, 1, "comment", head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]], bar, --# [{}, 0, "Howdy", ref, [{}]], 0, "do" ] ] -- -- return $tree; --} -- --sub type_schemas { -- ### For schemas XML files ### -- -- # FIXME: We should handle escaped < (less than) -- while ($input =~ / -- \s* -- (\s*(?:\s*)?(.*?)\s*<\/default>\s*)? -- (\s*(?:\s*)?(.*?)\s*<\/short>\s*)? -- (\s*(?:\s*)?(.*?)\s*<\/long>\s*)? -- <\/locale> -- /sgx) { -- my @totranslate = ($3,$6,$9); -- my @eachcomment = ($2,$5,$8); -- foreach (@totranslate) { -- my $currentcomment = shift @eachcomment; -- next if !$_; -- s/\s+/ /g; -- $messages{entity_decode_minimal($_)} = []; -- $comments{entity_decode_minimal($_)} = $currentcomment if (defined($currentcomment)); -- } -- } --} -- --sub type_rfc822deb { -- ### For rfc822-style Debian configuration files ### -- -- my $lineno = 1; -- my $type = ''; -- while ($input =~ /\G(.*?)(^|\n)(_+)([^:]+):[ \t]*(.*?)(?=\n\S|$)/sg) -- { -- my ($pre, $newline, $underscore, $tag, $text) = ($1, $2, $3, $4, $5); -- while ($pre =~ m/\n/g) -- { -- $lineno ++; -- } -- $lineno += length($newline); -- my @str_list = rfc822deb_split(length($underscore), $text); -- for my $str (@str_list) -- { -- $strcount++; -- $messages{$str} = []; -- $loc{$str} = $lineno; -- $count{$str} = $strcount; -- my $usercomment = ''; -- while($pre =~ s/(^|\n)#([^\n]*)$//s) -- { -- $usercomment = "\n" . $2 . $usercomment; -- } -- $comments{$str} = $tag . $usercomment; -- } -- $lineno += ($text =~ s/\n//g); -- } --} -- --sub rfc822deb_split { -- # Debian defines a special way to deal with rfc822-style files: -- # when a value contain newlines, it consists of -- # 1. a short form (first line) -- # 2. a long description, all lines begin with a space, -- # and paragraphs are separated by a single dot on a line -- # This routine returns an array of all paragraphs, and reformat -- # them. -- # When first argument is 2, the string is a comma separated list of -- # values. -- my $type = shift; -- my $text = shift; -- $text =~ s/^[ \t]//mg; -- return (split(/, */, $text, 0)) if $type ne 1; -- return ($text) if $text !~ /\n/; -- -- $text =~ s/([^\n]*)\n//; -- my @list = ($1); -- my $str = ''; -- for my $line (split (/\n/, $text)) -- { -- chomp $line; -- if ($line =~ /^\.\s*$/) -- { -- # New paragraph -- $str =~ s/\s*$//; -- push(@list, $str); -- $str = ''; -- } -- elsif ($line =~ /^\s/) -- { -- # Line which must not be reformatted -- $str .= "\n" if length ($str) && $str !~ /\n$/; -- $line =~ s/\s+$//; -- $str .= $line."\n"; -- } -- else -- { -- # Continuation line, remove newline -- $str .= " " if length ($str) && $str !~ /\n$/; -- $str .= $line; -- } -- } -- $str =~ s/\s*$//; -- push(@list, $str) if length ($str); -- return @list; --} -- --sub type_glade { -- ### For translatable Glade XML files ### -- -- my $tags = "label|title|text|format|copyright|comments|preview_text|tooltip|message"; -- -- while ($input =~ /<($tags)>([^<]+)<\/($tags)>/sg) { -- # Glade sometimes uses tags that normally mark translatable things for -- # little bits of non-translatable content. We work around this by not -- # translating strings that only includes something like label4 or window1. -- $messages{entity_decode($2)} = [] unless $2 =~ /^(window|label|dialog)[0-9]+$/; -- } -- -- while ($input =~ /(..[^<]*)<\/items>/sg) { -- for my $item (split (/\n/, $1)) { -- $messages{entity_decode($item)} = []; -- } -- } -- -- ## handle new glade files -- while ($input =~ /<(property|atkproperty)\s+[^>]*translatable\s*=\s*"yes"(?:\s+[^>]*comments\s*=\s*"([^"]*)")?[^>]*>([^<]+)<\/\1>/sg) { -- $messages{entity_decode($3)} = [] unless $3 =~ /^(window|label)[0-9]+$/; -- if (defined($2) and !($3 =~ /^(window|label)[0-9]+$/)) { -- $comments{entity_decode($3)} = entity_decode($2) ; -- } -- } -- while ($input =~ /]*)"\s+description="([^>]+)"\/>/sg) { -- $messages{entity_decode_minimal($2)} = []; -- } --} -- --sub type_scheme { -- my ($line, $i, $state, $str, $trcomment, $char); -- for $line (split(/\n/, $input)) { -- $i = 0; -- $state = 0; # 0 - nothing, 1 - string, 2 - translatable string -- while ($i < length($line)) { -- if (substr($line,$i,1) eq "\"") { -- if ($state == 2) { -- $comments{$str} = $trcomment if ($trcomment); -- $messages{$str} = []; -- $str = ''; -- $state = 0; $trcomment = ""; -- } elsif ($state == 1) { -- $str = ''; -- $state = 0; $trcomment = ""; -- } else { -- $state = 1; -- $str = ''; -- if ($i>0 && substr($line,$i-1,1) eq '_') { -- $state = 2; -- } -- } -- } elsif (!$state) { -- if (substr($line,$i,1) eq ";") { -- $trcomment = substr($line,$i+1); -- $trcomment =~ s/^;*\s*//; -- $i = length($line); -- } elsif ($trcomment && substr($line,$i,1) !~ /\s|\(|\)|_/) { -- $trcomment = ""; -- } -- } else { -- if (substr($line,$i,1) eq "\\") { -- $char = substr($line,$i+1,1); -- if ($char ne "\"" && $char ne "\\") { -- $str = $str . "\\"; -- } -- $i++; -- } -- $str = $str . substr($line,$i,1); -- } -- $i++; -- } -- } --} -- --sub msg_write { -- my @msgids; -- if (%count) -- { -- @msgids = sort { $count{$a} <=> $count{$b} } keys %count; -- } -- else -- { -- @msgids = sort keys %messages; -- } -- for my $message (@msgids) -- { -- my $offsetlines = 1; -- $offsetlines++ if $message =~ /%/; -- if (defined ($comments{$message})) -- { -- while ($comments{$message} =~ m/\n/g) -- { -- $offsetlines++; -- } -- } -- print OUT "# ".($loc{$message} - $offsetlines). " \"$FILE\"\n" -- if defined $loc{$message}; -- print OUT "/* ".$comments{$message}." */\n" -- if defined $comments{$message}; -- print OUT "/* xgettext:no-c-format */\n" if $message =~ /%/; -- -- my @lines = split (/\n/, $message, -1); -- for (my $n = 0; $n < @lines; $n++) -- { -- if ($n == 0) -- { -- print OUT "char *s = N_(\""; -- } -- else -- { -- print OUT " \""; -- } -- -- print OUT escape($lines[$n]); -- -- if ($n < @lines - 1) -- { -- print OUT "\\n\"\n"; -- } -- else -- { -- print OUT "\");\n"; -- } -- } -- } --} -- -diff --git a/intltool-extract.in b/intltool-extract.in -new file mode 120000 -index bb6c368..340fc8d ---- /dev/null -+++ b/intltool-extract.in -@@ -0,0 +1 @@ -+/usr/share/intltool/intltool-extract.in -\ No newline at end of file -diff --git a/intltool-merge.in b/intltool-merge.in -deleted file mode 100755 -index d0535ab..2238bbd ---- a/intltool-merge.in -+++ /dev/null -@@ -1,1356 +0,0 @@ --#!@INTLTOOL_PERL@ -w --# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- -- --# --# The Intltool Message Merger --# --# Copyright (C) 2000, 2003 Free Software Foundation. --# Copyright (C) 2000, 2001 Eazel, Inc --# --# Intltool is free software; you can redistribute it and/or --# modify it under the terms of the GNU General Public License --# version 2 published by the Free Software Foundation. --# --# Intltool 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., 675 Mass Ave, Cambridge, MA 02139, USA. --# --# As a special exception to the GNU General Public License, if you --# distribute this file as part of a program that contains a --# configuration script generated by Autoconf, you may include it under --# the same distribution terms that you use for the rest of that program. --# --# Authors: Maciej Stachowiak --# Kenneth Christiansen --# Darin Adler --# --# Proper XML UTF-8'ification written by Cyrille Chepelov --# -- --## Release information --my $PROGRAM = "intltool-merge"; --my $PACKAGE = "intltool"; --my $VERSION = "0.35.0"; -- --## Loaded modules --use strict; --use Getopt::Long; --use Text::Wrap; --use File::Basename; -- --my $must_end_tag = -1; --my $last_depth = -1; --my $translation_depth = -1; --my @tag_stack = (); --my @entered_tag = (); --my @translation_strings = (); --my $leading_space = ""; -- --## Scalars used by the option stuff --my $HELP_ARG = 0; --my $VERSION_ARG = 0; --my $BA_STYLE_ARG = 0; --my $XML_STYLE_ARG = 0; --my $KEYS_STYLE_ARG = 0; --my $DESKTOP_STYLE_ARG = 0; --my $SCHEMAS_STYLE_ARG = 0; --my $RFC822DEB_STYLE_ARG = 0; --my $QUIET_ARG = 0; --my $PASS_THROUGH_ARG = 0; --my $UTF8_ARG = 0; --my $MULTIPLE_OUTPUT = 0; --my $cache_file; -- --## Handle options --GetOptions --( -- "help" => \$HELP_ARG, -- "version" => \$VERSION_ARG, -- "quiet|q" => \$QUIET_ARG, -- "oaf-style|o" => \$BA_STYLE_ARG, ## for compatibility -- "ba-style|b" => \$BA_STYLE_ARG, -- "xml-style|x" => \$XML_STYLE_ARG, -- "keys-style|k" => \$KEYS_STYLE_ARG, -- "desktop-style|d" => \$DESKTOP_STYLE_ARG, -- "schemas-style|s" => \$SCHEMAS_STYLE_ARG, -- "rfc822deb-style|r" => \$RFC822DEB_STYLE_ARG, -- "pass-through|p" => \$PASS_THROUGH_ARG, -- "utf8|u" => \$UTF8_ARG, -- "multiple-output|m" => \$MULTIPLE_OUTPUT, -- "cache|c=s" => \$cache_file -- ) or &error; -- --my $PO_DIR; --my $FILE; --my $OUTFILE; -- --my %po_files_by_lang = (); --my %translations = (); --my $iconv = $ENV{"ICONV"} || $ENV{"INTLTOOL_ICONV"} || "@INTLTOOL_ICONV@"; --my $devnull = ($^O eq 'MSWin32' ? 'NUL:' : '/dev/null'); -- --# Use this instead of \w for XML files to handle more possible characters. --my $w = "[-A-Za-z0-9._:]"; -- --# XML quoted string contents --my $q = "[^\\\"]*"; -- --## Check for options. -- --if ($VERSION_ARG) --{ -- &print_version; --} --elsif ($HELP_ARG) --{ -- &print_help; --} --elsif ($BA_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &ba_merge_translations; -- &finalize; --} --elsif ($XML_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &xml_merge_output; -- &finalize; --} --elsif ($KEYS_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &keys_merge_translations; -- &finalize; --} --elsif ($DESKTOP_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &desktop_merge_translations; -- &finalize; --} --elsif ($SCHEMAS_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &schemas_merge_translations; -- &finalize; --} --elsif ($RFC822DEB_STYLE_ARG && @ARGV > 2) --{ -- &preparation; -- &print_message; -- &rfc822deb_merge_translations; -- &finalize; --} --else --{ -- &print_help; --} -- --exit; -- --## Sub for printing release information --sub print_version --{ -- print <<_EOF_; --${PROGRAM} (${PACKAGE}) ${VERSION} --Written by Maciej Stachowiak, Darin Adler and Kenneth Christiansen. -- --Copyright (C) 2000-2003 Free Software Foundation, Inc. --Copyright (C) 2000-2001 Eazel, Inc. --This is free software; see the source for copying conditions. There is NO --warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. --_EOF_ -- exit; --} -- --## Sub for printing usage information --sub print_help --{ -- print <<_EOF_; --Usage: ${PROGRAM} [OPTION]... PO_DIRECTORY FILENAME OUTPUT_FILE --Generates an output file that includes some localized attributes from an --untranslated source file. -- --Mandatory options: (exactly one must be specified) -- -b, --ba-style includes translations in the bonobo-activation style -- -d, --desktop-style includes translations in the desktop style -- -k, --keys-style includes translations in the keys style -- -s, --schemas-style includes translations in the schemas style -- -r, --rfc822deb-style includes translations in the RFC822 style -- -x, --xml-style includes translations in the standard xml style -- --Other options: -- -u, --utf8 convert all strings to UTF-8 before merging -- (default for everything except RFC822 style) -- -p, --pass-through deprecated, does nothing and issues a warning -- -m, --multiple-output output one localized file per locale, instead of -- a single file containing all localized elements -- -c, --cache=FILE specify cache file name -- (usually \$top_builddir/po/.intltool-merge-cache) -- -q, --quiet suppress most messages -- --help display this help and exit -- --version output version information and exit -- --Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE") --or send email to . --_EOF_ -- exit; --} -- -- --## Sub for printing error messages --sub print_error --{ -- print STDERR "Try `${PROGRAM} --help' for more information.\n"; -- exit; --} -- -- --sub print_message --{ -- print "Merging translations into $OUTFILE.\n" unless $QUIET_ARG; --} -- -- --sub preparation --{ -- $PO_DIR = $ARGV[0]; -- $FILE = $ARGV[1]; -- $OUTFILE = $ARGV[2]; -- -- &gather_po_files; -- &get_translation_database; --} -- --# General-purpose code for looking up translations in .po files -- --sub po_file2lang --{ -- my ($tmp) = @_; -- $tmp =~ s/^.*\/(.*)\.po$/$1/; -- return $tmp; --} -- --sub gather_po_files --{ -- for my $po_file (glob "$PO_DIR/*.po") { -- $po_files_by_lang{po_file2lang($po_file)} = $po_file; -- } --} -- --sub get_local_charset --{ -- my ($encoding) = @_; -- my $alias_file = $ENV{"G_CHARSET_ALIAS"} || "@INTLTOOL_LIBDIR@/charset.alias"; -- -- # seek character encoding aliases in charset.alias (glib) -- -- if (open CHARSET_ALIAS, $alias_file) -- { -- while () -- { -- next if /^\#/; -- return $1 if (/^\s*([-._a-zA-Z0-9]+)\s+$encoding\b/i) -- } -- -- close CHARSET_ALIAS; -- } -- -- # if not found, return input string -- -- return $encoding; --} -- --sub get_po_encoding --{ -- my ($in_po_file) = @_; -- my $encoding = ""; -- -- open IN_PO_FILE, $in_po_file or die; -- while () -- { -- ## example: "Content-Type: text/plain; charset=ISO-8859-1\n" -- if (/Content-Type\:.*charset=([-a-zA-Z0-9]+)\\n/) -- { -- $encoding = $1; -- last; -- } -- } -- close IN_PO_FILE; -- -- if (!$encoding) -- { -- print STDERR "Warning: no encoding found in $in_po_file. Assuming ISO-8859-1\n" unless $QUIET_ARG; -- $encoding = "ISO-8859-1"; -- } -- -- system ("$iconv -f $encoding -t UTF-8 <$devnull 2>$devnull"); -- if ($?) { -- $encoding = get_local_charset($encoding); -- } -- -- return $encoding --} -- --sub utf8_sanity_check --{ -- print STDERR "Warning: option --pass-through has been removed.\n" if $PASS_THROUGH_ARG; -- $UTF8_ARG = 1; --} -- --sub get_translation_database --{ -- if ($cache_file) { -- &get_cached_translation_database; -- } else { -- &create_translation_database; -- } --} -- --sub get_newest_po_age --{ -- my $newest_age; -- -- foreach my $file (values %po_files_by_lang) -- { -- my $file_age = -M $file; -- $newest_age = $file_age if !$newest_age || $file_age < $newest_age; -- } -- -- $newest_age = 0 if !$newest_age; -- -- return $newest_age; --} -- --sub create_cache --{ -- print "Generating and caching the translation database\n" unless $QUIET_ARG; -- -- &create_translation_database; -- -- open CACHE, ">$cache_file" || die; -- print CACHE join "\x01", %translations; -- close CACHE; --} -- --sub load_cache --{ -- print "Found cached translation database\n" unless $QUIET_ARG; -- -- my $contents; -- open CACHE, "<$cache_file" || die; -- { -- local $/; -- $contents = ; -- } -- close CACHE; -- %translations = split "\x01", $contents; --} -- --sub get_cached_translation_database --{ -- my $cache_file_age = -M $cache_file; -- if (defined $cache_file_age) -- { -- if ($cache_file_age <= &get_newest_po_age) -- { -- &load_cache; -- return; -- } -- print "Found too-old cached translation database\n" unless $QUIET_ARG; -- } -- -- &create_cache; --} -- --sub create_translation_database --{ -- for my $lang (keys %po_files_by_lang) -- { -- my $po_file = $po_files_by_lang{$lang}; -- -- if ($UTF8_ARG) -- { -- my $encoding = get_po_encoding ($po_file); -- -- if (lc $encoding eq "utf-8") -- { -- open PO_FILE, "<$po_file"; -- } -- else -- { -- print "NOTICE: $po_file is not in UTF-8 but $encoding, converting...\n" unless $QUIET_ARG;; -- -- open PO_FILE, "$iconv -f $encoding -t UTF-8 $po_file|"; -- } -- } -- else -- { -- open PO_FILE, "<$po_file"; -- } -- -- my $nextfuzzy = 0; -- my $inmsgid = 0; -- my $inmsgstr = 0; -- my $msgid = ""; -- my $msgstr = ""; -- -- while () -- { -- $nextfuzzy = 1 if /^#, fuzzy/; -- -- if (/^msgid "((\\.|[^\\])*)"/ ) -- { -- $translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr; -- $msgid = ""; -- $msgstr = ""; -- -- if ($nextfuzzy) { -- $inmsgid = 0; -- } else { -- $msgid = unescape_po_string($1); -- $inmsgid = 1; -- } -- $inmsgstr = 0; -- $nextfuzzy = 0; -- } -- -- if (/^msgstr "((\\.|[^\\])*)"/) -- { -- $msgstr = unescape_po_string($1); -- $inmsgstr = 1; -- $inmsgid = 0; -- } -- -- if (/^"((\\.|[^\\])*)"/) -- { -- $msgid .= unescape_po_string($1) if $inmsgid; -- $msgstr .= unescape_po_string($1) if $inmsgstr; -- } -- } -- $translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr; -- } --} -- --sub finalize --{ --} -- --sub unescape_one_sequence --{ -- my ($sequence) = @_; -- -- return "\\" if $sequence eq "\\\\"; -- return "\"" if $sequence eq "\\\""; -- return "\n" if $sequence eq "\\n"; -- return "\r" if $sequence eq "\\r"; -- return "\t" if $sequence eq "\\t"; -- return "\b" if $sequence eq "\\b"; -- return "\f" if $sequence eq "\\f"; -- return "\a" if $sequence eq "\\a"; -- return chr(11) if $sequence eq "\\v"; # vertical tab, see ascii(7) -- -- return chr(hex($1)) if ($sequence =~ /\\x([0-9a-fA-F]{2})/); -- return chr(oct($1)) if ($sequence =~ /\\([0-7]{3})/); -- -- # FIXME: Is \0 supported as well? Kenneth and Rodney don't want it, see bug #48489 -- -- return $sequence; --} -- --sub unescape_po_string --{ -- my ($string) = @_; -- -- $string =~ s/(\\x[0-9a-fA-F]{2}|\\[0-7]{3}|\\.)/unescape_one_sequence($1)/eg; -- -- return $string; --} -- --## NOTE: deal with < - < but not > - > because it seems its ok to have --## > in the entity. For further info please look at #84738. --sub entity_decode --{ -- local ($_) = @_; -- -- s/'/'/g; # ' -- s/"/"/g; # " -- s/&/&/g; -- s/</; -- close INPUT; -- } -- -- open OUTPUT, ">$OUTFILE" or die "can't open $OUTFILE: $!"; -- # Binmode so that selftest works ok if using a native Win32 Perl... -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- while ($source =~ s|^(.*?)([ \t]*<\s*$w+\s+($w+\s*=\s*"$q"\s*)+/?>)([ \t]*\n)?||s) -- { -- print OUTPUT $1; -- -- my $node = $2 . "\n"; -- -- my @strings = (); -- $_ = $node; -- while (s/(\s)_($w+\s*=\s*"($q)")/$1$2/s) { -- push @strings, entity_decode($3); -- } -- print OUTPUT; -- -- my %langs; -- for my $string (@strings) -- { -- for my $lang (keys %po_files_by_lang) -- { -- $langs{$lang} = 1 if $translations{$lang, $string}; -- } -- } -- -- for my $lang (sort keys %langs) -- { -- $_ = $node; -- s/(\sname\s*=\s*)"($q)"/$1"$2-$lang"/s; -- s/(\s)_($w+\s*=\s*")($q)"/$1 . $2 . entity_encoded_translation($lang, $3) . '"'/seg; -- print OUTPUT; -- } -- } -- -- print OUTPUT $source; -- -- close OUTPUT; --} -- -- --## XML (non-bonobo-activation) merge code -- -- --# Process tag attributes --# Only parameter is a HASH containing attributes -> values mapping --sub getAttributeString --{ -- my $sub = shift; -- my $do_translate = shift || 0; -- my $language = shift || ""; -- my $result = ""; -- my $translate = shift; -- foreach my $e (reverse(sort(keys %{ $sub }))) { -- my $key = $e; -- my $string = $sub->{$e}; -- my $quote = '"'; -- -- $string =~ s/^[\s]+//; -- $string =~ s/[\s]+$//; -- -- if ($string =~ /^'.*'$/) -- { -- $quote = "'"; -- } -- $string =~ s/^['"]//g; -- $string =~ s/['"]$//g; -- -- if ($do_translate && $key =~ /^_/) { -- $key =~ s|^_||g; -- if ($language) { -- # Handle translation -- my $decode_string = entity_decode($string); -- my $translation = $translations{$language, $decode_string}; -- if ($translation) { -- $translation = entity_encode($translation); -- $string = $translation; -- } -- $$translate = 2; -- } else { -- $$translate = 2 if ($translate && (!$$translate)); # watch not to "overwrite" $translate -- } -- } -- -- $result .= " $key=$quote$string$quote"; -- } -- return $result; --} -- --# Returns a translatable string from XML node, it works on contents of every node in XML::Parser tree --sub getXMLstring --{ -- my $ref = shift; -- my $spacepreserve = shift || 0; -- my @list = @{ $ref }; -- my $result = ""; -- -- my $count = scalar(@list); -- my $attrs = $list[0]; -- my $index = 1; -- -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); -- -- while ($index < $count) { -- my $type = $list[$index]; -- my $content = $list[$index+1]; -- if (! $type ) { -- # We've got CDATA -- if ($content) { -- # lets strip the whitespace here, and *ONLY* here -- $content =~ s/\s+/ /gs if (!$spacepreserve); -- $result .= $content; -- } -- } elsif ( "$type" ne "1" ) { -- # We've got another element -- $result .= "<$type"; -- $result .= getAttributeString(@{$content}[0], 0); # no nested translatable elements -- if ($content) { -- my $subresult = getXMLstring($content, $spacepreserve); -- if ($subresult) { -- $result .= ">".$subresult . ""; -- } else { -- $result .= "/>"; -- } -- } else { -- $result .= "/>"; -- } -- } -- $index += 2; -- } -- return $result; --} -- --# Translate list of nodes if necessary --sub translate_subnodes --{ -- my $fh = shift; -- my $content = shift; -- my $language = shift || ""; -- my $singlelang = shift || 0; -- my $spacepreserve = shift || 0; -- -- my @nodes = @{ $content }; -- -- my $count = scalar(@nodes); -- my $index = 0; -- while ($index < $count) { -- my $type = $nodes[$index]; -- my $rest = $nodes[$index+1]; -- if ($singlelang) { -- my $oldMO = $MULTIPLE_OUTPUT; -- $MULTIPLE_OUTPUT = 1; -- traverse($fh, $type, $rest, $language, $spacepreserve); -- $MULTIPLE_OUTPUT = $oldMO; -- } else { -- traverse($fh, $type, $rest, $language, $spacepreserve); -- } -- $index += 2; -- } --} -- --sub isWellFormedXmlFragment --{ -- my $ret = eval 'require XML::Parser'; -- if(!$ret) { -- die "You must have XML::Parser installed to run $0\n\n"; -- } -- -- my $fragment = shift; -- return 0 if (!$fragment); -- -- $fragment = "$fragment"; -- my $xp = new XML::Parser(Style => 'Tree'); -- my $tree = 0; -- eval { $tree = $xp->parse($fragment); }; -- return $tree; --} -- --sub traverse --{ -- my $fh = shift; -- my $nodename = shift; -- my $content = shift; -- my $language = shift || ""; -- my $spacepreserve = shift || 0; -- -- if (!$nodename) { -- if ($content =~ /^[\s]*$/) { -- $leading_space .= $content; -- } -- print $fh $content; -- } else { -- # element -- my @all = @{ $content }; -- my $attrs = shift @all; -- my $translate = 0; -- my $outattr = getAttributeString($attrs, 1, $language, \$translate); -- -- if ($nodename =~ /^_/) { -- $translate = 1; -- $nodename =~ s/^_//; -- } -- my $lookup = ''; -- -- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- -- print $fh "<$nodename", $outattr; -- if ($translate) { -- $lookup = getXMLstring($content, $spacepreserve); -- if (!$spacepreserve) { -- $lookup =~ s/^\s+//s; -- $lookup =~ s/\s+$//s; -- } -- -- if ($lookup || $translate == 2) { -- my $translation = $translations{$language, $lookup} if isWellFormedXmlFragment($translations{$language, $lookup}); -- if ($MULTIPLE_OUTPUT && ($translation || $translate == 2)) { -- $translation = $lookup if (!$translation); -- print $fh " xml:lang=\"", $language, "\"" if $language; -- print $fh ">"; -- if ($translate == 2) { -- translate_subnodes($fh, \@all, $language, 1, $spacepreserve); -- } else { -- print $fh $translation; -- } -- print $fh ""; -- -- return; # this means there will be no same translation with xml:lang="$language"... -- # if we want them both, just remove this "return" -- } else { -- print $fh ">"; -- if ($translate == 2) { -- translate_subnodes($fh, \@all, $language, 1, $spacepreserve); -- } else { -- print $fh $lookup; -- } -- print $fh ""; -- } -- } else { -- print $fh "/>"; -- } -- -- for my $lang (sort keys %po_files_by_lang) { -- if ($MULTIPLE_OUTPUT && $lang ne "$language") { -- next; -- } -- if ($lang) { -- # Handle translation -- # -- my $translate = 0; -- my $localattrs = getAttributeString($attrs, 1, $lang, \$translate); -- my $translation = $translations{$lang, $lookup} if isWellFormedXmlFragment($translations{$lang, $lookup}); -- if ($translate && !$translation) { -- $translation = $lookup; -- } -- -- if ($translation || $translate) { -- print $fh "\n"; -- $leading_space =~ s/.*\n//g; -- print $fh $leading_space; -- print $fh "<", $nodename, " xml:lang=\"", $lang, "\"", $localattrs, ">"; -- if ($translate == 2) { -- translate_subnodes($fh, \@all, $lang, 1, $spacepreserve); -- } else { -- print $fh $translation; -- } -- print $fh ""; -- } -- } -- } -- -- } else { -- my $count = scalar(@all); -- if ($count > 0) { -- print $fh ">"; -- my $index = 0; -- while ($index < $count) { -- my $type = $all[$index]; -- my $rest = $all[$index+1]; -- traverse($fh, $type, $rest, $language, $spacepreserve); -- $index += 2; -- } -- print $fh ""; -- } else { -- print $fh "/>"; -- } -- } -- } --} -- --sub intltool_tree_comment --{ -- my $expat = shift; -- my $data = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- push @$clist, 1 => $data; --} -- --sub intltool_tree_cdatastart --{ -- my $expat = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- push @$clist, 0 => $expat->original_string(); --} -- --sub intltool_tree_cdataend --{ -- my $expat = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- $clist->[$pos] .= $expat->original_string(); --} -- --sub intltool_tree_char --{ -- my $expat = shift; -- my $text = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- # Use original_string so that we retain escaped entities -- # in CDATA sections. -- # -- if ($pos > 0 and $clist->[$pos - 1] eq '0') { -- $clist->[$pos] .= $expat->original_string(); -- } else { -- push @$clist, 0 => $expat->original_string(); -- } --} -- --sub intltool_tree_start --{ -- my $expat = shift; -- my $tag = shift; -- my @origlist = (); -- -- # Use original_string so that we retain escaped entities -- # in attribute values. We must convert the string to an -- # @origlist array to conform to the structure of the Tree -- # Style. -- # -- my @original_array = split /\x/, $expat->original_string(); -- my $source = $expat->original_string(); -- -- # Remove leading tag. -- # -- $source =~ s|^\s*<\s*(\S+)||s; -- -- # Grab attribute key/value pairs and push onto @origlist array. -- # -- while ($source) -- { -- if ($source =~ /^\s*([\w:-]+)\s*[=]\s*["]/) -- { -- $source =~ s|^\s*([\w:-]+)\s*[=]\s*["]([^"]*)["]||s; -- push @origlist, $1; -- push @origlist, '"' . $2 . '"'; -- } -- elsif ($source =~ /^\s*([\w:-]+)\s*[=]\s*[']/) -- { -- $source =~ s|^\s*([\w:-]+)\s*[=]\s*[']([^']*)[']||s; -- push @origlist, $1; -- push @origlist, "'" . $2 . "'"; -- } -- else -- { -- last; -- } -- } -- -- my $ol = [ { @origlist } ]; -- -- push @{ $expat->{Lists} }, $expat->{Curlist}; -- push @{ $expat->{Curlist} }, $tag => $ol; -- $expat->{Curlist} = $ol; --} -- --sub readXml --{ -- my $filename = shift || return; -- if(!-f $filename) { -- die "ERROR Cannot find filename: $filename\n"; -- } -- -- my $ret = eval 'require XML::Parser'; -- if(!$ret) { -- die "You must have XML::Parser installed to run $0\n\n"; -- } -- my $xp = new XML::Parser(Style => 'Tree'); -- $xp->setHandlers(Char => \&intltool_tree_char); -- $xp->setHandlers(Start => \&intltool_tree_start); -- $xp->setHandlers(CdataStart => \&intltool_tree_cdatastart); -- $xp->setHandlers(CdataEnd => \&intltool_tree_cdataend); -- my $tree = $xp->parsefile($filename); -- --# Hello thereHowdydo --# would be: --# [foo, [{}, head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]], bar, [{}, --# 0, "Howdy", ref, [{}]], 0, "do" ] ] -- -- return $tree; --} -- --sub print_header --{ -- my $infile = shift; -- my $fh = shift; -- my $source; -- -- if(!-f $infile) { -- die "ERROR Cannot find filename: $infile\n"; -- } -- -- print $fh qq{\n}; -- { -- local $/; -- open DOCINPUT, "<${FILE}" or die; -- $source = ; -- close DOCINPUT; -- } -- if ($source =~ /()/s) -- { -- print $fh "$1\n"; -- } -- elsif ($source =~ /(]*>)/s) -- { -- print $fh "$1\n"; -- } --} -- --sub parseTree --{ -- my $fh = shift; -- my $ref = shift; -- my $language = shift || ""; -- -- my $name = shift @{ $ref }; -- my $cont = shift @{ $ref }; -- -- while (!$name || "$name" eq "1") { -- $name = shift @{ $ref }; -- $cont = shift @{ $ref }; -- } -- -- my $spacepreserve = 0; -- my $attrs = @{$cont}[0]; -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- -- traverse($fh, $name, $cont, $language, $spacepreserve); --} -- --sub xml_merge_output --{ -- my $source; -- -- if ($MULTIPLE_OUTPUT) { -- for my $lang (sort keys %po_files_by_lang) { -- if ( ! -e $lang ) { -- mkdir $lang or die "Cannot create subdirectory $lang: $!\n"; -- } -- open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n"; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- my $tree = readXml($FILE); -- print_header($FILE, \*OUTPUT); -- parseTree(\*OUTPUT, $tree, $lang); -- close OUTPUT; -- print "CREATED $lang/$OUTFILE\n" unless $QUIET_ARG; -- } -- } -- open OUTPUT, ">$OUTFILE" or die "Cannot open $OUTFILE: $!\n"; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- my $tree = readXml($FILE); -- print_header($FILE, \*OUTPUT); -- parseTree(\*OUTPUT, $tree); -- close OUTPUT; -- print "CREATED $OUTFILE\n" unless $QUIET_ARG; --} -- --sub keys_merge_translations --{ -- open INPUT, "<${FILE}" or die; -- open OUTPUT, ">${OUTFILE}" or die; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- while () -- { -- if (s/^(\s*)_(\w+=(.*))/$1$2/) -- { -- my $string = $3; -- -- print OUTPUT; -- -- my $non_translated_line = $_; -- -- for my $lang (sort keys %po_files_by_lang) -- { -- my $translation = $translations{$lang, $string}; -- next if !$translation; -- -- $_ = $non_translated_line; -- s/(\w+)=.*/[$lang]$1=$translation/; -- print OUTPUT; -- } -- } -- else -- { -- print OUTPUT; -- } -- } -- -- close OUTPUT; -- close INPUT; --} -- --sub desktop_merge_translations --{ -- open INPUT, "<${FILE}" or die; -- open OUTPUT, ">${OUTFILE}" or die; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- while () -- { -- if (s/^(\s*)_(\w+=(.*))/$1$2/) -- { -- my $string = $3; -- -- print OUTPUT; -- -- my $non_translated_line = $_; -- -- for my $lang (sort keys %po_files_by_lang) -- { -- my $translation = $translations{$lang, $string}; -- next if !$translation; -- -- $_ = $non_translated_line; -- s/(\w+)=.*/${1}[$lang]=$translation/; -- print OUTPUT; -- } -- } -- else -- { -- print OUTPUT; -- } -- } -- -- close OUTPUT; -- close INPUT; --} -- --sub schemas_merge_translations --{ -- my $source; -- -- { -- local $/; # slurp mode -- open INPUT, "<$FILE" or die "can't open $FILE: $!"; -- $source = ; -- close INPUT; -- } -- -- open OUTPUT, ">$OUTFILE" or die; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- # FIXME: support attribute translations -- -- # Empty nodes never need translation, so unmark all of them. -- # For example, <_foo/> is just replaced by . -- $source =~ s|<\s*_($w+)\s*/>|<$1/>|g; -- -- while ($source =~ s/ -- (.*?) -- (\s+)((\s*) -- (\s*(?:\s*)?(.*?)\s*<\/default>)?(\s*) -- (\s*(?:\s*)?(.*?)\s*<\/short>)?(\s*) -- (\s*(?:\s*)?(.*?)\s*<\/long>)?(\s*) -- <\/locale>) -- //sx) -- { -- print OUTPUT $1; -- -- my $locale_start_spaces = $2 ? $2 : ''; -- my $default_spaces = $4 ? $4 : ''; -- my $short_spaces = $7 ? $7 : ''; -- my $long_spaces = $10 ? $10 : ''; -- my $locale_end_spaces = $13 ? $13 : ''; -- my $c_default_block = $3 ? $3 : ''; -- my $default_string = $6 ? $6 : ''; -- my $short_string = $9 ? $9 : ''; -- my $long_string = $12 ? $12 : ''; -- -- print OUTPUT "$locale_start_spaces$c_default_block"; -- -- $default_string =~ s/\s+/ /g; -- $default_string = entity_decode($default_string); -- $short_string =~ s/\s+/ /g; -- $short_string = entity_decode($short_string); -- $long_string =~ s/\s+/ /g; -- $long_string = entity_decode($long_string); -- -- for my $lang (sort keys %po_files_by_lang) -- { -- my $default_translation = $translations{$lang, $default_string}; -- my $short_translation = $translations{$lang, $short_string}; -- my $long_translation = $translations{$lang, $long_string}; -- -- next if (!$default_translation && !$short_translation && -- !$long_translation); -- -- print OUTPUT "\n$locale_start_spaces"; -- -- print OUTPUT "$default_spaces"; -- -- if ($default_translation) -- { -- $default_translation = entity_encode($default_translation); -- print OUTPUT "$default_translation"; -- } -- -- print OUTPUT "$short_spaces"; -- -- if ($short_translation) -- { -- $short_translation = entity_encode($short_translation); -- print OUTPUT "$short_translation"; -- } -- -- print OUTPUT "$long_spaces"; -- -- if ($long_translation) -- { -- $long_translation = entity_encode($long_translation); -- print OUTPUT "$long_translation"; -- } -- -- print OUTPUT "$locale_end_spaces"; -- } -- } -- -- print OUTPUT $source; -- -- close OUTPUT; --} -- --sub rfc822deb_merge_translations --{ -- my %encodings = (); -- for my $lang (keys %po_files_by_lang) { -- $encodings{$lang} = ($UTF8_ARG ? 'UTF-8' : get_po_encoding($po_files_by_lang{$lang})); -- } -- -- my $source; -- -- $Text::Wrap::huge = 'overflow'; -- $Text::Wrap::break = qr/\n|\s(?=\S)/; -- -- { -- local $/; # slurp mode -- open INPUT, "<$FILE" or die "can't open $FILE: $!"; -- $source = ; -- close INPUT; -- } -- -- open OUTPUT, ">${OUTFILE}" or die; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- while ($source =~ /(^|\n+)(_*)([^:\s]+)(:[ \t]*)(.*?)(?=\n[\S\n]|$)/sg) -- { -- my $sep = $1; -- my $non_translated_line = $3.$4; -- my $string = $5; -- my $underscore = length($2); -- next if $underscore eq 0 && $non_translated_line =~ /^#/; -- # Remove [] dummy strings -- my $stripped = $string; -- $stripped =~ s/\[\s[^\[\]]*\],/,/g if $underscore eq 2; -- $stripped =~ s/\[\s[^\[\]]*\]$//; -- $non_translated_line .= $stripped; -- -- print OUTPUT $sep.$non_translated_line; -- -- if ($underscore) -- { -- my @str_list = rfc822deb_split($underscore, $string); -- -- for my $lang (sort keys %po_files_by_lang) -- { -- my $is_translated = 1; -- my $str_translated = ''; -- my $first = 1; -- -- for my $str (@str_list) -- { -- my $translation = $translations{$lang, $str}; -- -- if (!$translation) -- { -- $is_translated = 0; -- last; -- } -- -- # $translation may also contain [] dummy -- # strings, mostly to indicate an empty string -- $translation =~ s/\[\s[^\[\]]*\]$//; -- -- if ($first) -- { -- if ($underscore eq 2) -- { -- $str_translated .= $translation; -- } -- else -- { -- $str_translated .= -- Text::Tabs::expand($translation) . -- "\n"; -- } -- } -- else -- { -- if ($underscore eq 2) -- { -- $str_translated .= ', ' . $translation; -- } -- else -- { -- $str_translated .= Text::Tabs::expand( -- Text::Wrap::wrap(' ', ' ', $translation)) . -- "\n .\n"; -- } -- } -- $first = 0; -- -- # To fix some problems with Text::Wrap::wrap -- $str_translated =~ s/(\n )+\n/\n .\n/g; -- } -- next unless $is_translated; -- -- $str_translated =~ s/\n \.\n$//; -- $str_translated =~ s/\s+$//; -- -- $_ = $non_translated_line; -- s/^(\w+):\s*.*/$sep${1}-$lang.$encodings{$lang}: $str_translated/s; -- print OUTPUT; -- } -- } -- } -- print OUTPUT "\n"; -- -- close OUTPUT; -- close INPUT; --} -- --sub rfc822deb_split --{ -- # Debian defines a special way to deal with rfc822-style files: -- # when a value contain newlines, it consists of -- # 1. a short form (first line) -- # 2. a long description, all lines begin with a space, -- # and paragraphs are separated by a single dot on a line -- # This routine returns an array of all paragraphs, and reformat -- # them. -- # When first argument is 2, the string is a comma separated list of -- # values. -- my $type = shift; -- my $text = shift; -- $text =~ s/^[ \t]//mg; -- return (split(/, */, $text, 0)) if $type ne 1; -- return ($text) if $text !~ /\n/; -- -- $text =~ s/([^\n]*)\n//; -- my @list = ($1); -- my $str = ''; -- -- for my $line (split (/\n/, $text)) -- { -- chomp $line; -- if ($line =~ /^\.\s*$/) -- { -- # New paragraph -- $str =~ s/\s*$//; -- push(@list, $str); -- $str = ''; -- } -- elsif ($line =~ /^\s/) -- { -- # Line which must not be reformatted -- $str .= "\n" if length ($str) && $str !~ /\n$/; -- $line =~ s/\s+$//; -- $str .= $line."\n"; -- } -- else -- { -- # Continuation line, remove newline -- $str .= " " if length ($str) && $str !~ /\n$/; -- $str .= $line; -- } -- } -- -- $str =~ s/\s*$//; -- push(@list, $str) if length ($str); -- -- return @list; --} -- -diff --git a/intltool-merge.in b/intltool-merge.in -new file mode 120000 -index d0535ab..2238bbd ---- /dev/null -+++ b/intltool-merge.in -@@ -0,0 +1 @@ -+/usr/share/intltool/intltool-merge.in -\ No newline at end of file -diff --git a/intltool-update.in b/intltool-update.in -deleted file mode 100755 -index 661d8fe..0b1800f ---- a/intltool-update.in -+++ /dev/null -@@ -1,1089 +0,0 @@ --#!@INTLTOOL_PERL@ -w --# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- -- --# --# The Intltool Message Updater --# --# Copyright (C) 2000-2003 Free Software Foundation. --# --# Intltool is free software; you can redistribute it and/or --# modify it under the terms of the GNU General Public License --# version 2 published by the Free Software Foundation. --# --# Intltool 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., 675 Mass Ave, Cambridge, MA 02139, USA. --# --# As a special exception to the GNU General Public License, if you --# distribute this file as part of a program that contains a --# configuration script generated by Autoconf, you may include it under --# the same distribution terms that you use for the rest of that program. --# --# Authors: Kenneth Christiansen --# Maciej Stachowiak --# Darin Adler -- --## Release information --my $PROGRAM = "intltool-update"; --my $VERSION = "0.35.0"; --my $PACKAGE = "intltool"; -- --## Loaded modules --use strict; --use Getopt::Long; --use Cwd; --use File::Copy; --use File::Find; -- --## Scalars used by the option stuff --my $HELP_ARG = 0; --my $VERSION_ARG = 0; --my $DIST_ARG = 0; --my $POT_ARG = 0; --my $HEADERS_ARG = 0; --my $MAINTAIN_ARG = 0; --my $REPORT_ARG = 0; --my $VERBOSE = 0; --my $GETTEXT_PACKAGE = ""; --my $OUTPUT_FILE = ""; -- --my @languages; --my %varhash = (); --my %po_files_by_lang = (); -- --# Regular expressions to categorize file types. --# FIXME: Please check if the following is correct -- --my $xml_support = --"xml(?:\\.in)*|". # http://www.w3.org/XML/ (Note: .in is not required) --"ui|". # Bonobo specific - User Interface desc. files --"lang|". # ? --"glade2?(?:\\.in)*|". # Glade specific - User Interface desc. files (Note: .in is not required) --"scm(?:\\.in)*|". # ? (Note: .in is not required) --"oaf(?:\\.in)+|". # DEPRECATED: Replaces by Bonobo .server files --"etspec|". # ? --"server(?:\\.in)+|". # Bonobo specific --"sheet(?:\\.in)+|". # ? --"schemas(?:\\.in)+|". # GConf specific --"pong(?:\\.in)+|". # DEPRECATED: PONG is not used [by GNOME] any longer. --"kbd(?:\\.in)+"; # GOK specific. -- --my $ini_support = --"icon(?:\\.in)+|". # http://www.freedesktop.org/Standards/icon-theme-spec --"desktop(?:\\.in)+|". # http://www.freedesktop.org/Standards/menu-spec --"caves(?:\\.in)+|". # GNOME Games specific --"directory(?:\\.in)+|". # http://www.freedesktop.org/Standards/menu-spec --"soundlist(?:\\.in)+|". # GNOME specific --"keys(?:\\.in)+|". # GNOME Mime database specific --"theme(?:\\.in)+|". # http://www.freedesktop.org/Standards/icon-theme-spec --"service(?:\\.in)+"; # DBus specific -- --my $buildin_gettext_support = --"c|y|cs|cc|cpp|c\\+\\+|h|hh|gob|py"; -- --## Always flush buffer when printing --$| = 1; -- --## Sometimes the source tree will be rooted somewhere else. --my $SRCDIR = "."; --my $POTFILES_in; -- --$SRCDIR = $ENV{"srcdir"} if $ENV{"srcdir"}; --$POTFILES_in = "<$SRCDIR/POTFILES.in"; -- --my $devnull = ($^O eq 'MSWin32' ? 'NUL:' : '/dev/null'); -- --## Handle options --GetOptions --( -- "help" => \$HELP_ARG, -- "version" => \$VERSION_ARG, -- "dist|d" => \$DIST_ARG, -- "pot|p" => \$POT_ARG, -- "headers|s" => \$HEADERS_ARG, -- "maintain|m" => \$MAINTAIN_ARG, -- "report|r" => \$REPORT_ARG, -- "verbose|x" => \$VERBOSE, -- "gettext-package|g=s" => \$GETTEXT_PACKAGE, -- "output-file|o=s" => \$OUTPUT_FILE, -- ) or &Console_WriteError_InvalidOption; -- --&Console_Write_IntltoolHelp if $HELP_ARG; --&Console_Write_IntltoolVersion if $VERSION_ARG; -- --my $arg_count = ($DIST_ARG > 0) -- + ($POT_ARG > 0) -- + ($HEADERS_ARG > 0) -- + ($MAINTAIN_ARG > 0) -- + ($REPORT_ARG > 0); -- --&Console_Write_IntltoolHelp if $arg_count > 1; -- --# --version and --help don't require a module name --my $MODULE = $GETTEXT_PACKAGE || &FindPackageName || "unknown"; -- --if ($POT_ARG) --{ -- &GenerateHeaders; -- &GeneratePOTemplate; --} --elsif ($HEADERS_ARG) --{ -- &GenerateHeaders; --} --elsif ($MAINTAIN_ARG) --{ -- &FindLeftoutFiles; --} --elsif ($REPORT_ARG) --{ -- &GenerateHeaders; -- &GeneratePOTemplate; -- &Console_Write_CoverageReport; --} --elsif ((defined $ARGV[0]) && $ARGV[0] =~ /^[a-z]/) --{ -- my $lang = $ARGV[0]; -- -- ## Report error if the language file supplied -- ## to the command line is non-existent -- &Console_WriteError_NotExisting("$SRCDIR/$lang.po") -- if ! -s "$SRCDIR/$lang.po"; -- -- if (!$DIST_ARG) -- { -- print "Working, please wait..." if $VERBOSE; -- &GenerateHeaders; -- &GeneratePOTemplate; -- } -- &POFile_Update ($lang, $OUTPUT_FILE); -- &Console_Write_TranslationStatus ($lang, $OUTPUT_FILE); --} --else --{ -- &Console_Write_IntltoolHelp; --} -- --exit; -- --######### -- --sub Console_Write_IntltoolVersion --{ -- print <<_EOF_; --${PROGRAM} (${PACKAGE}) $VERSION --Written by Kenneth Christiansen, Maciej Stachowiak, and Darin Adler. -- --Copyright (C) 2000-2003 Free Software Foundation, Inc. --This is free software; see the source for copying conditions. There is NO --warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. --_EOF_ -- exit; --} -- --sub Console_Write_IntltoolHelp --{ -- print <<_EOF_; --Usage: ${PROGRAM} [OPTION]... LANGCODE --Updates PO template files and merge them with the translations. -- --Mode of operation (only one is allowed): -- -p, --pot generate the PO template only -- -s, --headers generate the header files in POTFILES.in -- -m, --maintain search for left out files from POTFILES.in -- -r, --report display a status report for the module -- -d, --dist merge LANGCODE.po with existing PO template -- --Extra options: -- -g, --gettext-package=NAME override PO template name, useful with --pot -- -o, --output-file=FILE write merged translation to FILE -- -x, --verbose display lots of feedback -- --help display this help and exit -- --version output version information and exit -- --Examples of use: --${PROGRAM} --pot just create a new PO template --${PROGRAM} xy create new PO template and merge xy.po with it -- --Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE") --or send email to . --_EOF_ -- exit; --} -- --sub echo_n --{ -- my $str = shift; -- my $ret = `echo "$str"`; -- -- $ret =~ s/\n$//; # do we need the "s" flag? -- -- return $ret; --} -- --sub POFile_DetermineType ($) --{ -- my $type = $_; -- my $gettext_type; -- -- my $xml_regex = "(?:" . $xml_support . ")"; -- my $ini_regex = "(?:" . $ini_support . ")"; -- my $buildin_regex = "(?:" . $buildin_gettext_support . ")"; -- -- if ($type =~ /\[type: gettext\/([^\]].*)]/) -- { -- $gettext_type=$1; -- } -- elsif ($type =~ /schemas(\.in)+$/) -- { -- $gettext_type="schemas"; -- } -- elsif ($type =~ /glade2?(\.in)*$/) -- { -- $gettext_type="glade"; -- } -- elsif ($type =~ /scm(\.in)*$/) -- { -- $gettext_type="scheme"; -- } -- elsif ($type =~ /keys(\.in)+$/) -- { -- $gettext_type="keys"; -- } -- -- # bucket types -- -- elsif ($type =~ /$xml_regex$/) -- { -- $gettext_type="xml"; -- } -- elsif ($type =~ /$ini_regex$/) -- { -- $gettext_type="ini"; -- } -- elsif ($type =~ /$buildin_regex$/) -- { -- $gettext_type="buildin"; -- } -- else -- { -- $gettext_type="unknown"; -- } -- -- return "gettext\/$gettext_type"; --} -- --sub TextFile_DetermineEncoding ($) --{ -- my $gettext_code="ASCII"; # All files are ASCII by default -- my $filetype=`file $_ | cut -d ' ' -f 2`; -- -- if ($? eq "0") -- { -- if ($filetype =~ /^(ISO|UTF)/) -- { -- chomp ($gettext_code = $filetype); -- } -- elsif ($filetype =~ /^XML/) -- { -- $gettext_code="UTF-8"; # We asume that .glade and other .xml files are UTF-8 -- } -- } -- -- return $gettext_code; --} -- --sub isNotValidMissing --{ -- my ($file) = @_; -- -- return if $file =~ /^\{arch\}\/.*$/; -- return if $file =~ /^$varhash{"PACKAGE"}-$varhash{"VERSION"}\/.*$/; --} -- --sub FindLeftoutFiles --{ -- my (@buf_i18n_plain, -- @buf_i18n_xml, -- @buf_i18n_xml_unmarked, -- @buf_i18n_ini, -- @buf_potfiles, -- @buf_potfiles_ignore, -- @buf_allfiles, -- @buf_allfiles_sorted, -- @buf_potfiles_sorted -- ); -- -- ## Search and find all translatable files -- find sub { -- push @buf_i18n_plain, "$File::Find::name" if /\.($buildin_gettext_support)$/; -- push @buf_i18n_xml, "$File::Find::name" if /\.($xml_support)$/; -- push @buf_i18n_ini, "$File::Find::name" if /\.($ini_support)$/; -- push @buf_i18n_xml_unmarked, "$File::Find::name" if /\.(schemas(\.in)+)$/; -- }, ".."; -- -- -- open POTFILES, $POTFILES_in or die "$PROGRAM: there's no POTFILES.in!\n"; -- @buf_potfiles = grep !/^(#|\s*$)/, ; -- close POTFILES; -- -- foreach (@buf_potfiles) { -- s/^\[.*]\s*//; -- } -- -- print "Searching for missing translatable files...\n" if $VERBOSE; -- -- ## Check if we should ignore some found files, when -- ## comparing with POTFILES.in -- foreach my $ignore ("POTFILES.skip", "POTFILES.ignore") -- { -- (-s $ignore) or next; -- -- if ("$ignore" eq "POTFILES.ignore") -- { -- print "The usage of POTFILES.ignore is deprecated. Please consider moving the\n". -- "content of this file to POTFILES.skip.\n"; -- } -- -- print "Found $ignore: Ignoring files...\n" if $VERBOSE; -- open FILE, "<$ignore" or die "ERROR: Failed to open $ignore!\n"; -- -- while () -- { -- push @buf_potfiles_ignore, $_ unless /^(#|\s*$)/; -- } -- close FILE; -- -- @buf_potfiles = (@buf_potfiles_ignore, @buf_potfiles); -- } -- -- foreach my $file (@buf_i18n_plain) -- { -- my $in_comment = 0; -- my $in_macro = 0; -- -- open FILE, "<$file"; -- while () -- { -- # Handle continued multi-line comment. -- if ($in_comment) -- { -- next unless s-.*\*/--; -- $in_comment = 0; -- } -- -- # Handle continued macro. -- if ($in_macro) -- { -- $in_macro = 0 unless /\\$/; -- next; -- } -- -- # Handle start of macro (or any preprocessor directive). -- if (/^\s*\#/) -- { -- $in_macro = 1 if /^([^\\]|\\.)*\\$/; -- next; -- } -- -- # Handle comments and quoted text. -- while (m-(/\*|//|\'|\")-) # \' and \" keep emacs perl mode happy -- { -- my $match = $1; -- if ($match eq "/*") -- { -- if (!s-/\*.*?\*/--) -- { -- s-/\*.*--; -- $in_comment = 1; -- } -- } -- elsif ($match eq "//") -- { -- s-//.*--; -- } -- else # ' or " -- { -- if (!s-$match([^\\]|\\.)*?$match-QUOTEDTEXT-) -- { -- warn "mismatched quotes at line $. in $file\n"; -- s-$match.*--; -- } -- } -- } -- -- if (/\.GetString ?\(QUOTEDTEXT/) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- ## Remove the first 3 chars and add newline -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- last; -- } -- -- if (/_\(QUOTEDTEXT/) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- ## Remove the first 3 chars and add newline -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- last; -- } -- } -- close FILE; -- } -- -- foreach my $file (@buf_i18n_xml) -- { -- open FILE, "<$file"; -- -- while () -- { -- # FIXME: share the pattern matching code with intltool-extract -- if (/\s_[-A-Za-z0-9._:]+\s*=\s*\"([^"]+)\"/ || /<_[^>]+>/ || /translatable=\"yes\"/) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- last; -- } -- } -- close FILE; -- } -- -- foreach my $file (@buf_i18n_ini) -- { -- open FILE, "<$file"; -- while () -- { -- if (/_(.*)=/) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- last; -- } -- } -- close FILE; -- } -- -- foreach my $file (@buf_i18n_xml_unmarked) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- } -- -- -- @buf_allfiles_sorted = sort (@buf_allfiles); -- @buf_potfiles_sorted = sort (@buf_potfiles); -- -- my %in2; -- foreach (@buf_potfiles_sorted) -- { -- $in2{$_} = 1; -- } -- -- my @result; -- -- foreach (@buf_allfiles_sorted) -- { -- if (!exists($in2{$_})) -- { -- push @result, $_ -- } -- } -- -- my @buf_potfiles_notexist; -- -- foreach (@buf_potfiles_sorted) -- { -- chomp (my $dummy = $_); -- if ("$dummy" ne "" and ! -f "../$dummy") -- { -- push @buf_potfiles_notexist, $_; -- } -- } -- -- ## Save file with information about the files missing -- ## if any, and give information about this procedure. -- if (@result + @buf_potfiles_notexist > 0) -- { -- if (@result) -- { -- print "\n" if $VERBOSE; -- unlink "missing"; -- open OUT, ">missing"; -- print OUT @result; -- close OUT; -- warn "\e[1mThe following files contain translations and are currently not in use. Please\e[0m\n". -- "\e[1mconsider adding these to the POTFILES.in file, located in the po/ directory.\e[0m\n\n"; -- print STDERR @result, "\n"; -- warn "If some of these files are left out on purpose then please add them to\n". -- "POTFILES.skip instead of POTFILES.in. A file \e[1m'missing'\e[0m containing this list\n". -- "of left out files has been written in the current directory.\n"; -- } -- if (@buf_potfiles_notexist) -- { -- unlink "notexist"; -- open OUT, ">notexist"; -- print OUT @buf_potfiles_notexist; -- close OUT; -- warn "\n" if ($VERBOSE or @result); -- warn "\e[1mThe following files do not exist anymore:\e[0m\n\n"; -- warn @buf_potfiles_notexist, "\n"; -- warn "Please remove them from POTFILES.in or POTFILES.skip. A file \e[1m'notexist'\e[0m\n". -- "containing this list of absent files has been written in the current directory.\n"; -- } -- } -- -- ## If there is nothing to complain about, notify the user -- else { -- print "\nAll files containing translations are present in POTFILES.in.\n" if $VERBOSE; -- } --} -- --sub Console_WriteError_InvalidOption --{ -- ## Handle invalid arguments -- print STDERR "Try `${PROGRAM} --help' for more information.\n"; -- exit 1; --} -- --sub GenerateHeaders --{ -- my $EXTRACT = "@INTLTOOL_EXTRACT@"; -- chomp $EXTRACT; -- -- $EXTRACT = $ENV{"INTLTOOL_EXTRACT"} if $ENV{"INTLTOOL_EXTRACT"}; -- -- ## Generate the .h header files, so we can allow glade and -- ## xml translation support -- if (! -x "$EXTRACT") -- { -- print STDERR "\n *** The intltool-extract script wasn't found!" -- ."\n *** Without it, intltool-update can not generate files.\n"; -- exit; -- } -- else -- { -- open (FILE, $POTFILES_in) or die "$PROGRAM: POTFILES.in not found.\n"; -- -- while () -- { -- chomp; -- next if /^\[\s*encoding/; -- -- ## Find xml files in POTFILES.in and generate the -- ## files with help from the extract script -- -- my $gettext_type= &POFile_DetermineType ($1); -- -- if (/\.($xml_support|$ini_support)$/ || /^\[/) -- { -- s/^\[[^\[].*]\s*//; -- -- my $filename = "../$_"; -- -- if ($VERBOSE) -- { -- system ($EXTRACT, "--update", "--srcdir=$SRCDIR", -- "--type=$gettext_type", $filename); -- } -- else -- { -- system ($EXTRACT, "--update", "--type=$gettext_type", -- "--srcdir=$SRCDIR", "--quiet", $filename); -- } -- } -- } -- close FILE; -- } --} -- --# --# Generate .pot file from POTFILES.in --# --sub GeneratePOTemplate --{ -- my $XGETTEXT = $ENV{"XGETTEXT"} || "@INTLTOOL_XGETTEXT@"; -- my $XGETTEXT_ARGS = $ENV{"XGETTEXT_ARGS"} || ''; -- chomp $XGETTEXT; -- -- if (! -x $XGETTEXT) -- { -- print STDERR " *** xgettext is not found on this system!\n". -- " *** Without it, intltool-update can not extract strings.\n"; -- exit; -- } -- -- print "Building $MODULE.pot...\n" if $VERBOSE; -- -- open INFILE, $POTFILES_in; -- unlink "POTFILES.in.temp"; -- open OUTFILE, ">POTFILES.in.temp" or die("Cannot open POTFILES.in.temp for writing"); -- -- my $gettext_support_nonascii = 0; -- -- # checks for GNU gettext >= 0.12 -- my $dummy = `$XGETTEXT --version --from-code=UTF-8 >$devnull 2>$devnull`; -- if ($? == 0) -- { -- $gettext_support_nonascii = 1; -- } -- else -- { -- # urge everybody to upgrade gettext -- print STDERR "WARNING: This version of gettext does not support extracting non-ASCII\n". -- " strings. That means you should install a version of gettext\n". -- " that supports non-ASCII strings (such as GNU gettext >= 0.12),\n". -- " or have to let non-ASCII strings untranslated. (If there is any)\n"; -- } -- -- my $encoding = "ASCII"; -- my $forced_gettext_code; -- my @temp_headers; -- my $encoding_problem_is_reported = 0; -- -- while () -- { -- next if (/^#/ or /^\s*$/); -- -- chomp; -- -- my $gettext_code; -- -- if (/^\[\s*encoding:\s*(.*)\s*\]/) -- { -- $forced_gettext_code=$1; -- } -- elsif (/\.($xml_support|$ini_support)$/ || /^\[/) -- { -- s/^\[.*]\s*//; -- print OUTFILE "../$_.h\n"; -- push @temp_headers, "../$_.h"; -- $gettext_code = &TextFile_DetermineEncoding ("../$_.h") if ($gettext_support_nonascii and not defined $forced_gettext_code); -- } -- else -- { -- if ($SRCDIR eq ".") { -- print OUTFILE "../$_\n"; -- } else { -- print OUTFILE "$SRCDIR/../$_\n"; -- } -- $gettext_code = &TextFile_DetermineEncoding ("../$_") if ($gettext_support_nonascii and not defined $forced_gettext_code); -- } -- -- next if (! $gettext_support_nonascii); -- -- if (defined $forced_gettext_code) -- { -- $encoding=$forced_gettext_code; -- } -- elsif (defined $gettext_code and "$encoding" ne "$gettext_code") -- { -- if ($encoding eq "ASCII") -- { -- $encoding=$gettext_code; -- } -- elsif ($gettext_code ne "ASCII") -- { -- # Only report once because the message is quite long -- if (! $encoding_problem_is_reported) -- { -- print STDERR "WARNING: You should use the same file encoding for all your project files,\n". -- " but $PROGRAM thinks that most of the source files are in\n". -- " $encoding encoding, while \"$_\" is (likely) in\n". -- " $gettext_code encoding. If you are sure that all translatable strings\n". -- " are in same encoding (say UTF-8), please \e[1m*prepend*\e[0m the following\n". -- " line to POTFILES.in:\n\n". -- " [encoding: UTF-8]\n\n". -- " and make sure that configure.in/ac checks for $PACKAGE >= 0.27 .\n". -- "(such warning message will only be reported once.)\n"; -- $encoding_problem_is_reported = 1; -- } -- } -- } -- } -- -- close OUTFILE; -- close INFILE; -- -- unlink "$MODULE.pot"; -- my @xgettext_argument=("$XGETTEXT", -- "--add-comments", -- "--directory\=\.", -- "--output\=$MODULE\.pot", -- "--files-from\=\.\/POTFILES\.in\.temp"); -- my $XGETTEXT_KEYWORDS = &FindPOTKeywords; -- push @xgettext_argument, $XGETTEXT_KEYWORDS; -- my $MSGID_BUGS_ADDRESS = &FindMakevarsBugAddress; -- push @xgettext_argument, "--msgid-bugs-address\=$MSGID_BUGS_ADDRESS" if $MSGID_BUGS_ADDRESS; -- push @xgettext_argument, "--from-code\=$encoding" if ($gettext_support_nonascii); -- push @xgettext_argument, $XGETTEXT_ARGS if $XGETTEXT_ARGS; -- my $xgettext_command = join ' ', @xgettext_argument; -- -- # intercept xgettext error message -- print "Running $xgettext_command\n" if $VERBOSE; -- my $xgettext_error_msg = `$xgettext_command 2>\&1`; -- my $command_failed = $?; -- -- unlink "POTFILES.in.temp"; -- -- print "Removing generated header (.h) files..." if $VERBOSE; -- unlink foreach (@temp_headers); -- print "done.\n" if $VERBOSE; -- -- if (! $command_failed) -- { -- if (! -e "$MODULE.pot") -- { -- print "None of the files in POTFILES.in contain strings marked for translation.\n" if $VERBOSE; -- } -- else -- { -- print "Wrote $MODULE.pot\n" if $VERBOSE; -- } -- } -- else -- { -- if ($xgettext_error_msg =~ /--from-code/) -- { -- # replace non-ASCII error message with a more useful one. -- print STDERR "ERROR: xgettext failed to generate PO template file because there is non-ASCII\n". -- " string marked for translation. Please make sure that all strings marked\n". -- " for translation are in uniform encoding (say UTF-8), then \e[1m*prepend*\e[0m the\n". -- " following line to POTFILES.in and rerun $PROGRAM:\n\n". -- " [encoding: UTF-8]\n\n"; -- } -- else -- { -- print STDERR "$xgettext_error_msg"; -- if (-e "$MODULE.pot") -- { -- # is this possible? -- print STDERR "ERROR: xgettext failed but still managed to generate PO template file.\n". -- " Please consult error message above if there is any.\n"; -- } -- else -- { -- print STDERR "ERROR: xgettext failed to generate PO template file. Please consult\n". -- " error message above if there is any.\n"; -- } -- } -- exit (1); -- } --} -- --sub POFile_Update --{ -- -f "$MODULE.pot" or die "$PROGRAM: $MODULE.pot does not exist.\n"; -- -- my $MSGMERGE = $ENV{"MSGMERGE"} || "@INTLTOOL_MSGMERGE@"; -- my ($lang, $outfile) = @_; -- -- print "Merging $SRCDIR/$lang.po with $MODULE.pot..." if $VERBOSE; -- -- my $infile = "$SRCDIR/$lang.po"; -- $outfile = "$SRCDIR/$lang.po" if ($outfile eq ""); -- -- # I think msgmerge won't overwrite old file if merge is not successful -- system ("$MSGMERGE", "-o", $outfile, $infile, "$MODULE.pot"); --} -- --sub Console_WriteError_NotExisting --{ -- my ($file) = @_; -- -- ## Report error if supplied language file is non-existing -- print STDERR "$PROGRAM: $file does not exist!\n"; -- print STDERR "Try '$PROGRAM --help' for more information.\n"; -- exit; --} -- --sub GatherPOFiles --{ -- my @po_files = glob ("./*.po"); -- -- @languages = map (&POFile_GetLanguage, @po_files); -- -- foreach my $lang (@languages) -- { -- $po_files_by_lang{$lang} = shift (@po_files); -- } --} -- --sub POFile_GetLanguage ($) --{ -- s/^(.*\/)?(.+)\.po$/$2/; -- return $_; --} -- --sub Console_Write_TranslationStatus --{ -- my ($lang, $output_file) = @_; -- my $MSGFMT = $ENV{"MSGFMT"} || "@INTLTOOL_MSGFMT@"; -- -- $output_file = "$SRCDIR/$lang.po" if ($output_file eq ""); -- -- system ("$MSGFMT", "-o", "$devnull", "--verbose", $output_file); --} -- --sub Console_Write_CoverageReport --{ -- my $MSGFMT = $ENV{"MSGFMT"} || "@INTLTOOL_MSGFMT@"; -- -- &GatherPOFiles; -- -- foreach my $lang (@languages) -- { -- print "$lang: "; -- &POFile_Update ($lang, ""); -- } -- -- print "\n\n * Current translation support in $MODULE \n\n"; -- -- foreach my $lang (@languages) -- { -- print "$lang: "; -- system ("$MSGFMT", "-o", "$devnull", "--verbose", "$SRCDIR/$lang.po"); -- } --} -- --sub SubstituteVariable --{ -- my ($str) = @_; -- -- # always need to rewind file whenever it has been accessed -- seek (CONF, 0, 0); -- -- # cache each variable. varhash is global to we can add -- # variables elsewhere. -- while () -- { -- if (/^(\w+)=(.*)$/) -- { -- ($varhash{$1} = $2) =~ s/^["'](.*)["']$/$1/; -- } -- } -- -- if ($str =~ /^(.*)\${?([A-Z_]+)}?(.*)$/) -- { -- my $rest = $3; -- my $untouched = $1; -- my $sub = ""; -- # Ignore recursive definitions of variables -- $sub = $varhash{$2} if defined $varhash{$2} and $varhash{$2} !~ /\${?$2}?/; -- -- return SubstituteVariable ("$untouched$sub$rest"); -- } -- -- # We're using Perl backticks ` and "echo -n" here in order to -- # expand any shell escapes (such as backticks themselves) in every variable -- return echo_n ($str); --} -- --sub CONF_Handle_Open --{ -- my $base_dirname = getcwd(); -- $base_dirname =~ s@.*/@@; -- -- my ($conf_in, $src_dir); -- -- if ($base_dirname =~ /^po(-.+)?$/) -- { -- if (-f "Makevars") -- { -- my $makefile_source; -- -- local (*IN); -- open (IN, ") -- { -- if (/^top_builddir[ \t]*=/) -- { -- $src_dir = $_; -- $src_dir =~ s/^top_builddir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/; -- -- chomp $src_dir; -- if (-f "$src_dir" . "/configure.ac") { -- $conf_in = "$src_dir" . "/configure.ac" . "\n"; -- } else { -- $conf_in = "$src_dir" . "/configure.in" . "\n"; -- } -- last; -- } -- } -- close IN; -- -- $conf_in || die "Cannot find top_builddir in Makevars."; -- } -- elsif (-f "../configure.ac") -- { -- $conf_in = "../configure.ac"; -- } -- elsif (-f "../configure.in") -- { -- $conf_in = "../configure.in"; -- } -- else -- { -- my $makefile_source; -- -- local (*IN); -- open (IN, ") -- { -- if (/^top_srcdir[ \t]*=/) -- { -- $src_dir = $_; -- $src_dir =~ s/^top_srcdir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/; -- -- chomp $src_dir; -- $conf_in = "$src_dir" . "/configure.in" . "\n"; -- -- last; -- } -- } -- close IN; -- -- $conf_in || die "Cannot find top_srcdir in Makefile."; -- } -- -- open (CONF, "<$conf_in"); -- } -- else -- { -- print STDERR "$PROGRAM: Unable to proceed.\n" . -- "Make sure to run this script inside the po directory.\n"; -- exit; -- } --} -- --sub FindPackageName --{ -- my $version; -- my $domain = &FindMakevarsDomain; -- my $name = $domain || "untitled"; -- -- &CONF_Handle_Open; -- -- my $conf_source; { -- local (*IN); -- open (IN, "<&CONF") || return $name; -- seek (IN, 0, 0); -- local $/; # slurp mode -- $conf_source = ; -- close IN; -- } -- -- # priority for getting package name: -- # 1. GETTEXT_PACKAGE -- # 2. first argument of AC_INIT (with >= 2 arguments) -- # 3. first argument of AM_INIT_AUTOMAKE (with >= 2 argument) -- -- # /^AM_INIT_AUTOMAKE\([\s\[]*([^,\)\s\]]+)/m -- # the \s makes this not work, why? -- if ($conf_source =~ /^AM_INIT_AUTOMAKE\(([^,\)]+),([^,\)]+)/m) -- { -- ($name, $version) = ($1, $2); -- $name =~ s/[\[\]\s]//g; -- $version =~ s/[\[\]\s]//g; -- $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/); -- $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/); -- $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/); -- $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/); -- } -- -- if ($conf_source =~ /^AC_INIT\(([^,\)]+),([^,\)]+)/m) -- { -- ($name, $version) = ($1, $2); -- $name =~ s/[\[\]\s]//g; -- $version =~ s/[\[\]\s]//g; -- $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/); -- $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/); -- $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/); -- $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/); -- } -- -- # \s makes this not work, why? -- $name = $1 if $conf_source =~ /^GETTEXT_PACKAGE=\[?([^\n\]]+)/m; -- -- # m4 macros AC_PACKAGE_NAME, AC_PACKAGE_VERSION etc. have same value -- # as corresponding $PACKAGE_NAME, $PACKAGE_VERSION etc. shell variables. -- $name =~ s/\bAC_PACKAGE_/\$PACKAGE_/g; -- -- $name = $domain if $domain; -- -- $name = SubstituteVariable ($name); -- $name =~ s/^["'](.*)["']$/$1/; -- -- return $name if $name; --} -- -- --sub FindPOTKeywords --{ -- -- my $keywords = "--keyword\=\_ --keyword\=N\_ --keyword\=U\_ --keyword\=Q\_"; -- my $varname = "XGETTEXT_OPTIONS"; -- my $make_source; { -- local (*IN); -- open (IN, "; -- close IN; -- } -- -- $keywords = $1 if $make_source =~ /^$varname[ ]*=\[?([^\n\]]+)/m; -- -- return $keywords; --} -- --sub FindMakevarsDomain --{ -- -- my $domain = ""; -- my $makevars_source; { -- local (*IN); -- open (IN, "; -- close IN; -- } -- -- $domain = $1 if $makevars_source =~ /^DOMAIN[ ]*=\[?([^\n\]\$]+)/m; -- $domain =~ s/^\s+//; -- $domain =~ s/\s+$//; -- -- return $domain; --} -- --sub FindMakevarsBugAddress --{ -- -- my $address = ""; -- my $makevars_source; { -- local (*IN); -- open (IN, "; -- close IN; -- } -- -- $address = $1 if $makevars_source =~ /^MSGID_BUGS_ADDRESS[ ]*=\[?([^\n\]\$]+)/m; -- $address =~ s/^\s+//; -- $address =~ s/\s+$//; -- -- return $address; --} -diff --git a/intltool-update.in b/intltool-update.in -new file mode 120000 -index 661d8fe..0b1800f ---- /dev/null -+++ b/intltool-update.in -@@ -0,0 +1 @@ -+/usr/share/intltool/intltool-update.in -\ No newline at end of file -diff --git a/pixmaps/intlclock-map-location-current.png b/pixmaps/intlclock-map-location-current.png -new file mode 100644 -index 0000000..5c505d1 -Binary files /dev/null and b/pixmaps/intlclock-map-location-current.png differ -diff --git a/pixmaps/intlclock-map-location-current.svg b/pixmaps/intlclock-map-location-current.svg -new file mode 100644 -index 0000000..93b5188 ---- /dev/null -+++ b/pixmaps/intlclock-map-location-current.svg -@@ -0,0 +1,76 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ image/svg+xml -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/pixmaps/intlclock-map-location-hilight.png b/pixmaps/intlclock-map-location-hilight.png -new file mode 100644 -index 0000000..d7de5b7 -Binary files /dev/null and b/pixmaps/intlclock-map-location-hilight.png differ -diff --git a/pixmaps/intlclock-map-location-hilight.svg b/pixmaps/intlclock-map-location-hilight.svg -new file mode 100644 -index 0000000..4a245e0 ---- /dev/null -+++ b/pixmaps/intlclock-map-location-hilight.svg -@@ -0,0 +1,90 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ image/svg+xml -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/pixmaps/intlclock-map-location-marker.png b/pixmaps/intlclock-map-location-marker.png -new file mode 100644 -index 0000000..48d2184 -Binary files /dev/null and b/pixmaps/intlclock-map-location-marker.png differ -diff --git a/po/Makefile.in.in b/po/Makefile.in.in -deleted file mode 100755 -index d2d4e4c..e4713cf ---- a/po/Makefile.in.in -+++ /dev/null -@@ -1,221 +0,0 @@ --# Makefile for program source directory in GNU NLS utilities package. --# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper --# --# This file file be copied and used freely without restrictions. It can --# be used in projects which are not available under the GNU Public License --# but which still want to provide support for the GNU gettext functionality. --# Please note that the actual code is *not* freely available. --# --# - Modified by Owen Taylor to use GETTEXT_PACKAGE --# instead of PACKAGE and to look for po2tbl in ./ not in intl/ --# --# - Modified by jacob berkman to install --# Makefile.in.in and po2tbl.sed.in for use with glib-gettextize --# --# - Modified by Rodney Dawes for use with intltool --# --# We have the following line for use by intltoolize: --# INTLTOOL_MAKEFILE -- --GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ --PACKAGE = @PACKAGE@ --VERSION = @VERSION@ -- --SHELL = /bin/sh -- --srcdir = @srcdir@ --top_srcdir = @top_srcdir@ --top_builddir = .. --VPATH = @srcdir@ -- --prefix = @prefix@ --exec_prefix = @exec_prefix@ --datadir = @datadir@ --datarootdir = @datarootdir@ --libdir = @libdir@ --DATADIRNAME = @DATADIRNAME@ --itlocaledir = $(prefix)/$(DATADIRNAME)/locale --subdir = po --install_sh = @install_sh@ --# Automake >= 1.8 provides @mkdir_p@. --# Until it can be supposed, use the safe fallback: --mkdir_p = $(install_sh) -d -- --INSTALL = @INSTALL@ --INSTALL_DATA = @INSTALL_DATA@ -- --GMSGFMT = @GMSGFMT@ --MSGFMT = @MSGFMT@ --XGETTEXT = @XGETTEXT@ --INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ --INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ --MSGMERGE = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist --GENPOT = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot -- --ALL_LINGUAS = @ALL_LINGUAS@ -- --PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; fi) -- --POFILES=$(shell if test -n "$(PO_LINGUAS)"; then LINGUAS="$(PO_LINGUAS)"; else LINGUAS="$(ALL_LINGUAS)"; fi; for lang in $$LINGUAS; do printf "$$lang.po "; done) -- --DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(POFILES) --EXTRA_DISTFILES = POTFILES.skip Makevars LINGUAS -- --POTFILES = \ --#This Gets Replace for some reason -- --CATALOGS=$(shell if test -n "$(PO_LINGUAS)"; then LINGUAS="$(PO_LINGUAS)"; else LINGUAS="$(ALL_LINGUAS)"; fi; for lang in $$LINGUAS; do printf "$$lang.gmo "; done) -- --.SUFFIXES: --.SUFFIXES: .po .pox .gmo .mo .msg .cat -- --.po.pox: -- $(MAKE) $(GETTEXT_PACKAGE).pot -- $(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox -- --.po.mo: -- $(MSGFMT) -o $@ $< -- --.po.gmo: -- file=`echo $* | sed 's,.*/,,'`.gmo \ -- && rm -f $$file && $(GMSGFMT) -o $$file $< -- --.po.cat: -- sed -f ../intl/po2msg.sed < $< > $*.msg \ -- && rm -f $@ && gencat $@ $*.msg -- -- --all: all-@USE_NLS@ -- --all-yes: $(CATALOGS) --all-no: -- --$(GETTEXT_PACKAGE).pot: $(POTFILES) -- $(GENPOT) -- --install: install-data --install-data: install-data-@USE_NLS@ --install-data-no: all --install-data-yes: all -- $(mkdir_p) $(DESTDIR)$(itlocaledir) -- if test -n "$(PO_LINGUAS)"; then \ -- linguas="$(PO_LINGUAS)"; \ -- else \ -- linguas="$(ALL_LINGUAS)"; \ -- fi; \ -- for lang in $$linguas; do \ -- dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \ -- $(mkdir_p) $$dir; \ -- if test -r $$lang.gmo; then \ -- $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ -- echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \ -- else \ -- $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ -- echo "installing $(srcdir)/$$lang.gmo as" \ -- "$$dir/$(GETTEXT_PACKAGE).mo"; \ -- fi; \ -- if test -r $$lang.gmo.m; then \ -- $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ -- echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ -- else \ -- if test -r $(srcdir)/$$lang.gmo.m ; then \ -- $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \ -- $$dir/$(GETTEXT_PACKAGE).mo.m; \ -- echo "installing $(srcdir)/$$lang.gmo.m as" \ -- "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ -- else \ -- true; \ -- fi; \ -- fi; \ -- done -- --# Empty stubs to satisfy archaic automake needs --dvi info tags TAGS ID: -- --# Define this as empty until I found a useful application. --installcheck: -- --uninstall: -- if test -n "$(PO_LINGUAS)"; then \ -- linguas="$(PO_LINGUAS)"; \ -- else \ -- linguas="$(ALL_LINGUAS)"; \ -- fi; \ -- for lang in $$linguas; do \ -- rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ -- rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ -- done -- --check: all $(GETTEXT_PACKAGE).pot -- --mostlyclean: -- rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp -- rm -f .intltool-merge-cache -- --clean: mostlyclean -- --distclean: clean -- rm -f Makefile Makefile.in POTFILES stamp-it -- rm -f *.mo *.msg *.cat *.cat.m *.gmo -- --maintainer-clean: distclean -- @echo "This command is intended for maintainers to use;" -- @echo "it deletes files that may require special tools to rebuild." -- rm -f Makefile.in.in -- --distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) --dist distdir: $(DISTFILES) -- dists="$(DISTFILES)"; \ -- extra_dists="$(EXTRA_DISTFILES)"; \ -- for file in $$extra_dists; do \ -- test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ -- done; \ -- for file in $$dists; do \ -- test -f $$file || file="$(srcdir)/$$file"; \ -- ln $$file $(distdir) 2> /dev/null \ -- || cp -p $$file $(distdir); \ -- done -- --update-po: Makefile -- $(MAKE) $(GETTEXT_PACKAGE).pot -- tmpdir=`pwd`; \ -- if test -n "$(PO_LINGUAS)"; then \ -- linguas="$(PO_LINGUAS)"; \ -- else \ -- linguas="$(ALL_LINGUAS)"; \ -- fi; \ -- for lang in $$linguas; do \ -- echo "$$lang:"; \ -- result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \ -- if $$result; then \ -- if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ -- rm -f $$tmpdir/$$lang.new.po; \ -- else \ -- if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ -- :; \ -- else \ -- echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ -- rm -f $$tmpdir/$$lang.new.po; \ -- exit 1; \ -- fi; \ -- fi; \ -- else \ -- echo "msgmerge for $$lang.gmo failed!"; \ -- rm -f $$tmpdir/$$lang.new.po; \ -- fi; \ -- done -- --Makefile POTFILES: stamp-it -- @if test ! -f $@; then \ -- rm -f stamp-it; \ -- $(MAKE) stamp-it; \ -- fi -- --stamp-it: Makefile.in.in ../config.status POTFILES.in -- cd .. \ -- && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ -- $(SHELL) ./config.status -- --# Tell versions [3.59,3.63) of GNU make not to export all variables. --# Otherwise a system limit (for SysV at least) may be exceeded. --.NOEXPORT: -diff --git a/po/Makefile.in.in b/po/Makefile.in.in -new file mode 120000 -index d2d4e4c..e4713cf ---- /dev/null -+++ b/po/Makefile.in.in -@@ -0,0 +1 @@ -+/usr/share/intltool/Makefile.in.in -\ No newline at end of file -diff --git a/src/Makefile.am b/src/Makefile.am -index 80d1419..d681d39 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -3,7 +3,7 @@ - INCLUDES = \ - $(INTLCLOCK_CFLAGS) \ - -DGNOMELOCALEDIR=\"$(prefix)/$(DATADIRNAME)/locale\" \ -- -DEVOLUTION_TEXTDOMAIN=\"evolution-2.6\" \ -+ -DEVOLUTION_TEXTDOMAIN=\"evolution-2.12\" \ - -DINTLCLOCK_TEXTDOMAIN=\"gnome-panel-2.0\" \ - -DINTLCLOCK_ICONDIR=\"$(pkgdatadir)\" \ - -DINTLCLOCK_DATADIR=\"$(pkgdatadir)\" \ -@@ -60,7 +60,11 @@ COMMON_SOURCES = \ - intlclock-zoneinfo.c \ - intlclock-zoneinfo.h \ - intlclock-zonetable.c \ -- intlclock-zonetable.h -+ intlclock-zonetable.h \ -+ set-timezone.c \ -+ set-timezone.h \ -+ gweather-xml.c \ -+ gweather-xml.h - - - intlclock_applet_SOURCES = \ -diff --git a/src/gweather-xml.c b/src/gweather-xml.c -new file mode 100644 -index 0000000..1de649f ---- /dev/null -+++ b/src/gweather-xml.c -@@ -0,0 +1,505 @@ -+/* gweather-xml.c - Locations.xml parsing code -+ * -+ * Copyright (C) 2005 Ryan Lortie, 2004 Gareth Owen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+ -+/* There is very little error checking in the parsing code below, it relies -+ * heavily on the locations file being in the correct format. If you have -+ * elements within a parent element, they must come first and be -+ * grouped together. -+ * The format is as follows: -+ * -+ * -+ * -+ * Name of the region -+ * Translated Name -+ * Another Translated Name -+ * -+ * Name of the country -+ * -+ * Name of the location -+ * IWIN code -+ * Forecast code (North America, Australia, UK only) -+ * Weather.com radar map code (North America only) -+ * Latitude and longitude as DD-MM[-SS][H] pair -+ * -+ * -+ * -+ * .... -+ * -+ * -+ * Name of city with multiple locations -+ * Forecast code -+ * Radar Map code -+ * -+ * ... -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * The thing to note is that each country can either contain different locations -+ * or be split into "states" which in turn contain a list of locations. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "gweather-xml.h" -+ -+static gint -+gweather_xml_location_sort_func( GtkTreeModel *model, GtkTreeIter *a, -+ GtkTreeIter *b, gpointer user_data ) -+{ -+ gint res; -+ gchar *name_a, *name_b; -+ gchar *fold_a, *fold_b; -+ -+ gtk_tree_model_get (model, a, GWEATHER_XML_COL_LOC, &name_a, -1); -+ gtk_tree_model_get (model, b, GWEATHER_XML_COL_LOC, &name_b, -1); -+ -+ fold_a = g_utf8_casefold(name_a, -1); -+ fold_b = g_utf8_casefold(name_b, -1); -+ -+ res = g_utf8_collate(fold_a, fold_b); -+ -+ g_free(name_a); -+ g_free(name_b); -+ g_free(fold_a); -+ g_free(fold_b); -+ -+ return res; -+} -+ -+static char* -+gweather_xml_get_value( xmlTextReaderPtr xml ) -+{ -+ char* value; -+ -+ /* check for null node */ -+ if ( xmlTextReaderIsEmptyElement( xml ) ) -+ return NULL; -+ -+ /* the next "node" is the text node containing the value we want to get */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ return NULL; -+ -+ value = (char *) xmlTextReaderValue( xml ); -+ -+ /* move on to the end of this node */ -+ while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_END_ELEMENT ) -+ if( xmlTextReaderRead( xml ) != 1 ) -+ { -+ xmlFree( value ); -+ return NULL; -+ } -+ -+ /* consume the end element too */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ { -+ xmlFree( value ); -+ return NULL; -+ } -+ -+ return value; -+} -+ -+static char * -+gweather_xml_parse_name( xmlTextReaderPtr xml ) -+{ -+ const char * const *locales; -+ const char *this_language; -+ int best_match = INT_MAX; -+ char *lang, *tagname; -+ gboolean keep_going; -+ char *name = NULL; -+ int i; -+ -+ locales = g_get_language_names(); -+ -+ do -+ { -+ /* First let's get the language */ -+ lang = (char *) xmlTextReaderXmlLang( xml ); -+ -+ if( lang == NULL ) -+ this_language = "C"; -+ else -+ this_language = lang; -+ -+ /* the next "node" is text node containing the actual name */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ { -+ xmlFree( lang ); -+ return NULL; -+ } -+ -+ for( i = 0; locales[i] && i < best_match; i++ ) -+ if( !strcmp( locales[i], this_language ) ) -+ { -+ /* if we've already encounted a less accurate -+ translation, then free it */ -+ xmlFree( name ); -+ -+ name = (char *) xmlTextReaderValue( xml ); -+ best_match = i; -+ -+ break; -+ } -+ -+ xmlFree( lang ); -+ -+ while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_ELEMENT ) -+ if( xmlTextReaderRead( xml ) != 1 ) -+ { -+ xmlFree( name ); -+ return NULL; -+ } -+ -+ /* if the next tag is another then keep going */ -+ tagname = (char *) xmlTextReaderName( xml ); -+ keep_going = !strcmp( tagname, "name" ); -+ xmlFree( tagname ); -+ -+ } while( keep_going ); -+ -+ return name; -+} -+ -+static int -+gweather_xml_parse_node (GtkTreeView *view, GtkTreeIter *parent, -+ xmlTextReaderPtr xml, WeatherLocation *current, -+ const char *dflt_radar, const char *dflt_zone, -+ const char *cityname) -+{ -+ GtkTreeStore *store = GTK_TREE_STORE( gtk_tree_view_get_model( view ) ); -+ char *name, *code, *zone, *radar, *coordinates; -+ char **city, *nocity = NULL; -+ GtkTreeIter iter, *self; -+ gboolean is_location; -+ char *tagname; -+ int ret = -1; -+ int tagtype; -+ -+ if( (tagname = (char *) xmlTextReaderName( xml )) == NULL ) -+ return -1; -+ -+ if( !strcmp( tagname, "city" ) ) -+ city = &name; -+ else -+ city = &nocity; -+ -+ is_location = !strcmp( tagname, "location" ); -+ -+ /* if we're processing the top-level, then don't create a new iter */ -+ if( !strcmp( tagname, "gweather" ) ) -+ self = NULL; -+ else -+ { -+ self = &iter; -+ /* insert this node into the tree */ -+ gtk_tree_store_append( store, self, parent ); -+ } -+ -+ xmlFree( tagname ); -+ -+ coordinates = NULL; -+ radar = NULL; -+ zone = NULL; -+ code = NULL; -+ name = NULL; -+ -+ /* absorb the start tag */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ goto error_out; -+ -+ /* start parsing the actual contents of the node */ -+ while( (tagtype = xmlTextReaderNodeType( xml )) != -+ XML_READER_TYPE_END_ELEMENT ) -+ { -+ -+ /* skip non-element types */ -+ if( tagtype != XML_READER_TYPE_ELEMENT ) -+ { -+ if( xmlTextReaderRead( xml ) != 1 ) -+ goto error_out; -+ -+ continue; -+ } -+ -+ tagname = (char *) xmlTextReaderName( xml ); -+ -+ if( !strcmp( tagname, "region" ) || !strcmp( tagname, "country" ) || -+ !strcmp( tagname, "state" ) || !strcmp( tagname, "city" ) || -+ !strcmp( tagname, "location" ) ) -+ { -+ /* recursively handle sub-sections */ -+ if( gweather_xml_parse_node( view, self, xml, current, -+ radar, zone, *city ) ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "name" ) ) -+ { -+ xmlFree( name ); -+ if( (name = gweather_xml_parse_name( xml )) == NULL ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "code" ) ) -+ { -+ xmlFree( code ); -+ if( (code = gweather_xml_get_value( xml )) == NULL ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "zone" ) ) -+ { -+ xmlFree( zone ); -+ if( (zone = gweather_xml_get_value( xml )) == NULL ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "radar" ) ) -+ { -+ xmlFree( radar ); -+ if( (radar = gweather_xml_get_value( xml )) == NULL ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "coordinates" ) ) -+ { -+ xmlFree( coordinates ); -+ if( (coordinates = gweather_xml_get_value( xml )) == NULL ) -+ goto error_out; -+ } -+ else /* some strange tag */ -+ { -+ /* skip past it */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ goto error_out; -+ } -+ -+ xmlFree( tagname ); -+ } -+ -+ if( self ) -+ gtk_tree_store_set( store, self, GWEATHER_XML_COL_LOC, name, -1 ); -+ -+ /* absorb the end tag. in the case of processing a then 'self' -+ is NULL. In this case, we let this fail since we might be at EOF */ -+ if( xmlTextReaderRead( xml ) != 1 && self ) -+ goto error_out; -+ -+ /* if this is an actual location, setup the WeatherLocation for it */ -+ if( is_location ) -+ { -+ WeatherLocation *new_loc; -+ -+ if( cityname == NULL ) -+ cityname = name; -+ -+ if( radar != NULL ) -+ dflt_radar = radar; -+ -+ if( zone != NULL ) -+ dflt_zone = zone; -+ -+ new_loc = weather_location_new( cityname, code, dflt_zone, -+ dflt_radar, coordinates ); -+ -+ gtk_tree_store_set( store, &iter, GWEATHER_XML_COL_POINTER, new_loc, -1 ); -+ -+ /* If this location is actually the currently selected one, select it */ -+ if( current && weather_location_equal( new_loc, current ) ) -+ { -+ GtkTreePath *path; -+ -+ path = gtk_tree_model_get_path( GTK_TREE_MODEL (store), &iter ); -+ gtk_tree_view_expand_to_path( view, path ); -+ gtk_tree_view_set_cursor( view, path, NULL, FALSE ); -+ gtk_tree_view_scroll_to_cell( view, path, NULL, TRUE, 0.5, 0.5 ); -+ gtk_tree_path_free( path ); -+ } -+ } -+ -+ ret = 0; -+ -+error_out: -+ xmlFree( name ); -+ xmlFree( code ); -+ xmlFree( zone ); -+ xmlFree( radar ); -+ xmlFree( coordinates ); -+ -+ return ret; -+} -+ -+/***************************************************************************** -+ * Func: gweather_xml_load_locations() -+ * Desc: Main entry point for loading the locations from the XML file -+ * Parm: -+ * *tree: tree to view locations -+ * *current: currently selected location -+ */ -+int -+gweather_xml_load_locations( GtkTreeView *tree, WeatherLocation *current ) -+{ -+ char *tagname, *format; -+ GtkTreeSortable *sortable; -+ xmlTextReaderPtr xml; -+ int keep_going; -+ int ret = -1; -+ -+ /* Open the xml file containing the different locations */ -+#ifdef GWEATHER_XML_LOCATION -+ xml = xmlNewTextReaderFilename (GWEATHER_XML_LOCATION "Locations.xml"); -+#else -+ xml = xmlNewTextReaderFilename ("/usr/share/gnome-applets/gweather/Locations.xml"); -+#endif -+ if( xml == NULL ) -+ goto error_out; -+ -+ /* fast forward to the first element */ -+ do -+ { -+ /* if we encounter a problem here, exit right away */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ goto error_out; -+ } while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_ELEMENT ); -+ -+ /* check the name and format */ -+ tagname = (char *) xmlTextReaderName( xml ); -+ keep_going = tagname && !strcmp( tagname, "gweather" ); -+ xmlFree( tagname ); -+ -+ if( !keep_going ) -+ goto error_out; -+ -+ format = (char *) xmlTextReaderGetAttribute( xml, (xmlChar *) "format" ); -+ keep_going = format && !strcmp( format, "1.0" ); -+ xmlFree( format ); -+ -+ if( !keep_going ) -+ goto error_out; -+ -+ ret = gweather_xml_parse_node( tree, NULL, xml, current, NULL, NULL, NULL ); -+ -+ if( ret ) -+ goto error_out; -+ -+ /* Sort the tree */ -+ sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model( tree )); -+ gtk_tree_sortable_set_default_sort_func( sortable, -+ &gweather_xml_location_sort_func, -+ NULL, NULL); -+ gtk_tree_sortable_set_sort_column_id( sortable, -+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, -+ GTK_SORT_ASCENDING ); -+error_out: -+ xmlFreeTextReader( xml ); -+ -+ return ret; -+} -+ -+typedef struct { -+ const gchar *name; -+ gdouble latitude; -+ gdouble longitude; -+ gdouble distance; -+ WeatherLocation *location; -+} SearchData; -+ -+ -+static gdouble -+distance (gdouble lat1, gdouble lon1, -+ gdouble lat2, gdouble lon2) -+{ -+ gdouble radius = 6372.795; -+ -+ return acos (cos (lat1) * cos (lat2) * cos (lon1 - lon2) + sin (lat1) * sin (lat2)) * radius; -+} -+ -+gboolean -+compare_location (GtkTreeModel *model, -+ GtkTreePath *path, -+ GtkTreeIter *iter, -+ gpointer user_data) -+{ -+ SearchData *data = user_data; -+ WeatherLocation *loc; -+ gdouble d; -+ -+ gtk_tree_model_get (model, iter, GWEATHER_XML_COL_POINTER, &loc, -1); -+ -+ if (!loc) -+ return FALSE; -+ -+ d = distance (data->latitude, data->longitude, loc->latitude, loc->longitude); -+ -+ if (d < data->distance) { -+ data->distance = d; -+ data->location = loc; -+ } -+ -+ return FALSE; -+} -+ -+gchar * -+find_weather_code (const gchar *name, -+ gdouble lat, -+ gdouble lon) -+{ -+ GtkTreeStore *model; -+ GtkWidget *tv; -+ GtkTreeViewColumn *column; -+ GtkCellRenderer *cell_renderer; -+ SearchData data; -+ gchar *code; -+ -+ model = gtk_tree_store_new (GWEATHER_XML_NUM_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER); -+ tv = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model)); -+ -+ cell_renderer = gtk_cell_renderer_text_new (); -+ column = gtk_tree_view_column_new_with_attributes ("not used", cell_renderer, -+ "text", GWEATHER_XML_COL_LOC, NULL); -+ gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column); -+ gtk_tree_view_set_expander_column (GTK_TREE_VIEW (tv), column); -+ gweather_xml_load_locations (GTK_TREE_VIEW (tv), NULL); -+ -+ data.name = name; -+ data.latitude = lat; -+ data.longitude = lon; -+ data.distance = 1e6; -+ data.location = NULL; -+ -+ gtk_tree_model_foreach (GTK_TREE_MODEL (model), compare_location, &data); -+ -+ if (data.distance < 50) -+ code = g_strdup (data.location->code); -+ else -+ code = g_strdup ("-"); -+ -+ g_debug ("distance: %f\nin: %s\nlat, lon: %f, %f\nout: %s\nDMS: %s\ncode: %s\n", -+ data.distance, name, lat, lon, data.location->name, data.location->coordinates, code); -+ -+ gtk_widget_destroy (tv); -+ -+ return code; -+} -diff --git a/src/gweather-xml.h b/src/gweather-xml.h -new file mode 100644 -index 0000000..6d012c4 ---- /dev/null -+++ b/src/gweather-xml.h -@@ -0,0 +1,37 @@ -+/* gweather-xml.h -+ * -+ * Copyright (C) 2004 Gareth Owen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#ifndef __GWEATHER_XML_H__ -+#define __GWEATHER_XML_H__ -+ -+#include -+#include -+ -+enum -+{ -+ GWEATHER_XML_COL_LOC = 0, -+ GWEATHER_XML_COL_POINTER, -+ GWEATHER_XML_NUM_COLUMNS -+}; -+ -+int gweather_xml_load_locations( GtkTreeView *tree, WeatherLocation *current ); -+gchar *find_weather_code (const gchar *name, gdouble lat, gdouble lon); -+ -+ -+#endif /* __GWEATHER_XML_H__ */ -diff --git a/src/intlclock-events-popup.c b/src/intlclock-events-popup.c -index 4276f81..a54f6e3 100644 ---- a/src/intlclock-events-popup.c -+++ b/src/intlclock-events-popup.c -@@ -1,6 +1,8 @@ - #include - #include - #include -+#include -+#include - - #ifdef HAVE_CONFIG_H - #include "config.h" -@@ -11,12 +13,18 @@ - #endif - - #include "intlclock-events-popup.h" -+#include "intlclock-ui.h" -+ -+#define KEY_EXPAND_LOCATIONS "expand_locations" -+#define KEY_EXPAND_TASKS "expand_tasks" -+#define KEY_EXPAND_APPOINTMENTS "expand_appointments" - - G_DEFINE_TYPE (IntlClockEventsPopup, intlclock_events_popup, GTK_TYPE_WINDOW) - - typedef struct { - IntlClock *clock; - PanelApplet *panel_applet; -+ IntlClockUI *ui; - - GtkWidget *calendar; - GtkWidget *main_section; -@@ -126,7 +134,7 @@ intlclock_events_popup_size_allocate_cb (GtkWidget *widget, GtkAllocation *alloc - } - - IntlClockEventsPopup * --intlclock_events_popup_new (IntlClock *clock, PanelApplet *panel_applet) -+intlclock_events_popup_new (IntlClock *clock, PanelApplet *panel_applet, IntlClockUI *ui) - { - IntlClockEventsPopup *this; - IntlClockEventsPopupPrivate *priv; -@@ -138,6 +146,7 @@ intlclock_events_popup_new (IntlClock *clock, PanelApplet *panel_applet) - - priv->clock = g_object_ref (clock); - priv->panel_applet = panel_applet; -+ priv->ui = ui; - - gtk_widget_set_name (GTK_WIDGET (this), "intlclock-events-window"); - gtk_container_set_border_width (GTK_CONTAINER (this), 0); -@@ -275,6 +284,21 @@ intlclock_events_popup_tick (IntlClock *clock, IntlClockEventsPopup *this) - gmtime (&priv->current_time); - } - -+static GtkWidget * create_hig_frame (IntlClockEventsPopup *this, -+ const char *title, -+ const char *button_label, -+ const char *key, -+ GCallback callback); -+ -+ -+static void -+edit_locations (IntlClockEventsPopup *this) -+{ -+ IntlClockEventsPopupPrivate *priv = PRIVATE (this); -+ -+ intlclock_ui_edit_locations (priv->ui); -+} -+ - static void - intlclock_events_popup_fill (IntlClockEventsPopup *this) - { -@@ -296,7 +320,10 @@ intlclock_events_popup_fill (IntlClockEventsPopup *this) - - orient = panel_applet_get_orient (priv->panel_applet); - -- priv->clock_container = gtk_vbox_new (FALSE, 0); -+ priv->clock_container = create_hig_frame (this, -+ _("Locations"), _("Edit"), -+ KEY_EXPAND_LOCATIONS, -+ G_CALLBACK (edit_locations)); - - switch (orient) { - case PANEL_APPLET_ORIENT_UP: -@@ -642,28 +669,167 @@ modify_task_text_attributes (GtkTreeModel *model, - g_value_take_boxed (value, attr_list); - } - -+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 -+expander_activated (GtkExpander *expander, -+ gpointer data) -+{ -+ IntlClockEventsPopup *this = data; -+ IntlClockEventsPopupPrivate *priv = PRIVATE (this); -+ const gchar *key; -+ gboolean expanded; -+ -+ key = (const gchar*)g_object_get_data (G_OBJECT (expander), "gconf-key"); -+ expanded = gtk_expander_get_expanded (expander); -+ -+ panel_applet_gconf_set_bool (priv->panel_applet, key, expanded, NULL); -+} -+ -+static void -+expanded_changed (GConfClient *client, -+ guint cnxn_id, -+ GConfEntry *entry, -+ GtkExpander *expander) -+{ -+ if (!entry->value || entry->value->type != GCONF_VALUE_BOOL) -+ return; -+ -+ gtk_expander_set_expanded (expander, -+ gconf_value_get_bool (entry->value)); -+} -+ -+static void -+remove_listener (gpointer data) -+{ -+ GConfClient *client; -+ -+ client = gconf_client_get_default (); -+ gconf_client_notify_remove (client, GPOINTER_TO_UINT (data)); -+ g_object_unref (client); -+} -+ -+static void -+connect_expander_with_gconf (IntlClockEventsPopup *this, -+ GtkWidget *expander, -+ const gchar *key) -+{ -+ IntlClockEventsPopupPrivate *priv = PRIVATE (this); -+ GConfClient *client; -+ gboolean expanded; -+ guint listener; -+ gchar *full_key; -+ -+ g_object_set_data (G_OBJECT (expander), "gconf-key", (gpointer)key); -+ -+ expanded = panel_applet_gconf_get_bool (priv->panel_applet, key, NULL); -+ gtk_expander_set_expanded (GTK_EXPANDER (expander), expanded); -+ -+ g_signal_connect_after (expander, "activate", -+ G_CALLBACK (expander_activated), -+ this); -+ -+ client = gconf_client_get_default (); -+ full_key = panel_applet_gconf_get_full_key (priv->panel_applet, key); -+ listener = gconf_client_notify_add (client, full_key, -+ (GConfClientNotifyFunc)expanded_changed, -+ expander, NULL, NULL); -+ g_object_set_data_full (G_OBJECT (expander), "listener-id", -+ GUINT_TO_POINTER (listener), remove_listener); -+ g_object_unref (client); -+} -+ -+static void add_child (GtkContainer *container, -+ GtkWidget *child, -+ GtkExpander *expander) -+{ -+ gboolean expanded; -+ -+ expanded = gtk_expander_get_expanded (expander); -+ g_object_set (child, "visible", expanded, NULL); -+} -+ - static GtkWidget * --create_hig_frame (const char *title) -+create_hig_frame (IntlClockEventsPopup *this, -+ 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); -- -- alignment = gtk_alignment_new (0, 0.5, 0, 0); -- gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0); -- gtk_widget_show (alignment); -- -- label = gtk_label_new (bold_title); -- gtk_label_set_use_markup (GTK_LABEL (label), TRUE); -- gtk_container_add (GTK_CONTAINER (alignment), label); -- gtk_widget_show (label); -- -+ expander = gtk_expander_new (""); -+ gtk_expander_set_label (GTK_EXPANDER (expander), 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, this); -+ } -+ -+ connect_expander_with_gconf (this, expander, key); - - return vbox; - } -@@ -791,6 +957,12 @@ compare_tasks (GtkTreeModel *model, - } - } - -+static void -+edit_tasks (IntlClockEventsPopup *this) -+{ -+ clock_launch_evolution (this, "--component=tasks"); -+} -+ - static GtkWidget * - create_task_list (IntlClockEventsPopup *this, - GtkWidget **tree_view, -@@ -804,7 +976,9 @@ create_task_list (IntlClockEventsPopup *this, - GtkCellRenderer *cell; - GtkTreeViewColumn *column; - -- vbox = create_hig_frame (_("Tasks")); -+ vbox = create_hig_frame (this, _("Tasks"), _("Edit"), -+ KEY_EXPAND_TASKS, -+ G_CALLBACK (edit_tasks)); - - *scrolled_window = scrolled = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), -@@ -812,8 +986,8 @@ create_task_list (IntlClockEventsPopup *this, - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), - GTK_POLICY_NEVER, - GTK_POLICY_AUTOMATIC); -- gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0); - gtk_widget_show (scrolled); -+ gtk_container_add (GTK_CONTAINER (vbox), scrolled); - - if (!priv->tasks_model) { - GType column_types [N_TASK_COLUMNS] = { -@@ -984,6 +1158,12 @@ handle_appointments_changed (IntlClockEventsPopup *this) - update_frame_visibility (priv->appointment_list, GTK_TREE_MODEL (priv->appointments_model)); - } - -+static void -+edit_appointments (IntlClockEventsPopup *this) -+{ -+ clock_launch_evolution (this, "--component=calendar"); -+} -+ - static GtkWidget * - create_appointment_list (IntlClockEventsPopup *this, - GtkWidget **tree_view, -@@ -997,7 +1177,9 @@ create_appointment_list (IntlClockEventsPopup *this, - GtkCellRenderer *cell; - GtkTreeViewColumn *column; - -- vbox = create_hig_frame ( _("Appointments")); -+ vbox = create_hig_frame (this, _("Appointments"), _("Edit"), -+ KEY_EXPAND_APPOINTMENTS, -+ G_CALLBACK (edit_appointments)); - - *scrolled_window = scrolled = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), -@@ -1005,8 +1187,8 @@ create_appointment_list (IntlClockEventsPopup *this, - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), - GTK_POLICY_NEVER, - GTK_POLICY_AUTOMATIC); -- gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0); - gtk_widget_show (scrolled); -+ gtk_container_add (GTK_CONTAINER (vbox), scrolled); - - if (!priv->appointments_model) { - priv->appointments_model = -diff --git a/src/intlclock-events-popup.h b/src/intlclock-events-popup.h -index 84a5183..b88e4c7 100644 ---- a/src/intlclock-events-popup.h -+++ b/src/intlclock-events-popup.h -@@ -2,6 +2,7 @@ - #define __INTLCLOCK_EVENTS_POPUP_H__ - - #include "intlclock.h" -+#include "intlclock-ui.h" - - #include - #include -@@ -29,7 +30,8 @@ typedef struct - GType intlclock_events_popup_get_type (void); - - IntlClockEventsPopup *intlclock_events_popup_new (IntlClock *clock, -- PanelApplet *panel_applet); -+ PanelApplet *panel_applet, -+ IntlClockUI *ui); - void intlclock_events_popup_set_date (IntlClockEventsPopup *this, - guint year, guint month, guint mday); - GtkWidget *intlclock_events_popup_get_clock_container (IntlClockEventsPopup *this); -diff --git a/src/intlclock-location-tile.c b/src/intlclock-location-tile.c -index 40d96e3..412ad22 100644 ---- a/src/intlclock-location-tile.c -+++ b/src/intlclock-location-tile.c -@@ -23,9 +23,18 @@ typedef struct { - - IntlClockFaceSize size; - -+ GtkWidget *box; - GtkWidget *clock_face; - GtkWidget *city_label; - GtkWidget *time_label; -+ -+ GtkWidget *current_button; -+ GtkWidget *current_label; -+ GtkWidget *current_marker; -+ GtkSizeGroup *button_group; -+ -+ GtkWidget *weather_icon; -+ - } IntlClockLocationTilePrivate; - - static void intlclock_location_tile_finalize (GObject *); -@@ -36,6 +45,12 @@ static void intlclock_location_tile_refresh (IntlClockLocationTile *this); - #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INTLCLOCK_LOCATION_TILE_TYPE, IntlClockLocationTilePrivate)) - - static void intlclock_location_tile_fill (IntlClockLocationTile *this); -+static void update_weather_icon (IntlClockLocation *loc, WeatherInfo *info, gpointer data); -+static gboolean weather_tooltip (GtkWidget *widget, -+ gint x, gint y, -+ gboolean keyboard_mode, -+ GtkTooltip *tooltip, -+ gpointer data); - - IntlClockLocationTile * - intlclock_location_tile_new (IntlClock *clock, IntlClockUI *ui, -@@ -56,13 +71,17 @@ intlclock_location_tile_new (IntlClock *clock, IntlClockUI *ui, - priv->location = g_object_ref (loc); - priv->size = size; - -- gtk_alignment_set (GTK_ALIGNMENT (this), 0.0, 0.0, 0.0, 0.0); -- gtk_alignment_set_padding (GTK_ALIGNMENT (this), 3, 3, 3, 3); -- - intlclock_location_tile_fill (this); - -- g_signal_connect (G_OBJECT (priv->clock), "tick", -- G_CALLBACK (intlclock_location_tile_tick), this); -+ update_weather_icon (loc, intlclock_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); -+ g_signal_connect (G_OBJECT (loc), "weather-updated", -+ G_CALLBACK (update_weather_icon), this); -+ g_signal_connect (G_OBJECT (priv->clock), "tick", -+ G_CALLBACK (intlclock_location_tile_tick), this); - - return this; - } -@@ -133,13 +152,99 @@ intlclock_location_tile_finalize (GObject *g_obj) - priv->location = NULL; - } - -+ if (priv->button_group) { -+ g_object_unref (priv->button_group); -+ priv->button_group = NULL; -+ } -+ - G_OBJECT_CLASS (intlclock_location_tile_parent_class)->finalize (g_obj); - } - -+static gboolean -+press_on_tile (GtkWidget *widget, -+ GdkEventButton *event, -+ IntlClockLocationTile *tile) -+{ -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ -+ intlclock_blink_location (priv->clock, priv->location); -+ -+ return TRUE; -+} -+ -+static void -+make_current (GtkWidget *widget, IntlClockLocationTile *tile) -+{ -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ GError *error = NULL; -+ GtkWidget *dialog; -+ -+ if (intlclock_location_make_current (priv->location, &error)) { -+ g_signal_emit_by_name (priv->clock, "current-timezone-changed", 0); -+ } -+ else if (error) { -+ dialog = gtk_message_dialog_new (NULL, -+ 0, -+ GTK_MESSAGE_ERROR, -+ GTK_BUTTONS_OK, -+ _("Failed to set the system timezone")); -+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), error->message); -+ g_signal_connect (dialog, "response", -+ G_CALLBACK (gtk_widget_destroy), NULL); -+ gtk_window_present (GTK_WINDOW (dialog)); -+ -+ g_error_free (error); -+ } -+} -+ -+static gboolean -+enter_or_leave_tile (GtkWidget *widget, -+ GdkEventCrossing *event, -+ IntlClockLocationTile *tile) -+{ -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ -+ if (event->type == GDK_ENTER_NOTIFY) { -+ gint can_set; -+ -+ can_set = can_set_system_timezone (); -+ if (!intlclock_location_is_current (priv->location) && -+ can_set != 0) { -+ gtk_label_set_markup (GTK_LABEL (priv->current_label), -+ can_set == 1 ? -+ _("Set...") : -+ _("Set")); -+ gtk_widget_show (priv->current_button); -+ } -+ } -+ else { -+ if (event->detail != GDK_NOTIFY_INFERIOR) -+ gtk_widget_hide (priv->current_button); -+ } -+ -+ return TRUE; -+} -+ - static void - intlclock_location_tile_fill (IntlClockLocationTile *this) - { - IntlClockLocationTilePrivate *priv = PRIVATE (this); -+ GtkWidget *align; -+ GtkWidget *strut; -+ GtkWidget *box; -+ -+ 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); -+ -+ GtkWidget *alignment = gtk_alignment_new (0, 0, 1, 0); -+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 3, 3, 3, 0); - - GtkWidget *tile = gtk_hbox_new (FALSE, 6); - GtkWidget *head_section = gtk_vbox_new (FALSE, 0); -@@ -147,21 +252,55 @@ intlclock_location_tile_fill (IntlClockLocationTile *this) - 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); - -- gtk_box_pack_start (GTK_BOX (head_section), priv->city_label, -- FALSE, FALSE, 0); -- gtk_box_pack_start (GTK_BOX (head_section), priv->time_label, -- FALSE, FALSE, 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 (); -+ 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 as current timezone for this computer")); -+ -+ priv->current_marker = gtk_image_new_from_icon_name ("go-home", GTK_ICON_SIZE_BUTTON); -+ gtk_widget_set_no_show_all (priv->current_marker, TRUE); -+ -+ align = gtk_alignment_new (1, 1, 0, 0); -+ 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); -+ 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); -+ -+ g_signal_connect (priv->current_button, "clicked", -+ G_CALLBACK (make_current), this); - - priv->clock_face = intlclock_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, FALSE, FALSE, 0); -+ gtk_box_pack_start (GTK_BOX (tile), head_section, TRUE, TRUE, 0); - -- gtk_container_add (GTK_CONTAINER (this), tile); -+ gtk_container_add (GTK_CONTAINER (alignment), tile); -+ gtk_container_add (GTK_CONTAINER (priv->box), alignment); -+ gtk_container_add (GTK_CONTAINER (this), priv->box); - - intlclock_location_tile_refresh (this); - } -@@ -231,6 +370,21 @@ intlclock_location_tile_refresh (IntlClockLocationTile *this) - char buf[256]; - struct tm now; - -+ if (intlclock_location_is_current (priv->location)) { -+ if (!GTK_WIDGET_VISIBLE (priv->current_marker)) { -+ GdkPixbuf *pixbuf; -+ -+ pixbuf = gtk_image_get_pixbuf (GTK_IMAGE (priv->weather_icon)); -+ intlclock_ui_update_weather_icon (priv->ui, pixbuf); -+ } -+ -+ gtk_widget_hide (priv->current_button); -+ gtk_widget_show (priv->current_marker); -+ } -+ else { -+ gtk_widget_hide (priv->current_marker); -+ } -+ - if (intlclock_needs_face_refresh (this)) { - intlclock_face_refresh (INTLCLOCK_FACE (priv->clock_face)); - } -@@ -271,3 +425,86 @@ intlclock_location_tile_tick (IntlClock *clock, - - intlclock_location_tile_refresh (this); - } -+ -+static gboolean -+weather_tooltip (GtkWidget *widget, -+ gint x, -+ gint y, -+ gboolean keyboard_mode, -+ GtkTooltip *tooltip, -+ gpointer data) -+{ -+ IntlClockLocationTile *tile = data; -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ WeatherInfo *info; -+ GdkPixbuf *pixbuf = NULL; -+ gchar *conditions, *temp, *apparent, *wind; -+ gchar *line1, *line2, *line3, *line4, *tip; -+ -+ info = intlclock_location_get_weather_info (priv->location); -+ -+ if (!info || !weather_info_is_valid (info)) -+ return FALSE; -+ -+ weather_info_get_pixbuf (info, &pixbuf); -+ 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)); -+ -+ temp = weather_info_get_temp (info); -+ apparent = weather_info_get_apparent (info); -+ if (strcmp (apparent, temp) != 0 && -+ /* FIXME libgweather needs some real api */ -+ strcmp (apparent, dgettext ("gnome-applets-2.0", "Unknown")) != 0) -+ line2 = g_strdup_printf (_("%s, feels like %s"), temp, apparent); -+ else -+ line2 = g_strdup (temp); -+ -+ wind = weather_info_get_wind (info); -+ if (strcmp (apparent, dgettext ("gnome-applets-2.0", "Unknown")) != 0) -+ line3 = g_strdup_printf ("%s\n", wind); -+ else -+ line3 = g_strdup (""); -+ -+ line4 = g_strdup_printf (_("Sunrise: %s / Sunset: %s"), -+ weather_info_get_sunrise (info), -+ weather_info_get_sunset (info)); -+ -+ 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); -+ -+ return TRUE; -+} -+ -+ -+static void -+update_weather_icon (IntlClockLocation *loc, WeatherInfo *info, gpointer data) -+{ -+ IntlClockLocationTile *tile = data; -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ GdkPixbuf *pixbuf = NULL; -+ -+ if (!info || !weather_info_is_valid (info)) -+ return; -+ -+ weather_info_get_pixbuf_mini (info, &pixbuf); -+ -+ 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); -+ intlclock_ui_update_weather_icon (priv->ui, pixbuf); -+ } -+} -+ -diff --git a/src/intlclock-location.c b/src/intlclock-location.c -index 384b2aa..911505c 100644 ---- a/src/intlclock-location.c -+++ b/src/intlclock-location.c -@@ -1,4 +1,3 @@ --#include "intlclock-location.h" - - #ifdef HAVE_CONFIG_H - #include -@@ -13,9 +12,16 @@ - #include - #include - #include -+#include - - #include - #include -+#include -+ -+#include "intlclock-location.h" -+#include "intlclock-marshallers.h" -+#include "set-timezone.h" -+#include "gweather-xml.h" - - G_DEFINE_TYPE (IntlClockLocation, intlclock_location, G_TYPE_OBJECT) - -@@ -29,17 +35,31 @@ typedef struct { - - gfloat latitude; - gfloat longitude; -+ -+ gchar *weather_code; -+ WeatherInfo *weather_info; -+ guint weather_timeout; -+ - } IntlClockLocationPrivate; - -+enum { -+ WEATHER_UPDATED, -+ LAST_SIGNAL -+}; -+ -+static guint location_signals[LAST_SIGNAL] = { 0 }; -+ - static void intlclock_location_finalize (GObject *); - static void intlclock_location_set_tz (IntlClockLocation *this); - static void intlclock_location_unset_tz (IntlClockLocation *this); -+static void setup_weather_updates (IntlClockLocation *loc); - - #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INTLCLOCK_LOCATION_TYPE, IntlClockLocationPrivate)) - - IntlClockLocation * - intlclock_location_new (const gchar *name, const gchar *timezone, -- gfloat latitude, gfloat longitude) -+ gfloat latitude, gfloat longitude, -+ const gchar *code) - { - IntlClockLocation *this; - IntlClockLocationPrivate *priv; -@@ -62,6 +82,14 @@ intlclock_location_new (const gchar *name, const gchar *timezone, - priv->latitude = latitude; - priv->longitude = longitude; - -+ if (code) -+ priv->weather_code = g_strdup (code); -+ else -+ priv->weather_code = find_weather_code (name, -+ latitude * M_PI/180.0, -+ longitude * M_PI/180.0); -+ setup_weather_updates (this); -+ - return this; - } - -@@ -193,6 +221,77 @@ guess_zone_from_tree (const gchar *localtime, IntlClockZoneTable *zones) - return ret; - } - -+static const gchar *current_zone = NULL; -+static GnomeVFSMonitorHandle *monitor = NULL; -+ -+static void -+parse_etc_sysconfig_clock (void) -+{ -+ gchar *data; -+ gsize len; -+ gchar **lines; -+ gchar *res; -+ gint i; -+ gchar *p, *q; -+ -+ lines = NULL; -+ res = NULL; -+ if (g_file_test ("/etc/sysconfig/clock", -+ G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { -+ if (!g_file_get_contents ("/etc/sysconfig/clock", -+ &data, &len, NULL)) -+ goto out; -+ -+ lines = g_strsplit (data, "\n", 0); -+ g_free (data); -+ -+ for (i = 0; lines[i] && !res; i++) { -+ if (g_str_has_prefix (lines[i], "ZONE=")) { -+ p = lines[i] + strlen ("ZONE="); -+ if (p[0] != '\"') -+ goto out; -+ p++; -+ q = strchr (p, '\"'); -+ q[0] = '\0'; -+ res = g_strdup (p); -+ } -+ } -+ } -+ -+out: -+ if (lines) -+ g_strfreev (lines); -+ -+ g_free (current_zone); -+ current_zone = res; -+} -+ -+static void -+monitor_etc_sysconfig_clock (GnomeVFSMonitorHandle *handle, -+ const gchar *monitor_uri, -+ const gchar *info_uri, -+ GnomeVFSMonitorEventType event_type, -+ gpointer user_data) -+{ -+ parse_etc_sysconfig_clock (); -+} -+ -+static const gchar * -+zone_from_etc_sysconfig_clock (void) -+{ -+ if (monitor == NULL) { -+ parse_etc_sysconfig_clock (); -+ -+ gnome_vfs_monitor_add (&monitor, -+ "/etc/sysconfig/clock", -+ GNOME_VFS_MONITOR_FILE, -+ monitor_etc_sysconfig_clock, -+ NULL); -+ } -+ -+ return current_zone; -+} -+ - static gchar * - intlclock_location_guess_zone (IntlClockZoneTable *zones) - { -@@ -200,6 +299,12 @@ intlclock_location_guess_zone (IntlClockZoneTable *zones) - const char *localtime = "/etc/localtime"; - gchar *linkfile = NULL; - GError *err = NULL; -+ gchar *zone; -+ -+ /* look for /etc/sysconfig/clock */ -+ if ((zone = zone_from_etc_sysconfig_clock ())) { -+ return g_strdup (zone); -+ } - - /* guess the current time zone by readlink() on /etc/localtime */ - linkfile = g_file_read_link (localtime, &err); -@@ -235,14 +340,14 @@ intlclock_location_new_from_env (IntlClockZoneTable *zones) - - if (zone == NULL) { - /* make a fake location with a null TZ */ -- return intlclock_location_new (_("Unknown Location"), NULL, 0.0, 0.0); -+ return intlclock_location_new (_("Unknown Location"), NULL, 0.0, 0.0, NULL); - } - - info = intlclock_zonetable_get_zone (zones, zone); - - if (info == NULL) { - /* make a fake location with the current TZ */ -- return intlclock_location_new (_("Unknown Location"), zone, 0.0, 0.0); -+ return intlclock_location_new (_("Unknown Location"), zone, 0.0, 0.0, NULL); - } - - g_free (zone); -@@ -260,7 +365,7 @@ intlclock_location_new_from_env (IntlClockZoneTable *zones) - } - - ret = intlclock_location_new (name, intlclock_zoneinfo_get_name (info), -- lat, lon); -+ lat, lon, NULL); - - g_free (name); - -@@ -274,6 +379,15 @@ intlclock_location_class_init (IntlClockLocationClass *this_class) - - g_obj_class->finalize = intlclock_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 (IntlClockLocationClass, weather_updated), -+ NULL, NULL, -+ _intlclock_marshal_VOID__POINTER, -+ G_TYPE_NONE, 1, G_TYPE_POINTER); -+ - g_type_class_add_private (this_class, sizeof (IntlClockLocationPrivate)); - } - -@@ -318,6 +432,21 @@ intlclock_location_finalize (GObject *g_obj) - 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 (intlclock_location_parent_class)->finalize (g_obj); - } - -@@ -467,3 +596,156 @@ intlclock_location_localtime (IntlClockLocation *loc, struct tm *tm) - - intlclock_location_unset_tz (loc); - } -+ -+gboolean -+intlclock_location_is_current (IntlClockLocation *loc) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ gboolean current; -+ long sys_timezone; -+ const char *zone; -+ -+ if ((zone = zone_from_etc_sysconfig_clock ())) -+ return strcmp (zone, priv->timezone) == 0; -+ -+ unsetenv ("TZ"); -+ tzset (); -+ sys_timezone = timezone; -+ -+ setenv ("TZ", priv->timezone, 1); -+ tzset(); -+ -+ current = sys_timezone == timezone; -+ -+ if (priv->sys_timezone) { -+ setenv ("TZ", priv->sys_timezone, 1); -+ } else { -+ unsetenv ("TZ"); -+ } -+ tzset(); -+ -+ return current; -+} -+ -+gboolean -+intlclock_location_make_current (IntlClockLocation *loc, GError **error) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ gchar *filename; -+ gboolean ret; -+ -+ filename = g_build_filename (SYSTEM_ZONEINFODIR, priv->timezone, NULL); -+ ret = set_system_timezone (filename, error); -+ g_free (filename); -+ -+ /* FIXME this ugly shortcut is necessary until we move the -+ * current timezone tracking to intlclock.c and emit the -+ * signal from there -+ */ -+ g_free (current_zone); -+ current_zone = g_strdup (priv->timezone); -+ -+ return ret; -+} -+ -+const gchar * -+intlclock_location_get_weather_code (IntlClockLocation *loc) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ -+ return priv->weather_code; -+} -+ -+WeatherInfo * -+intlclock_location_get_weather_info (IntlClockLocation *loc) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ -+ return priv->weather_info; -+} -+ -+static void -+weather_info_updated (WeatherInfo *info, gpointer data) -+{ -+ IntlClockLocation *loc = data; -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ -+ g_signal_emit (loc, location_signals[WEATHER_UPDATED], -+ 0, priv->weather_info); -+} -+ -+static gboolean -+update_weather_info (gpointer data) -+{ -+ IntlClockLocation *loc = data; -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ WeatherPrefs prefs = { -+ FORECAST_STATE, -+ FALSE, -+ NULL, -+ TEMP_UNIT_CENTIGRADE, -+ SPEED_UNIT_MS, -+ PRESSURE_UNIT_MB, -+ DISTANCE_UNIT_KM -+ }; -+ -+ 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 void -+setup_weather_updates (IntlClockLocation *loc) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ const gchar *code; -+ WeatherLocation *wl; -+ WeatherPrefs prefs = { -+ FORECAST_STATE, -+ FALSE, -+ NULL, -+ TEMP_UNIT_CENTIGRADE, -+ SPEED_UNIT_MS, -+ PRESSURE_UNIT_MB, -+ DISTANCE_UNIT_KM -+ }; -+ gfloat lat, lon; -+ gchar *dms; -+ -+ if (!priv->weather_code || strcmp (priv->weather_code, "-") == 0) -+ return; -+ -+ dms = rad2dms (priv->latitude, priv->longitude); -+ wl = weather_location_new (priv->name, priv->weather_code, -+ NULL, NULL, dms); -+ -+ priv->weather_info = -+ weather_info_new (wl, &prefs, weather_info_updated, loc); -+ -+ priv->weather_timeout = -+ g_timeout_add_seconds (1800, update_weather_info, loc); -+ -+ weather_location_free (wl); -+ g_free (dms); -+} -+ -diff --git a/src/intlclock-location.h b/src/intlclock-location.h -index 824ee3c..a3856e7 100644 ---- a/src/intlclock-location.h -+++ b/src/intlclock-location.h -@@ -4,6 +4,7 @@ - #include - #include - #include -+#include - - #include "intlclock-zonetable.h" - -@@ -24,12 +25,16 @@ typedef struct - typedef struct - { - GObjectClass g_object_class; -+ -+ void (* weather_updated) (IntlClockLocation *location, WeatherInfo *info); -+ - } IntlClockLocationClass; - - GType intlclock_location_get_type (void); - - IntlClockLocation *intlclock_location_new (const gchar *name, const gchar *timezone, -- gfloat latitude, gfloat longitude); -+ gfloat latitude, gfloat longitude, -+ const gchar *code); - - IntlClockLocation *intlclock_location_new_from_env (IntlClockZoneTable *zones); - -@@ -46,5 +51,11 @@ void intlclock_location_set_coords (IntlClockLocation *loc, gfloat latitude, gfl - - void intlclock_location_localtime (IntlClockLocation *loc, struct tm *tm); - -+gboolean intlclock_location_is_current (IntlClockLocation *loc); -+gboolean intlclock_location_make_current (IntlClockLocation *loc, GError **error); -+ -+const gchar *intlclock_location_get_weather_code (IntlClockLocation *loc); -+WeatherInfo *intlclock_location_get_weather_info (IntlClockLocation *loc); -+ - G_END_DECLS - #endif /* __INTLCLOCK_LOCATION_H__ */ -diff --git a/src/intlclock-map.c b/src/intlclock-map.c -index 2d72975..9ded127 100644 ---- a/src/intlclock-map.c -+++ b/src/intlclock-map.c -@@ -25,7 +25,7 @@ typedef struct { - gint height; - - GdkPixbuf *stock_map_pixbuf; -- GdkPixbuf *location_marker_pixbuf; -+ GdkPixbuf *location_marker_pixbuf[3]; - - GdkPixbuf *location_map_pixbuf; - -@@ -54,6 +54,7 @@ static void intlclock_map_display (IntlClockMap *this); - - - static void intlclock_map_locations_changed (IntlClock *clock, IntlClockMap *this); -+static void intlclock_map_blink_location (IntlClock *clock, IntlClockLocation *loc, IntlClockMap *this); - static void intlclock_map_tick (IntlClock *clock, IntlClockMap *this); - - #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INTLCLOCK_MAP_TYPE, IntlClockMapPrivate)) -@@ -69,8 +70,12 @@ intlclock_map_new (IntlClock *clock) - - priv->clock = g_object_ref (clock); - -- priv->location_marker_pixbuf = rsvg_pixbuf_from_file -- (INTLCLOCK_ICONDIR "/intlclock-map-location-marker.svg", NULL); -+ priv->location_marker_pixbuf[0] = gdk_pixbuf_new_from_file -+ (INTLCLOCK_ICONDIR "/intlclock-map-location-marker.png", NULL); -+ priv->location_marker_pixbuf[1] = gdk_pixbuf_new_from_file -+ (INTLCLOCK_ICONDIR "/intlclock-map-location-hilight.png", NULL); -+ priv->location_marker_pixbuf[2] = gdk_pixbuf_new_from_file -+ (INTLCLOCK_ICONDIR "/intlclock-map-location-current.png", NULL); - - g_signal_connect (G_OBJECT (priv->clock), "tick", - G_CALLBACK (intlclock_map_tick), this); -@@ -78,6 +83,12 @@ intlclock_map_new (IntlClock *clock) - g_signal_connect (G_OBJECT (priv->clock), "locations_changed", - G_CALLBACK (intlclock_map_locations_changed), this); - -+ g_signal_connect (G_OBJECT (priv->clock), "current_timezone_changed", -+ G_CALLBACK (intlclock_map_locations_changed), this); -+ -+ g_signal_connect (G_OBJECT (priv->clock), "blink_location", -+ G_CALLBACK (intlclock_map_blink_location), this); -+ - intlclock_map_refresh (this); - - return this; -@@ -109,13 +120,16 @@ intlclock_map_init (IntlClockMap *this) - priv->clock = NULL; - - priv->stock_map_pixbuf = NULL; -- priv->location_marker_pixbuf = NULL; -+ priv->location_marker_pixbuf[0] = NULL; -+ priv->location_marker_pixbuf[1] = NULL; -+ priv->location_marker_pixbuf[2] = NULL; - } - - static void - intlclock_map_finalize (GObject *g_obj) - { - IntlClockMapPrivate *priv = PRIVATE (g_obj); -+ int i; - - g_signal_handlers_disconnect_by_func - (priv->clock, G_CALLBACK (intlclock_map_tick), g_obj); -@@ -130,10 +144,12 @@ intlclock_map_finalize (GObject *g_obj) - priv->stock_map_pixbuf = NULL; - } - -- if (priv->location_marker_pixbuf) { -- gdk_pixbuf_unref (priv->location_marker_pixbuf); -- priv->location_marker_pixbuf = NULL; -- } -+ for (i = 0; i < 3; i++) { -+ if (priv->location_marker_pixbuf[i]) { -+ gdk_pixbuf_unref (priv->location_marker_pixbuf[i]); -+ priv->location_marker_pixbuf[i] = NULL; -+ } -+ } - - if (priv->location_map_pixbuf) { - gdk_pixbuf_unref (priv->location_map_pixbuf); -@@ -164,12 +180,13 @@ intlclock_map_refresh (IntlClockMap *this) - IntlClockMapPrivate *priv = PRIVATE (this); - GtkWidget *widget = GTK_WIDGET (this); - GtkWidget *parent = gtk_widget_get_parent (widget); -+ GtkRequisition req; - gint width; - gint height; - -- gtk_widget_size_request (widget, &(widget->requisition)); -- width = widget->requisition.width; -- height = widget->requisition.height; -+ gtk_widget_size_request (widget, &req); -+ width = req.width; -+ height = req.height; - - if (parent) { - if (widget->allocation.width != 1) { -@@ -276,10 +293,10 @@ intlclock_map_size_allocate (GtkWidget *this, GtkAllocation *allocation) - } - - static void --intlclock_map_mark (IntlClockMap *this, gfloat latitude, gfloat longitude) -+intlclock_map_mark (IntlClockMap *this, gfloat latitude, gfloat longitude, gint mark) - { - IntlClockMapPrivate *priv = PRIVATE (this); -- GdkPixbuf *marker = priv->location_marker_pixbuf; -+ GdkPixbuf *marker = priv->location_marker_pixbuf[mark]; - GdkPixbuf *partial = NULL; - - int x, y; -@@ -395,14 +412,22 @@ intlclock_map_mark (IntlClockMap *this, gfloat latitude, gfloat longitude) - } - - static void --intlclock_map_place_location (IntlClockMap *this, IntlClockLocation *loc) -+intlclock_map_place_location (IntlClockMap *this, IntlClockLocation *loc, gboolean hilight) - { - IntlClockMapPrivate *priv = PRIVATE (this); - gfloat latitude, longitude; -+ gint marker; - - intlclock_location_get_coords (loc, &latitude, &longitude); - -- intlclock_map_mark (this, latitude, longitude); -+ if (hilight) -+ marker = 1; -+ else if (intlclock_location_is_current (loc)) -+ marker = 2; -+ else -+ marker = 0; -+ -+ intlclock_map_mark (this, latitude, longitude, marker); - } - - static void -@@ -428,7 +453,7 @@ intlclock_map_place_locations (IntlClockMap *this) - while (locs) { - loc = INTLCLOCK_LOCATION (locs->data); - -- intlclock_map_place_location (this, loc); -+ intlclock_map_place_location (this, loc, FALSE); - - locs = locs->next; - } -@@ -633,16 +658,12 @@ intlclock_map_rotate (IntlClockMap *this) - static void - intlclock_map_display (IntlClockMap *this) - { -- IntlClockMapPrivate *priv = PRIVATE (this); -- - gtk_widget_queue_draw (GTK_WIDGET (this)); - } - - static void - intlclock_map_locations_changed (IntlClock *clock, IntlClockMap *this) - { -- IntlClockMapPrivate *priv = PRIVATE (this); -- - intlclock_map_place_locations (this); - - intlclock_map_render_shadow (this); -@@ -651,6 +672,49 @@ intlclock_map_locations_changed (IntlClock *clock, IntlClockMap *this) - intlclock_map_display (this); - } - -+typedef struct { -+ IntlClockMap *map; -+ IntlClockLocation *location; -+ int count; -+} BlinkData; -+ -+static gboolean -+highlight (gpointer user_data) -+{ -+ BlinkData *data = user_data; -+ -+ if (data->count == 6) { -+ g_free (data); -+ return FALSE; -+ } -+ -+ if (data->count % 2 == 0) -+ intlclock_map_place_location (data->map, data->location, TRUE); -+ else -+ intlclock_map_place_locations (data->map); -+ intlclock_map_render_shadow (data->map); -+ intlclock_map_rotate (data->map); -+ intlclock_map_display (data->map); -+ -+ data->count++; -+ -+ return TRUE; -+} -+ -+static void -+intlclock_map_blink_location (IntlClock *clock, IntlClockLocation *loc, IntlClockMap *this) -+{ -+ BlinkData *data; -+ -+ data = g_new0 (BlinkData, 1); -+ data->map = this; -+ data->location = loc; -+ -+ highlight (data); -+ -+ g_timeout_add (300, highlight, data); -+} -+ - static gboolean - intlclock_map_needs_refresh (IntlClockMap *this) - { -diff --git a/src/intlclock-marshallers.c b/src/intlclock-marshallers.c -deleted file mode 100644 -index 8f01ab8..0000000 ---- a/src/intlclock-marshallers.c -+++ /dev/null -@@ -1,51 +0,0 @@ -- --#include -- -- --#ifdef G_ENABLE_DEBUG --#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) --#define g_marshal_value_peek_char(v) g_value_get_char (v) --#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) --#define g_marshal_value_peek_int(v) g_value_get_int (v) --#define g_marshal_value_peek_uint(v) g_value_get_uint (v) --#define g_marshal_value_peek_long(v) g_value_get_long (v) --#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) --#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) --#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) --#define g_marshal_value_peek_enum(v) g_value_get_enum (v) --#define g_marshal_value_peek_flags(v) g_value_get_flags (v) --#define g_marshal_value_peek_float(v) g_value_get_float (v) --#define g_marshal_value_peek_double(v) g_value_get_double (v) --#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) --#define g_marshal_value_peek_param(v) g_value_get_param (v) --#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) --#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) --#define g_marshal_value_peek_object(v) g_value_get_object (v) --#else /* !G_ENABLE_DEBUG */ --/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. -- * Do not access GValues directly in your code. Instead, use the -- * g_value_get_*() functions -- */ --#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int --#define g_marshal_value_peek_char(v) (v)->data[0].v_int --#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint --#define g_marshal_value_peek_int(v) (v)->data[0].v_int --#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint --#define g_marshal_value_peek_long(v) (v)->data[0].v_long --#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong --#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 --#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 --#define g_marshal_value_peek_enum(v) (v)->data[0].v_long --#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong --#define g_marshal_value_peek_float(v) (v)->data[0].v_float --#define g_marshal_value_peek_double(v) (v)->data[0].v_double --#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer --#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer --#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer --#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer --#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer --#endif /* !G_ENABLE_DEBUG */ -- -- --/* VOID:VOID (intlclock-marshallers.list:1) */ -- -diff --git a/src/intlclock-marshallers.h b/src/intlclock-marshallers.h -deleted file mode 100644 -index c022a3e..0000000 ---- a/src/intlclock-marshallers.h -+++ /dev/null -@@ -1,15 +0,0 @@ -- --#ifndef ___intlclock_marshal_MARSHAL_H__ --#define ___intlclock_marshal_MARSHAL_H__ -- --#include -- --G_BEGIN_DECLS -- --/* VOID:VOID (intlclock-marshallers.list:1) */ --#define _intlclock_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID -- --G_END_DECLS -- --#endif /* ___intlclock_marshal_MARSHAL_H__ */ -- -diff --git a/src/intlclock-marshallers.list b/src/intlclock-marshallers.list -index 5b76282..e737cac 100644 ---- a/src/intlclock-marshallers.list -+++ b/src/intlclock-marshallers.list -@@ -1 +1,3 @@ - VOID:VOID -+VOID:OBJECT -+VOID:POINTER -diff --git a/src/intlclock-sunpos.c b/src/intlclock-sunpos.c -index 942617b..89d4cc1 100644 ---- a/src/intlclock-sunpos.c -+++ b/src/intlclock-sunpos.c -@@ -1,348 +1,196 @@ - /* -- * sunpos.c -- * kirk johnson -- * july 1993 -+ * Copyright (C) 2007 Red Hat, Inc. - * -- * includes revisions from Frank T. Solensky, february 1999 -+ * 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. - * -- * code for calculating the position on the earth's surface for which -- * the sun is directly overhead (adapted from _practical astronomy -- * with your calculator, third edition_, peter duffett-smith, -- * cambridge university press, 1988.) -+ * 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. - * -- * Copyright (C) 1989, 1990, 1993-1995, 1999 Kirk Lauritz Johnson -+ * 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. - * -- * Parts of the source code (as marked) are: -- * Copyright (C) 1989, 1990, 1991 by Jim Frost -- * Copyright (C) 1992 by Jamie Zawinski -- * -- * Permission to use, copy, modify and freely distribute xearth for -- * non-commercial and not-for-profit purposes is hereby granted -- * without fee, provided that both the above copyright notice and this -- * permission notice appear in all copies and in supporting -- * documentation. -- * -- * Unisys Corporation holds worldwide patent rights on the Lempel Zev -- * Welch (LZW) compression technique employed in the CompuServe GIF -- * image file format as well as in other formats. Unisys has made it -- * clear, however, that it does not require licensing or fees to be -- * paid for freely distributed, non-commercial applications (such as -- * xearth) that employ LZW/GIF technology. Those wishing further -- * information about licensing the LZW patent should contact Unisys -- * directly at (lzw_info@unisys.com) or by writing to -- * -- * Unisys Corporation -- * Welch Licensing Department -- * M/S-C1SW19 -- * P.O. Box 500 -- * Blue Bell, PA 19424 -- * -- * The author makes no representations about the suitability of this -- * software for any purpose. It is provided "as is" without express or -- * implied warranty. -- * -- * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, -- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT -- * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ * Authors: -+ * Jonathan Blandford -+ * Matthias Clasen - */ -- --#include --#include -+ - #include -+#include -+#include - --#include "intlclock-sunpos.h" -- --#define TWOPI (2*M_PI) --#define DegsToRads(x) ((x)*(TWOPI/360)) -- --/* -- * the epoch upon which these astronomical calculations are based is -- * 1990 january 0.0, 631065600 seconds since the beginning of the -- * "unix epoch" (00:00:00 GMT, Jan. 1, 1970) -- * -- * given a number of seconds since the start of the unix epoch, -- * DaysSinceEpoch() computes the number of days since the start of the -- * astronomical epoch (1990 january 0.0) -- */ -- --#define EpochStart (631065600) --#define DaysSinceEpoch(secs) (((secs)-EpochStart)*(1.0/(24*3600))) -- --/* -- * assuming the apparent orbit of the sun about the earth is circular, -- * the rate at which the orbit progresses is given by RadsPerDay -- -- * TWOPI radians per orbit divided by 365.242191 days per year: -- */ -- --#define RadsPerDay (TWOPI/365.242191) -- --/* -- * details of sun's apparent orbit at epoch 1990.0 (after -- * duffett-smith, table 6, section 46) -- * -- * Epsilon_g (ecliptic longitude at epoch 1990.0) 279.403303 degrees -- * OmegaBar_g (ecliptic longitude of perigee) 282.768422 degrees -- * Eccentricity (eccentricity of orbit) 0.016713 -+/* 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 orbit at epoch 1990.0 */ - --#define Epsilon_g (DegsToRads(279.403303)) --#define OmegaBar_g (DegsToRads(282.768422)) --#define Eccentricity (0.016713) -+#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 perigree */ -+#define ECCENTRICITY 0.016713 /* eccentricity of orbit */ -+#define R_0 149598500 /* km */ /* semi-major access */ -+#define THETA_0 0.533128 /* degrees */ /* angular diameter at r = r_0 */ -+#define MEAN_OBLIQUITY 23.440592 /* degrees */ /* mean obliquity of earths axis at epoch 1990.0 */ - --/* -- * MeanObliquity gives the mean obliquity of the earth's axis at epoch -- * 1990.0 (computed as 23.440592 degrees according to the method given -- * in duffett-smith, section 27) -- */ --#define MeanObliquity (23.440592*(TWOPI/360)) -+#define NORMALIZE(x) \ -+ while (x>360) x-=360; while (x<0) x+= 360; - --/* -- * Lunar parameters, epoch January 0, 1990.0 -- */ --#define MoonMeanLongitude DegsToRads(318.351648) --#define MoonMeanLongitudePerigee DegsToRads( 36.340410) --#define MoonMeanLongitudeNode DegsToRads(318.510107) --#define MoonInclination DegsToRads( 5.145396) -+#define DEG_TO_RADS(x) \ -+ (x * G_PI/180.0) - --#define SideralMonth (27.3217) -+#define RADS_TO_DEG(x) \ -+ (x * 180.0/G_PI) - --/* -- * Force an angular value into the range [-PI, +PI] -+/* Calculate number of days since 4713BC. - */ --#define Normalize(x) \ -- do { \ -- if ((x) < -M_PI) \ -- do (x) += TWOPI; while ((x) < -M_PI); \ -- else if ((x) > M_PI) \ -- do (x) -= TWOPI; while ((x) > M_PI); \ -- } while (0) -- --static double solve_keplers_equation (double); --static double mean_sun (double); --static double sun_ecliptic_longitude (time_t); --static void ecliptic_to_equatorial (double, double, double *, double *); --static double julian_date (int, int, int); --static double GST (time_t); -- --/* -- * solve Kepler's equation via Newton's method -- * (after duffett-smith, section 47) -- */ --static double solve_keplers_equation(M) -- double M; -+static gdouble -+unix_time_to_julian_date (gint unix_time) - { -- double E; -- double delta; -- -- E = M; -- while (1) -- { -- delta = E - Eccentricity*sin(E) - M; -- if (fabs(delta) <= 1e-10) break; -- E -= delta / (1 - Eccentricity*cos(E)); -- } -- -- return E; -+ 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 */ - --/* -- * Calculate the position of the mean sun: where the sun would -- * be if the earth's orbit were circular instead of ellipictal. -- */ -+#define ERROR_ACCURACY 1e-6 /* radians */ - --static double mean_sun (D) -- double D; /* days since ephemeris epoch */ -+static gdouble -+solve_keplers_equation (gdouble e, -+ gdouble M) - { -- double N, M; -+ gdouble d, E; - -- N = RadsPerDay * D; -- N = fmod(N, TWOPI); -- if (N < 0) N += TWOPI; -+ /* 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; -+ } - -- M = N + Epsilon_g - OmegaBar_g; -- if (M < 0) M += TWOPI; -- return M; -+ return E; - } - --/* -- * compute ecliptic longitude of sun (in radians) -- * (after duffett-smith, section 47) -- */ --static double sun_ecliptic_longitude(ssue) -- time_t ssue; /* seconds since unix epoch */ -+ /* convert the ecliptic longitude to right ascension and declination. Section 27. */ -+static void -+ecliptic_to_equatorial (gdouble lambda, -+ gdouble beta, -+ gdouble *ra, -+ gdouble *dec) - { -- double D; -- double M_sun, E; -- double v; -+ gdouble cos_mo; -+ gdouble sin_mo; - -- D = DaysSinceEpoch(ssue); -- M_sun = mean_sun(D); -+ g_assert (ra != NULL); -+ g_assert (dec != NULL); - -- E = solve_keplers_equation(M_sun); -- v = 2 * atan(sqrt((1+Eccentricity)/(1-Eccentricity)) * tan(E/2)); -+ sin_mo = sin (DEG_TO_RADS (MEAN_OBLIQUITY)); -+ cos_mo = cos (DEG_TO_RADS (MEAN_OBLIQUITY)); - -- return (v + OmegaBar_g); -+ *ra = atan2 (sin (lambda) * cos_mo - tan (beta) * sin_mo, cos (lambda)); -+ *dec = asin (sin (beta) * cos_mo + cos (beta) * sin_mo * sin (lambda)); - } - -- --/* -- * convert from ecliptic to equatorial coordinates -- * (after duffett-smith, section 27) -- */ --static void ecliptic_to_equatorial(lambda, beta, alpha, delta) -- double lambda; /* ecliptic longitude */ -- double beta; /* ecliptic latitude */ -- double *alpha; /* (return) right ascension */ -- double *delta; /* (return) declination */ -+/* calculate GST. Section 12 */ -+static gdouble -+greenwich_sidereal_time (gdouble unix_time) - { -- double sin_e, cos_e; -+ gdouble u, JD, T, T0, UT; - -- sin_e = sin(MeanObliquity); -- cos_e = cos(MeanObliquity); -+ 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); - -- *alpha = atan2(sin(lambda)*cos_e - tan(beta)*sin_e, cos(lambda)); -- *delta = asin(sin(beta)*cos_e + cos(beta)*sin_e*sin(lambda)); -+ return T0; - } - -- --/* -- * computing julian dates (assuming gregorian calendar, thus this is -- * only valid for dates of 1582 oct 15 or later) -- * (after duffett-smith, section 4) -- */ --static double julian_date(y, m, d) -- int y; /* year (e.g. 19xx) */ -- int m; /* month (jan=1, feb=2, ...) */ -- int d; /* day of month */ -+/* Calculate the position of the sun at a given time. pages 89-91 */ -+void -+sun_position (gint unix_time, gdouble *lat, gdouble *lon) - { -- int A, B, C, D; -- double JD; -+ gdouble jd, D, N, M, E, x, v, lambda; -+ gdouble ra, dec; -+ jd = unix_time_to_julian_date (unix_time); - -- /* lazy test to ensure gregorian calendar */ -- assert(y >= 1583); -+ /* Calculate number of days since the epoch */ -+ D = jd - EPOCH; - -- if ((m == 1) || (m == 2)) -- { -- y -= 1; -- m += 12; -- } -+ N = D*360/365.242191; - -- A = y / 100; -- B = 2 - A + (A / 4); -- C = 365.25 * y; -- D = 30.6001 * (m + 1); -+ /* normalize to 0 - 360 degrees */ -+ NORMALIZE (N); - -- JD = B + C + D + d + 1720994.5; -+ /* Step 4: */ -+ M = N + EPSILON_G - MU_G; -+ NORMALIZE (M); - -- return JD; --} -- -- --/* -- * compute greenwich mean sidereal time (GST) corresponding to a given -- * number of seconds since the unix epoch -- * (after duffett-smith, section 12) -- */ --static double GST(ssue) -- time_t ssue; /* seconds since unix epoch */ --{ -- double JD; -- double T, T0; -- double UT; -- struct tm *tm; -+ /* Step 5: convert to radians */ -+ M = DEG_TO_RADS (M); - -- tm = gmtime(&ssue); -+ /* Step 6: */ -+ E = solve_keplers_equation (ECCENTRICITY, M); - -- JD = julian_date(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday); -- T = (JD - 2451545) / 36525; -+ /* Step 7: */ -+ x = sqrt ((1 + ECCENTRICITY)/(1 - ECCENTRICITY)) * tan (E/2); - -- T0 = ((T + 2.5862e-5) * T + 2400.051336) * T + 6.697374558; -+ /* Step 8, 9 */ -+ v = 2 * RADS_TO_DEG (atan (x)); -+ NORMALIZE (v); - -- T0 = fmod(T0, 24.0); -- if (T0 < 0) T0 += 24; -+ /* Step 10 */ -+ lambda = v + MU_G; -+ NORMALIZE (lambda); - -- UT = tm->tm_hour + (tm->tm_min + tm->tm_sec / 60.0) / 60.0; -+ /* convert the ecliptic longitude to right ascension and declination */ -+ ecliptic_to_equatorial (DEG_TO_RADS (lambda), 0.0, &ra, &dec); - -- T0 += UT * 1.002737909; -- T0 = fmod(T0, 24.0); -- if (T0 < 0) T0 += 24; -+ ra = ra - (G_PI/12) * greenwich_sidereal_time (unix_time); -+ ra = RADS_TO_DEG (ra); -+ dec = RADS_TO_DEG (dec); -+ NORMALIZE (ra); -+ NORMALIZE (dec); - -- return T0; -+ *lat = dec; -+ *lon = ra; - } - - --/* -- * given a particular time (expressed in seconds since the unix -- * epoch), compute position on the earth (lat, lon) such that sun is -- * directly overhead. -- */ --void sun_position(ssue, lat, lon) -- time_t ssue; /* seconds since unix epoch */ -- double *lat; /* (return) latitude */ -- double *lon; /* (return) longitude */ -+#if 0 -+int -+main (int argc, char *argv[]) - { -- double lambda; -- double alpha, delta; -- double tmp; -+ gint i; -+ gint now; -+ GTimeVal timeval; -+ gdouble lat, lon; - -- lambda = sun_ecliptic_longitude(ssue); -- ecliptic_to_equatorial(lambda, 0.0, &alpha, &delta); -+ gtk_init (&argc, &argv); - -- tmp = alpha - (TWOPI/24)*GST(ssue); -- Normalize(tmp); -- *lon = tmp * (360/TWOPI); -- *lat = delta * (360/TWOPI); --} -+ 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); -+ } - --/* -- * given a particular time (expressed in seconds since the unix -- * epoch), compute position on the earth (lat, lon) such that the -- * moon is directly overhead. -- * -- * Based on duffett-smith **2nd ed** section 61; combines some steps -- * into single expressions to reduce the number of extra variables. -- */ --void moon_position(ssue, lat, lon) -- time_t ssue; /* seconds since unix epoch */ -- double *lat; /* (return) latitude */ -- double *lon; /* (return) longitude */ --{ -- double lambda, beta; -- double D, L, Ms, Mm, N, Ev, Ae, Ec, alpha, delta; -- -- D = DaysSinceEpoch(ssue); -- lambda = sun_ecliptic_longitude(ssue); -- Ms = mean_sun(D); -- -- L = fmod(D/SideralMonth, 1.0)*TWOPI + MoonMeanLongitude; -- Normalize(L); -- Mm = L - DegsToRads(0.1114041*D) - MoonMeanLongitudePerigee; -- Normalize(Mm); -- N = MoonMeanLongitudeNode - DegsToRads(0.0529539*D); -- Normalize(N); -- Ev = DegsToRads(1.2739) * sin(2.0*(L-lambda)-Mm); -- Ae = DegsToRads(0.1858) * sin(Ms); -- Mm += Ev - Ae - DegsToRads(0.37)*sin(Ms); -- Ec = DegsToRads(6.2886) * sin(Mm); -- L += Ev + Ec - Ae + DegsToRads(0.214) * sin(2.0*Mm); -- L += DegsToRads(0.6583) * sin(2.0*(L-lambda)); -- N -= DegsToRads(0.16) * sin(Ms); -- -- L -= N; -- lambda =(fabs(cos(L)) < 1e-12) ? -- (N + sin(L) * cos(MoonInclination) * M_PI/2) : -- (N + atan2(sin(L) * cos(MoonInclination), cos(L))); -- Normalize(lambda); -- beta = asin(sin(L) * sin(MoonInclination)); -- ecliptic_to_equatorial(lambda, beta, &alpha, &delta); -- alpha -= (TWOPI/24)*GST(ssue); -- Normalize(alpha); -- *lon = alpha * (360/TWOPI); -- *lat = delta * (360/TWOPI); -+ return 0; - } -+ -+#endif -diff --git a/src/intlclock-ui.c b/src/intlclock-ui.c -index f51e4de..a856aef 100644 ---- a/src/intlclock-ui.c -+++ b/src/intlclock-ui.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -26,18 +27,17 @@ - #include "intlclock-map.h" - #include "intlclock-zoneinfo.h" - #include "intlclock-zonetable.h" -+#include "set-timezone.h" - - G_DEFINE_TYPE (IntlClockUI, intlclock_ui, G_TYPE_OBJECT) - - /* GConf keys for compatibility with the older GNOME clock */ --#define N_GCONF_PREFS 7 -+#define N_GCONF_PREFS 5 - static const char *KEY_CITIES = "cities"; - static const char *KEY_FORMAT = "format"; - static const char *KEY_SHOW_SECONDS = "show_seconds"; - static const char *KEY_SHOW_DATE = "show_date"; - static const char *KEY_SHOW_WEEK = "show_week_numbers"; --static const char *KEY_SHOW_LOCATIONS = "show_locations"; --static const char *KEY_SHOW_MAP = "show_map"; - - /* Needs to match the indices in the combo */ - typedef enum { -@@ -78,12 +78,14 @@ typedef struct { - GtkWidget *panel_box; - GtkWidget *panel_button; - GtkWidget *panel_label; -+ GtkWidget *panel_weather_icon; - - GtkTooltips *panel_tips; - - GtkWidget *panel_button_popup; - - GtkWidget *clock_vbox; -+ GtkSizeGroup *clock_group; - - GtkWidget *main_section; - GtkWidget *clock_calendar; -@@ -97,12 +99,20 @@ typedef struct { - - GtkListStore *cities_store; - -- gboolean show_locations; -- gboolean show_map; -- - GtkWidget *prefs_window; - GtkTreeView *prefs_locations; - -+ GtkWidget *prefs_location_add_button; -+ GtkWidget *prefs_location_edit_button; -+ GtkWidget *prefs_location_remove_button; -+ -+ GtkWidget *hours_spin; -+ GtkWidget *minutes_spin; -+ GtkWidget *seconds_spin; -+ GtkWidget *calendar; -+ GtkWidget *current_time_label; -+ GtkWidget *set_time_button; -+ - gboolean format_12hr; - gboolean format_show_seconds; - gboolean format_show_date; -@@ -118,9 +128,6 @@ static gboolean update_panel_label (gpointer this); - static void setup_gconf (IntlClockUI *this); - static void load_gconf_settings (IntlClockUI *this); - --static void bonobo_run_time_configuration (BonoboUIComponent *uic, -- IntlClockUI *this, -- const gchar *verbname); - static void bonobo_display_properties_dialog (BonoboUIComponent *uic, - IntlClockUI *this, - const gchar *verbname); -@@ -141,9 +148,8 @@ static void position_popup_window (IntlClockUI *this, - GtkWindow *window, - GtkWidget *origin); - -+static void display_prefs_window (IntlClockUI *this, gboolean locations); - static void display_prefs_window_cb (GtkButton *button, gpointer this); --static void run_time_configuration (IntlClockUI *this); --static void run_time_configuration_cb (GtkButton *button, gpointer this); - static void run_prefs_locations_add (GtkButton *button, gpointer this); - static void run_prefs_locations_edit (GtkButton *button, gpointer this); - static void run_prefs_locations_remove (GtkButton *button, gpointer this); -@@ -162,7 +168,6 @@ static void zone_combo_changed (GtkComboBox *widget, gpointer this); - - static const BonoboUIVerb intlclock_menu_verbs [] = { - BONOBO_UI_UNSAFE_VERB ("IntlClockPreferences", bonobo_display_properties_dialog), -- BONOBO_UI_UNSAFE_VERB ("IntlClockConfig", bonobo_run_time_configuration), - BONOBO_UI_VERB_END - }; - -@@ -206,7 +211,9 @@ intlclock_ui_reset_timeout (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); - -- if (GTK_WIDGET_VISIBLE (priv->events_window) || priv->format_show_seconds) { -+ if (GTK_WIDGET_VISIBLE (priv->events_window) || -+ (priv->prefs_window && GTK_WIDGET_VISIBLE (priv->prefs_window)) || -+ priv->format_show_seconds) { - intlclock_set_tick_timeout (INTLCLOCK (priv->clock), 1); - } else { - intlclock_set_tick_timeout (INTLCLOCK (priv->clock), 60); -@@ -435,22 +442,20 @@ intlclock_window_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer u - - /* draw map pane background */ - -- if (priv->show_map) { -- cairo_rectangle ( -- cr, -- priv->map_section->allocation.x + 0.5, -- priv->map_section->allocation.y + 0.5, -- priv->map_section->allocation.width - 1, -- priv->map_section->allocation.height - 1); -- -- cairo_set_source_rgb ( -- cr, -- widget->style->bg [GTK_STATE_NORMAL].red / 65535.0, -- widget->style->bg [GTK_STATE_NORMAL].green / 65535.0, -- widget->style->bg [GTK_STATE_NORMAL].blue / 65535.0); -- -- cairo_fill (cr); -- } -+ cairo_rectangle ( -+ cr, -+ priv->map_section->allocation.x + 0.5, -+ priv->map_section->allocation.y + 0.5, -+ priv->map_section->allocation.width - 1, -+ priv->map_section->allocation.height - 1); -+ -+ cairo_set_source_rgb ( -+ cr, -+ widget->style->bg [GTK_STATE_NORMAL].red / 65535.0, -+ widget->style->bg [GTK_STATE_NORMAL].green / 65535.0, -+ widget->style->bg [GTK_STATE_NORMAL].blue / 65535.0); -+ -+ cairo_fill (cr); - - /* draw internal window outline */ - -@@ -469,47 +474,43 @@ intlclock_window_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer u - - /* draw map/cities pane separator */ - -- if (priv->show_map) { -- cairo_move_to ( -- cr, -- priv->map_section->allocation.x + 0.5, -- priv->map_section->allocation.y + priv->map_section->allocation.height - 0.5); -+ cairo_move_to ( -+ cr, -+ priv->map_section->allocation.x + 0.5, -+ priv->map_section->allocation.y + priv->map_section->allocation.height - 0.5); - -- cairo_line_to ( -- cr, -- priv->map_section->allocation.x + priv->map_section->allocation.width - 0.5, -- priv->map_section->allocation.y + priv->map_section->allocation.height - 0.5); -+ cairo_line_to ( -+ cr, -+ priv->map_section->allocation.x + priv->map_section->allocation.width - 0.5, -+ priv->map_section->allocation.y + priv->map_section->allocation.height - 0.5); - -- cairo_set_source_rgb ( -- cr, -- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); -+ cairo_set_source_rgb ( -+ cr, -+ widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, -+ widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, -+ widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); - -- cairo_stroke (cr); -- } -+ cairo_stroke (cr); - - /* draw cities/main pane separator */ - -- if (priv->show_locations) { -- cairo_move_to ( -- cr, -- priv->cities_section->allocation.x + 0.5, -- priv->cities_section->allocation.y + priv->cities_section->allocation.height - 0.5); -+ cairo_move_to ( -+ cr, -+ priv->cities_section->allocation.x + 0.5, -+ priv->cities_section->allocation.y + priv->cities_section->allocation.height - 0.5); - -- cairo_line_to ( -- cr, -- priv->cities_section->allocation.x + priv->cities_section->allocation.width - 0.5, -- priv->cities_section->allocation.y + priv->cities_section->allocation.height - 0.5); -+ cairo_line_to ( -+ cr, -+ priv->cities_section->allocation.x + priv->cities_section->allocation.width - 0.5, -+ priv->cities_section->allocation.y + priv->cities_section->allocation.height - 0.5); - -- cairo_set_source_rgb ( -- cr, -- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); -+ cairo_set_source_rgb ( -+ cr, -+ widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, -+ widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, -+ widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); - -- cairo_stroke (cr); -- } -+ cairo_stroke (cr); - - cairo_destroy (cr); - -@@ -532,7 +533,6 @@ intlclock_ui_locations_changed (IntlClock *clock, IntlClockUI *this) - IntlClockUIPrivate *priv = PRIVATE (this); - - create_cities_section (this); -- intlclock_map_refresh (INTLCLOCK_MAP (priv->map_widget)); - } - - static gboolean -@@ -550,12 +550,20 @@ update_panel_label (gpointer this) - time (&now_t); - localtime_r (&now_t, &now); - -+ if (priv->current_time_label && -+ GTK_WIDGET_VISIBLE (priv->current_time_label)) { -+ date = intlclock_format_time (priv->clock, &now, -+ FALSE, FALSE, TRUE, -+ FALSE, FALSE, NULL, TRUE); -+ gtk_label_set_markup (GTK_LABEL (priv->current_time_label), date); -+ g_free (date); -+ } -+ - date = intlclock_format_time (priv->clock, &now, - priv->format_show_date, - priv->format_12hr, - priv->format_show_seconds, - FALSE, priv->format_show_date, NULL, TRUE); -- - gtk_label_set_markup (GTK_LABEL (priv->panel_label), date); - g_free (date); - -@@ -583,6 +591,7 @@ create_panel_buttons (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); - PanelAppletOrient orient; -+ GtkWidget *box; - - orient = panel_applet_get_orient (priv->panel_applet); - -@@ -590,13 +599,16 @@ create_panel_buttons (IntlClockUI *this) - case PANEL_APPLET_ORIENT_UP: - case PANEL_APPLET_ORIENT_DOWN: - priv->panel_box = gtk_hbox_new (FALSE, 0); -+ box = gtk_hbox_new (FALSE, 6); - break; - case PANEL_APPLET_ORIENT_RIGHT: - case PANEL_APPLET_ORIENT_LEFT: - priv->panel_box = gtk_vbox_new (FALSE, 0); -+ box = gtk_vbox_new (FALSE, 6); - break; - } - priv->panel_label = gtk_label_new (NULL); -+ priv->panel_weather_icon = gtk_image_new (); - priv->panel_button = gtk_toggle_button_new (); - priv->panel_tips = gtk_tooltips_new (); - -@@ -626,8 +638,9 @@ create_panel_buttons (IntlClockUI *this) - gtk_button_set_relief (GTK_BUTTON (priv->panel_button), - GTK_RELIEF_NONE); - -- gtk_container_add (GTK_CONTAINER (priv->panel_button), -- priv->panel_label); -+ gtk_container_add (GTK_CONTAINER (priv->panel_button), box); -+ gtk_container_add (GTK_CONTAINER (box), priv->panel_weather_icon); -+ gtk_container_add (GTK_CONTAINER (box), priv->panel_label); - - g_signal_connect ( - G_OBJECT (priv->panel_button), "clicked", -@@ -655,12 +668,13 @@ create_panel_buttons (IntlClockUI *this) - ); - - gtk_widget_show (priv->panel_label); -+ gtk_widget_show (priv->panel_weather_icon); -+ gtk_widget_show (box); - - gtk_box_pack_start (GTK_BOX (priv->panel_box), priv->panel_button, - FALSE, FALSE, 0); - -- gtk_container_add (GTK_CONTAINER (priv->panel_applet), -- priv->panel_box); -+ gtk_container_add (GTK_CONTAINER (priv->panel_applet), priv->panel_box); - - gtk_widget_show_all (priv->panel_box); - } -@@ -671,10 +685,16 @@ intlclock_ui_change_orient (PanelApplet *applet, - IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); -- -- if (GTK_IS_WIDGET (priv->panel_box)) -- gtk_widget_destroy (priv->panel_box); -+ GdkPixbuf *pixbuf = NULL; -+ -+ if (GTK_IS_WIDGET (priv->panel_box)) { -+ pixbuf = g_object_ref (gtk_image_get_pixbuf (GTK_IMAGE (priv->panel_weather_icon))); -+ gtk_widget_destroy (priv->panel_box); -+ } - create_panel_buttons (this); -+ intlclock_ui_update_weather_icon (this, pixbuf); -+ if (pixbuf) -+ g_object_unref (pixbuf); - } - - static void -@@ -714,7 +734,7 @@ create_events_window (IntlClockUI *this) - IntlClockUIPrivate *priv = PRIVATE (this); - - priv->events_window = -- GTK_WIDGET (intlclock_events_popup_new (priv->clock, priv->panel_applet)); -+ GTK_WIDGET (intlclock_events_popup_new (priv->clock, priv->panel_applet, this)); - - g_signal_connect (G_OBJECT (priv->events_window), "size-allocate", - G_CALLBACK (intlclock_events_window_size_allocate_cb), this); -@@ -723,17 +743,35 @@ create_events_window (IntlClockUI *this) - } - - static void -+add_to_group (GtkWidget *child, gpointer data) -+{ -+ GtkSizeGroup *group = data; -+ -+ gtk_size_group_add_widget (group, child); -+} -+ -+static void - create_clock_window (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); - GtkSettings *settings; - GtkStyle *style; -+ GtkWidget *clock_container; - -- priv->clock_vbox = intlclock_events_popup_get_clock_container -+ clock_container = intlclock_events_popup_get_clock_container - (INTLCLOCK_EVENTS_POPUP (priv->events_window)); -- gtk_widget_show (priv->clock_vbox); --} -+ gtk_widget_show (clock_container); - -+ priv->clock_vbox = gtk_vbox_new (FALSE, 6); -+ gtk_container_add (GTK_CONTAINER (clock_container), priv->clock_vbox); -+ -+ priv->clock_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); -+ gtk_size_group_set_ignore_hidden (priv->clock_group, FALSE); -+ -+ gtk_container_foreach (GTK_CONTAINER (clock_container), -+ (GtkCallback)add_to_group, -+ priv->clock_group); -+} - static void - create_main_section (IntlClockUI *this) - { -@@ -750,7 +788,6 @@ create_main_section (IntlClockUI *this) - MAIN_SECTION_PADDING); - gtk_box_pack_end (GTK_BOX (priv->clock_vbox), - priv->main_section, FALSE, FALSE, 0); -- - } else { - gtk_container_foreach (GTK_CONTAINER (priv->main_section), - (GtkCallback)gtk_widget_destroy, -@@ -824,7 +861,7 @@ create_cities_section (IntlClockUI *this) - IntlClockUIPrivate *priv = PRIVATE (this); - GList *node; - IntlClockLocationTile *city; -- GtkWidget *header, *subheader, *image;; -+ GtkWidget *header, *subheader, *image; - GList *cities; - - if (priv->cities_section) { -@@ -832,12 +869,8 @@ create_cities_section (IntlClockUI *this) - priv->cities_section = NULL; - } - -- if (!priv->show_locations) { -- return; -- } -- - priv->cities_section = gtk_vbox_new (FALSE, 6); -- gtk_container_set_border_width (GTK_CONTAINER (priv->cities_section), 8); -+ gtk_container_set_border_width (GTK_CONTAINER (priv->cities_section), 0); - - cities = intlclock_get_locations (priv->clock); - if (g_list_length (cities) == 0) { -@@ -884,10 +917,6 @@ create_map_section (IntlClockUI *this) - priv->map_widget = NULL; - } - -- if (!priv->show_map) { -- return; -- } -- - map = intlclock_map_new (priv->clock); - - priv->map_section = gtk_alignment_new (0, 0, 1, 1); -@@ -895,11 +924,10 @@ create_map_section (IntlClockUI *this) - - gtk_container_add (GTK_CONTAINER (priv->map_section), priv->map_widget); - -- gtk_box_pack_start (GTK_BOX (priv->clock_vbox), -- priv->map_section, FALSE, FALSE, 0); -- - gtk_alignment_set_padding (GTK_ALIGNMENT (priv->map_section), - 1, 1, 1, 1); -+ gtk_box_pack_start (GTK_BOX (priv->clock_vbox), -+ priv->map_section, FALSE, FALSE, 0); - - gtk_widget_show (priv->map_widget); - gtk_widget_show (priv->map_section); -@@ -959,6 +987,8 @@ intlclock_prefs_hide (GtkWidget *widget, IntlClockUI *this) - - gtk_tree_selection_unselect_all - (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree))); -+ -+ intlclock_ui_reset_timeout (this); - } - - static gboolean -@@ -1057,28 +1087,6 @@ set_seconds_check_cb (GtkWidget *widget, IntlClockUI *this) - } - - static void --set_locations_check_cb (GtkWidget *widget, IntlClockUI *this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- panel_applet_gconf_set_bool (PANEL_APPLET (priv->panel_applet), -- KEY_SHOW_LOCATIONS, -- GTK_TOGGLE_BUTTON (widget)->active, -- NULL); --} -- --static void --set_map_check_cb (GtkWidget *widget, IntlClockUI *this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- panel_applet_gconf_set_bool (PANEL_APPLET (priv->panel_applet), -- KEY_SHOW_MAP, -- GTK_TOGGLE_BUTTON (widget)->active, -- NULL); --} -- --static void - fill_prefs_window (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); -@@ -1087,6 +1095,9 @@ fill_prefs_window (IntlClockUI *this) - GtkCellRenderer *renderer; - GtkTreeViewColumn *col; - -+ time_t now_t; -+ struct tm now; -+ - /* Set the 12 hour / 24 hour widget */ - widget = glade_xml_get_widget (priv->glade_xml, "12hr_radio"); - g_signal_connect (widget, "toggled", -@@ -1109,18 +1120,6 @@ fill_prefs_window (IntlClockUI *this) - g_signal_connect (widget, "toggled", G_CALLBACK (set_seconds_check_cb), - this); - -- /* Set the "Show Locations" checkbox */ -- widget = glade_xml_get_widget (priv->glade_xml, "show_locations_check"); -- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), priv->show_locations); -- g_signal_connect (widget, "toggled", G_CALLBACK (set_locations_check_cb), -- this); -- -- /* Set the "Show Map" checkbox */ -- widget = glade_xml_get_widget (priv->glade_xml, "show_map_check"); -- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), priv->show_map); -- g_signal_connect (widget, "toggled", G_CALLBACK (set_map_check_cb), -- this); -- - /* Fill the Cities list */ - widget = glade_xml_get_widget (priv->glade_xml, "cities_list"); - -@@ -1136,6 +1135,15 @@ fill_prefs_window (IntlClockUI *this) - - gtk_tree_view_set_model (GTK_TREE_VIEW (widget), - GTK_TREE_MODEL (priv->cities_store)); -+ -+ /* Fill the time settings */ -+ tzset (); -+ time (&now_t); -+ localtime_r (&now_t, &now); -+ -+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->seconds_spin), now.tm_sec); -+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->minutes_spin), now.tm_min); -+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->hours_spin), now.tm_hour); - } - - static gint -@@ -1150,19 +1158,139 @@ sort_zoneinfo_by_l10n_name (gconstpointer a, gconstpointer b) - return strcmp (name_a, name_b); - } - -+static void -+intlclock_prefs_locations_changed (GtkTreeSelection *selection, -+ IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ gint n; -+ -+ n = gtk_tree_selection_count_selected_rows (selection); -+ gtk_widget_set_sensitive (priv->prefs_location_edit_button, n > 0); -+ gtk_widget_set_sensitive (priv->prefs_location_remove_button, n > 0); -+} -+ -+static void -+wrap_cb (GtkSpinButton *spin, -+ IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ gdouble value; -+ gdouble min, max; -+ GtkWidget *next; -+ 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 *)priv->seconds_spin) -+ gtk_spin_button_spin (GTK_SPIN_BUTTON (priv->minutes_spin), -+ direction, 1.0); -+ else if (spin == (GtkSpinButton *)priv->minutes_spin) -+ gtk_spin_button_spin (GTK_SPIN_BUTTON (priv->hours_spin), -+ direction, 1.0); -+ else { -+ guint year, month, day; -+ GDate *date; -+ -+ gtk_calendar_get_date (GTK_CALENDAR (priv->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 (priv->calendar), -+ month, year); -+ gtk_calendar_select_day (GTK_CALENDAR (priv->calendar), -+ day); -+ -+ g_date_free (date); -+ } -+} -+ -+static void -+update_set_time_button (IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ gint can_set; -+ GtkWidget *box; -+ -+ can_set = can_set_system_time (); -+ box = glade_xml_get_widget (priv->glade_xml, "time_settings_box"); -+ -+ gtk_widget_set_sensitive (box, can_set != 0); -+ gtk_button_set_label (GTK_BUTTON (priv->set_time_button), -+ can_set == 1 ? -+ _("Set System Time...") : -+ _("Set System Time")); -+} -+ -+static void -+set_time_callback (IntlClockUI *this, GError *error) -+{ -+ GtkWidget *dialog; -+ -+ if (error) { -+ dialog = gtk_message_dialog_new (NULL, -+ 0, -+ GTK_MESSAGE_ERROR, -+ GTK_BUTTONS_OK, -+ _("Failed to set the system time")); -+ -+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), 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 (this); -+} -+ - static void --display_prefs_window (IntlClockUI *this) -+set_time (GtkWidget *widget, IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ struct tm t; -+ gint64 time; -+ -+ t.tm_sec = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->seconds_spin)); -+ t.tm_min = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->minutes_spin)); -+ t.tm_hour = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->hours_spin)); -+ gtk_calendar_get_date (GTK_CALENDAR (priv->calendar), -+ &t.tm_year, &t.tm_mon, &t.tm_mday); -+ t.tm_year -= 1900; -+ -+ time = mktime (&t); -+ -+ set_system_time_async (time, (GFunc)set_time_callback, this, NULL); -+} -+ -+static void -+display_prefs_window (IntlClockUI *this, gboolean locations) - { - IntlClockUIPrivate *priv = PRIVATE (this); - GtkWidget *edit_window; - GtkWidget *prefs_window; - GtkWidget *prefs_close_button; -- GtkWidget *prefs_settings_button; - GtkWidget *edit_cancel_button; - GtkWidget *edit_ok_button; - GtkWidget *zone_combo; -- -- GtkWidget *tmp_button; -+ GtkTreeSelection *selection; - - if (!priv->prefs_window) { - priv->prefs_window = -@@ -1170,38 +1298,36 @@ display_prefs_window (IntlClockUI *this) - - prefs_close_button = - glade_xml_get_widget (priv->glade_xml, "prefs-close-button"); -- -- prefs_settings_button = -- glade_xml_get_widget (priv->glade_xml, "prefs-time-settings-button"); -- - priv->prefs_locations = - GTK_TREE_VIEW (glade_xml_get_widget (priv->glade_xml, "cities_list")); - -+ selection = gtk_tree_view_get_selection (priv->prefs_locations); -+ g_signal_connect (G_OBJECT (selection), "changed", -+ G_CALLBACK (intlclock_prefs_locations_changed), this); -+ -+ - g_signal_connect (G_OBJECT (priv->prefs_window), "delete_event", - G_CALLBACK (intlclock_prefs_hide_event), this); - - g_signal_connect (G_OBJECT (prefs_close_button), "clicked", - G_CALLBACK (intlclock_prefs_hide), this); - -- g_signal_connect (G_OBJECT (prefs_settings_button), "clicked", -- G_CALLBACK (run_time_configuration_cb), this); -- -- tmp_button = -+ priv->prefs_location_remove_button = - glade_xml_get_widget (priv->glade_xml, "prefs-locations-remove-button"); - -- g_signal_connect (G_OBJECT (tmp_button), "clicked", -+ g_signal_connect (G_OBJECT (priv->prefs_location_remove_button), "clicked", - G_CALLBACK (run_prefs_locations_remove), this); -- -- tmp_button = -+ -+ priv->prefs_location_add_button = - glade_xml_get_widget (priv->glade_xml, "prefs-locations-add-button"); - -- g_signal_connect (G_OBJECT (tmp_button), "clicked", -+ g_signal_connect (G_OBJECT (priv->prefs_location_add_button), "clicked", - G_CALLBACK (run_prefs_locations_add), this); - -- tmp_button = -+ priv->prefs_location_edit_button = - glade_xml_get_widget (priv->glade_xml, "prefs-locations-edit-button"); - -- g_signal_connect (G_OBJECT (tmp_button), "clicked", -+ g_signal_connect (G_OBJECT (priv->prefs_location_edit_button), "clicked", - G_CALLBACK (run_prefs_locations_edit), this); - - edit_window = glade_xml_get_widget (priv->glade_xml, -@@ -1234,11 +1360,48 @@ display_prefs_window (IntlClockUI *this) - item. */ - gtk_combo_box_remove_text (GTK_COMBO_BOX (zone_combo), 0); - -+ /* Set up the time setting section */ -+ priv->current_time_label = glade_xml_get_widget (priv->glade_xml, "current_time_label"); -+ priv->set_time_button = glade_xml_get_widget (priv->glade_xml, "set_time_button"); -+ g_signal_connect (priv->set_time_button, "clicked", G_CALLBACK (set_time), this); -+ -+ priv->calendar = glade_xml_get_widget (priv->glade_xml, "calendar"); -+ priv->hours_spin = glade_xml_get_widget (priv->glade_xml, "hours_spin"); -+ priv->minutes_spin = glade_xml_get_widget (priv->glade_xml, "minutes_spin"); -+ priv->seconds_spin = glade_xml_get_widget (priv->glade_xml, "seconds_spin"); -+ -+ gtk_entry_set_width_chars (GTK_ENTRY (priv->hours_spin), 2); -+ gtk_entry_set_width_chars (GTK_ENTRY (priv->minutes_spin), 2); -+ gtk_entry_set_width_chars (GTK_ENTRY (priv->seconds_spin), 2); -+ -+ gtk_entry_set_alignment (GTK_ENTRY (priv->hours_spin), 1.0); -+ gtk_entry_set_alignment (GTK_ENTRY (priv->minutes_spin), 1.0); -+ gtk_entry_set_alignment (GTK_ENTRY (priv->seconds_spin), 1.0); -+ g_signal_connect (priv->seconds_spin, "wrapped", G_CALLBACK (wrap_cb), this); -+ g_signal_connect (priv->minutes_spin, "wrapped", G_CALLBACK (wrap_cb), this); -+ g_signal_connect (priv->hours_spin, "wrapped", G_CALLBACK (wrap_cb), this); -+ - /* fill it with the current preferences */ - fill_prefs_window (this); - } - -+ if (locations) { -+ GtkWidget *notebook = -+ glade_xml_get_widget (priv->glade_xml, "notebook"); -+ gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 1); -+ } -+ -+ update_set_time_button (this); -+ - gtk_window_present (GTK_WINDOW (priv->prefs_window)); -+ -+ intlclock_ui_reset_timeout (this); -+} -+ -+void -+intlclock_ui_edit_locations (IntlClockUI *ui) -+{ -+ display_prefs_window (ui, TRUE); - } - - static void -@@ -1306,16 +1469,11 @@ intlclock_ui_new (IntlClock *clock, PanelApplet *applet) - create_events_window (this); - create_clock_window (this); - create_cities_store (this); -- -- if (priv->show_locations) { -- create_cities_section (this); -- } -- -- if (priv->show_map) { -- create_map_section (this); -- intlclock_map_refresh (INTLCLOCK_MAP (priv->map_widget)); -- } -- -+ create_cities_section (this); -+ create_map_section (this); -+ -+ intlclock_map_refresh (INTLCLOCK_MAP (priv->map_widget)); -+ - intlclock_ui_reset_timeout (this); - - return this; -@@ -1365,9 +1523,6 @@ intlclock_ui_init (IntlClockUI *this) - - priv->cities_store = NULL; - -- priv->show_locations = TRUE; -- priv->show_map = TRUE; -- - priv->prefs_window = NULL; - - priv->format_12hr = TRUE; -@@ -1547,56 +1702,6 @@ gconf_show_week_changed (GConfClient *client, - } - - static void --gconf_show_locations_changed (GConfClient *client, -- guint cnxn_id, -- GConfEntry *entry, -- IntlClockUI *this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- GtkWidget *widget; -- -- gboolean value; -- -- if (!entry->value || entry->value->type != GCONF_VALUE_BOOL) -- return; -- -- value = gconf_value_get_bool (entry->value); -- -- priv->show_locations = (value != 0); -- -- widget = glade_xml_get_widget (priv->glade_xml, "show_locations_check"); -- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), -- priv->show_locations); -- -- create_cities_section (this); --} -- --static void --gconf_show_map_changed (GConfClient *client, -- guint cnxn_id, -- GConfEntry *entry, -- IntlClockUI *this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- GtkWidget *widget; -- -- gboolean value; -- -- if (!entry->value || entry->value->type != GCONF_VALUE_BOOL) -- return; -- -- value = gconf_value_get_bool (entry->value); -- -- priv->show_map = (value != 0); -- -- widget = glade_xml_get_widget (priv->glade_xml, "show_map_check"); -- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), -- priv->show_map); -- -- create_map_section (this); --} -- --static void - location_start_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, -@@ -1614,6 +1719,7 @@ location_start_element (GMarkupParseContext *context, - gchar *timezone = NULL; - gfloat latitude = 0.0; - gfloat longitude = 0.0; -+ gchar *code = NULL; - - int index = 0; - -@@ -1633,6 +1739,8 @@ location_start_element (GMarkupParseContext *context, - 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]; - } - } - -@@ -1642,7 +1750,7 @@ location_start_element (GMarkupParseContext *context, - return; - } - -- loc = intlclock_location_new (name, timezone, latitude, longitude); -+ loc = intlclock_location_new (name, timezone, latitude, longitude, code); - - *(GList **)user_data = g_list_append (ret, loc); - } -@@ -1713,10 +1821,11 @@ gconf_loc_to_string (IntlClockLocation *loc) - prev_locale = setlocale (LC_NUMERIC, "POSIX"); - - ret = g_markup_printf_escaped -- ("", -+ ("", - intlclock_location_get_name (loc), - intlclock_location_get_timezone (loc), -- latitude, longitude); -+ latitude, longitude, -+ intlclock_location_get_weather_code (loc)); - - setlocale (LC_NUMERIC, ""); - -@@ -1803,24 +1912,6 @@ setup_gconf (IntlClockUI *this) - g_free (key); - - key = panel_applet_gconf_get_full_key -- (PANEL_APPLET (priv->panel_applet), KEY_SHOW_LOCATIONS); -- priv->listeners [index++] = -- gconf_client_notify_add ( -- client, key, -- (GConfClientNotifyFunc) gconf_show_locations_changed, -- this, NULL, NULL); -- g_free (key); -- -- key = panel_applet_gconf_get_full_key -- (PANEL_APPLET (priv->panel_applet), KEY_SHOW_MAP); -- priv->listeners [index++] = -- gconf_client_notify_add ( -- client, key, -- (GConfClientNotifyFunc) gconf_show_map_changed, -- this, NULL, NULL); -- g_free (key); -- -- key = panel_applet_gconf_get_full_key - (PANEL_APPLET (priv->panel_applet), KEY_CITIES); - priv->listeners [index++] = - gconf_client_notify_add ( -@@ -1868,14 +1959,6 @@ load_gconf_settings (IntlClockUI *this) - panel_applet_gconf_get_bool (priv->panel_applet, - KEY_SHOW_WEEK, NULL); - -- priv->show_locations = -- panel_applet_gconf_get_bool (priv->panel_applet, -- KEY_SHOW_LOCATIONS, NULL); -- -- priv->show_map = -- panel_applet_gconf_get_bool (priv->panel_applet, -- KEY_SHOW_MAP, NULL); -- - values = panel_applet_gconf_get_list (priv->panel_applet, KEY_CITIES, - GCONF_VALUE_STRING, NULL); - -@@ -1894,90 +1977,14 @@ static void bonobo_display_properties_dialog (BonoboUIComponent *uic, - { - IntlClockUIPrivate *priv = PRIVATE (this); - -- display_prefs_window (this); --} -- --static void bonobo_run_time_configuration (BonoboUIComponent *uic, -- IntlClockUI *this, -- const gchar *verbname) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- run_time_configuration (this); -+ display_prefs_window (this, FALSE); - } - - static void display_prefs_window_cb (GtkButton *button, gpointer this) - { - IntlClockUIPrivate *priv = PRIVATE (this); - -- display_prefs_window (this); --} -- --static void --run_time_configuration_cb (GtkButton *button, gpointer this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- run_time_configuration (this); --} -- --static void --run_time_configuration (IntlClockUI *this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- GtkWidget *dialog; -- GError *err; -- char **argv; -- char *path; -- -- GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (priv->events_window)); -- gchar *tool = "/opt/gnome/bin/gnomesu /sbin/yast2 timezone"; -- -- if (!tool || tool[0] == '\0') -- return; -- -- if (!g_shell_parse_argv (tool, NULL, &argv, NULL)) -- return; -- -- if (!(path = g_find_program_in_path (argv [0]))) { -- g_strfreev (argv); -- return; -- } -- -- g_free (path); -- -- err = NULL; -- if (gdk_spawn_on_screen (screen, -- NULL, -- argv, -- NULL, -- G_SPAWN_SEARCH_PATH, -- NULL, -- NULL, -- NULL, -- &err)) { -- g_strfreev (argv); -- return; -- } -- -- g_strfreev (argv); -- -- dialog = gtk_message_dialog_new (NULL, -- GTK_DIALOG_DESTROY_WITH_PARENT, -- GTK_MESSAGE_ERROR, -- GTK_BUTTONS_OK, -- _("Failed to launch time configuration tool: %s"), -- err->message); -- g_error_free (err); -- -- g_signal_connect (dialog, "response", -- G_CALLBACK (gtk_widget_destroy), NULL); -- -- gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); -- gtk_window_set_screen (GTK_WINDOW (dialog), screen); -- -- gtk_widget_show_all (dialog); -+ display_prefs_window (this, FALSE); - } - - static void -@@ -2205,7 +2212,7 @@ static void - run_prefs_locations_remove (GtkButton *button, gpointer this) - { - IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -- GtkTreeModel *model = gtk_tree_view_get_model (priv->prefs_locations);; -+ GtkTreeModel *model = gtk_tree_view_get_model (priv->prefs_locations); - GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->prefs_locations)); - - gtk_tree_selection_selected_foreach (sel, remove_tree_row, this); -@@ -2230,7 +2237,7 @@ run_prefs_locations_edit (GtkButton *button, gpointer this) - { - IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); - -- GtkTreeModel *model = gtk_tree_view_get_model (priv->prefs_locations);; -+ GtkTreeModel *model = gtk_tree_view_get_model (priv->prefs_locations); - GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->prefs_locations)); - - gtk_tree_selection_selected_foreach (sel, edit_tree_row, this); -@@ -2283,7 +2290,7 @@ run_prefs_edit_save (GtkButton *button, gpointer this) - intlclock_location_set_coords (loc, lat, lon); - } else { - GList *locs; -- loc = intlclock_location_new (name, intlclock_zoneinfo_get_name (info), lat, lon); -+ loc = intlclock_location_new (name, intlclock_zoneinfo_get_name (info), lat, lon, NULL); - - locs = g_list_copy (intlclock_get_locations (priv->clock)); - locs = g_list_append (locs, loc); -@@ -2294,3 +2301,11 @@ run_prefs_edit_save (GtkButton *button, gpointer this) - - intlclock_edit_hide (edit_window, this); - } -+ -+void -+intlclock_ui_update_weather_icon (IntlClockUI *ui, GdkPixbuf *pixbuf) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (ui)); -+ -+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->panel_weather_icon), pixbuf); -+} -diff --git a/src/intlclock-ui.h b/src/intlclock-ui.h -index ecbee03..a10099a 100644 ---- a/src/intlclock-ui.h -+++ b/src/intlclock-ui.h -@@ -29,6 +29,8 @@ GType intlclock_ui_get_type (void); - - IntlClockUI *intlclock_ui_new (IntlClock *clock, PanelApplet *applet); - gboolean intlclock_ui_is_12hr (IntlClockUI *ui); -+void intlclock_ui_edit_locations (IntlClockUI *ui); -+void intlclock_ui_update_weather_icon (IntlClockUI *ui, GdkPixbuf *pixbuf); - - G_END_DECLS - #endif /* __INTLCLOCK_UI_H__ */ -diff --git a/src/intlclock.c b/src/intlclock.c -index 02f5b0a..552c45c 100644 ---- a/src/intlclock.c -+++ b/src/intlclock.c -@@ -32,6 +32,8 @@ typedef struct { - enum { - TICK, - LOCATIONS_CHANGED, -+ BLINK_LOCATION, -+ CURRENT_TIMEZONE_CHANGED, - LAST_SIGNAL - }; - -@@ -87,7 +89,25 @@ intlclock_class_init (IntlClockClass *this_class) - _intlclock_marshal_VOID__VOID, - G_TYPE_NONE, 0); - -- g_type_class_add_private (this_class, sizeof (IntlClockPrivate)); -+ intlclock_signals[BLINK_LOCATION] = g_signal_new -+ ("blink-location", -+ G_OBJECT_CLASS_TYPE (obj_class), -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (IntlClockClass, blink_location), -+ NULL, NULL, -+ _intlclock_marshal_VOID__OBJECT, -+ G_TYPE_NONE, 1, INTLCLOCK_LOCATION_TYPE); -+ -+ intlclock_signals[CURRENT_TIMEZONE_CHANGED] = g_signal_new -+ ("current-timezone-changed", -+ G_OBJECT_CLASS_TYPE (obj_class), -+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, -+ G_STRUCT_OFFSET (IntlClockClass, current_timezone_changed), -+ NULL, NULL, -+ _intlclock_marshal_VOID__VOID, -+ G_TYPE_NONE, 0); -+ -+ g_type_class_add_private (this_class, sizeof (IntlClockPrivate)); - } - - static void -@@ -133,7 +153,7 @@ intlclock_set_locations (IntlClock *this, GList *locations) - - priv->locations = locations; - -- g_signal_emit_by_name (this, "locations-changed"); -+ g_signal_emit (this, intlclock_signals[LOCATIONS_CHANGED], 0); - } - - GList * -@@ -202,7 +222,7 @@ intlclock_emit_tick (gpointer data) - IntlClock *this = INTLCLOCK (data); - IntlClockPrivate *priv = PRIVATE (this); - -- g_signal_emit_by_name (this, "tick"); -+ g_signal_emit (this, intlclock_signals[TICK], 0); - - if (priv->in_partial_timeout) { - intlclock_reset_timeout (this); -@@ -353,3 +373,9 @@ intlclock_free_locations (IntlClock *this) - g_list_free (priv->locations); - priv->locations = NULL; - } -+ -+void -+intlclock_blink_location (IntlClock *this, IntlClockLocation *loc) -+{ -+ g_signal_emit (this, intlclock_signals[BLINK_LOCATION], 0, loc); -+} -diff --git a/src/intlclock.h b/src/intlclock.h -index 3b0012c..20c681d 100644 ---- a/src/intlclock.h -+++ b/src/intlclock.h -@@ -27,6 +27,9 @@ typedef struct - - void (* tick) (IntlClock *clock); - void (* locations_changed) (IntlClock *clock); -+ void (* blink_location) (IntlClock *clock, IntlClockLocation *loc); -+ void (* current_timezone_changed) (IntlClock *clock); -+ - } IntlClockClass; - - GType intlclock_get_type (void); -@@ -35,6 +38,7 @@ IntlClock *intlclock_new (void); - - void intlclock_set_locations (IntlClock *this, GList *list); - GList *intlclock_get_locations (IntlClock *this); -+void intlclock_blink_location (IntlClock *this, IntlClockLocation *loc); - - IntlClockZoneTable *intlclock_get_zonetable (IntlClock *this); - gchar *intlclock_format_time (IntlClock *this, struct tm *now, -diff --git a/src/set-timezone.c b/src/set-timezone.c -new file mode 100644 -index 0000000..3233ce3 ---- /dev/null -+++ b/src/set-timezone.c -@@ -0,0 +1,432 @@ -+/* -*- 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 -+#include -+ -+static DBusGConnection * -+get_session_bus (void) -+{ -+ GError *error; -+ static DBusGConnection *bus = NULL; -+ -+ if (bus == NULL) { -+ error = NULL; -+ bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); -+ if (bus == NULL) { -+ g_warning ("Couldn't connect to session bus: %s", -+ error->message); -+ g_error_free (error); -+ } -+ } -+ -+ return bus; -+} -+ -+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; -+} -+ -+static PolKitContext * -+get_pk_context (void) -+{ -+ static PolKitContext *pk_context = NULL; -+ -+ if (pk_context == NULL) { -+ pk_context = polkit_context_new (); -+ if (!polkit_context_init (pk_context, NULL)) { -+ polkit_context_unref (pk_context); -+ pk_context = NULL; -+ } -+ } -+ -+ return pk_context; -+} -+ -+gboolean -+set_system_timezone (const char *filename, GError **err) -+{ -+ DBusGConnection *session_bus; -+ DBusGConnection *system_bus; -+ DBusGProxy *mechanism_proxy; -+ DBusGProxy *polkit_gnome_proxy; -+ gboolean ret = FALSE; -+ -+ session_bus = get_session_bus (); -+ if (session_bus == NULL) -+ goto out; -+ -+ system_bus = get_system_bus (); -+ if (system_bus == NULL) -+ goto out; -+ -+ mechanism_proxy = dbus_g_proxy_new_for_name (system_bus, -+ "org.gnome.ClockApplet.Mechanism", -+ "/", -+ "org.gnome.ClockApplet.Mechanism"); -+ -+ polkit_gnome_proxy = dbus_g_proxy_new_for_name (session_bus, -+ "org.gnome.PolicyKit", -+ "/org/gnome/PolicyKit/Manager", -+ "org.gnome.PolicyKit.Manager"); -+ -+ if (filename != NULL) { -+ GError *error; -+ -+ g_debug ("Trying to set timezone '%s'", filename); -+ try_again: -+ error = NULL; -+ /* first, try to call into the mechanism */ -+ if (!dbus_g_proxy_call_with_timeout (mechanism_proxy, -+ "SetTimezone", -+ INT_MAX, -+ &error, -+ /* parameters: */ -+ G_TYPE_STRING, filename, -+ G_TYPE_INVALID, -+ /* return values: */ -+ G_TYPE_INVALID)) { -+ if (dbus_g_error_has_name (error, "org.gnome.ClockApplet.Mechanism.NotPrivileged")) { -+ char **tokens; -+ char *polkit_result_textual; -+ char *polkit_action; -+ gboolean gained_privilege; -+ -+ tokens = g_strsplit (error->message, " ", 2); -+ g_error_free (error); -+ if (g_strv_length (tokens) != 2) { -+ g_warning ("helper return string malformed"); -+ g_strfreev (tokens); -+ goto out; -+ } -+ polkit_action = tokens[0]; -+ polkit_result_textual = tokens[1]; -+ -+ g_debug ("helper refused; returned polkit_result='%s' and polkit_action='%s'", -+ polkit_result_textual, polkit_action); -+ -+ /* Now ask the user for auth... */ -+ if (!dbus_g_proxy_call_with_timeout (polkit_gnome_proxy, -+ "ShowDialog", -+ INT_MAX, -+ &error, -+ /* parameters: */ -+ G_TYPE_STRING, polkit_action, -+ G_TYPE_UINT, 0, /* X11 window ID; none */ -+ G_TYPE_INVALID, -+ /* return values: */ -+ G_TYPE_BOOLEAN, &gained_privilege, -+ G_TYPE_INVALID)) { -+ g_propagate_error (err, error); -+ g_strfreev (tokens); -+ goto out; -+ } -+ g_strfreev (tokens); -+ -+ if (gained_privilege) { -+ g_debug ("Gained privilege; trying to set timezone again"); -+ goto try_again; -+ } -+ -+ } else { -+ g_propagate_error (err, error); -+ } -+ goto out; -+ } -+ -+ g_debug ("Successfully set time zone to '%s'", filename); -+ } -+ -+ ret = TRUE; -+out: -+ g_object_unref (mechanism_proxy); -+ g_object_unref (polkit_gnome_proxy); -+ -+ return ret; -+} -+ -+static gint -+can_do (const gchar *pk_action_id) -+{ -+ DBusConnection *system_bus; -+ PolKitCaller *pk_caller; -+ PolKitAction *pk_action; -+ PolKitResult pk_result; -+ PolKitContext *pk_context; -+ DBusError dbus_error; -+ gint res = 0; -+ -+ system_bus = dbus_g_connection_get_connection (get_system_bus ()); -+ if (system_bus == NULL) -+ goto out; -+ -+ pk_context = get_pk_context (); -+ if (pk_context == NULL) -+ goto out; -+ -+ pk_caller = NULL; -+ pk_action = NULL; -+ -+ pk_action = polkit_action_new (); -+ polkit_action_set_action_id (pk_action, pk_action_id); -+ -+ dbus_error_init (&dbus_error); -+ pk_caller = polkit_caller_new_from_pid (system_bus, getpid (), &dbus_error); -+ if (pk_caller == NULL) { -+ fprintf (stderr, "cannot get caller from dbus name\n"); -+ goto out; -+ } -+ -+ pk_result = polkit_context_can_caller_do_action (pk_context, pk_action, pk_caller); -+ -+ switch (pk_result) { -+ default: -+ case POLKIT_RESULT_UNKNOWN: -+ case POLKIT_RESULT_NO: -+ res = 0; -+ break; -+ case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH: -+ case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_SESSION: -+ case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_ALWAYS: -+ case POLKIT_RESULT_ONLY_VIA_SELF_AUTH: -+ case POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_SESSION: -+ case POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_ALWAYS: -+ res = 1; -+ break; -+ case POLKIT_RESULT_YES: -+ res = 2; -+ break; -+ } -+ -+out: -+ if (pk_action != NULL) -+ polkit_action_unref (pk_action); -+ if (pk_caller != NULL) -+ polkit_caller_unref (pk_caller); -+ -+ return res; -+} -+ -+gint -+can_set_system_timezone (void) -+{ -+ return can_do ("org.gnome.clockapplet.mechanism.settimezone"); -+} -+ -+gint -+can_set_system_time (void) -+{ -+ return can_do ("org.gnome.clockapplet.mechanism.settime"); -+} -+ -+typedef struct { -+ gint ref_count; -+ gint64 time; -+ 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); -+ } -+} -+ -+static void set_time_async (SetTimeCallbackData *data); -+ -+static void -+auth_notify (DBusGProxy *proxy, -+ DBusGProxyCall *call, -+ void *user_data) -+{ -+ SetTimeCallbackData *data = user_data; -+ GError *error = NULL; -+ gboolean gained_privilege; -+ -+ g_print ("ending async ShowDialog call\n"); -+ if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_BOOLEAN, &gained_privilege, G_TYPE_INVALID)) { -+ g_print ("result: %d\n", gained_privilege); -+ if (gained_privilege) -+ set_time_async (data); -+ } -+ else { -+ if (data->callback) -+ data->callback (data->data, error); -+ else -+ g_error_free (error); -+ } -+} -+ -+static void -+do_auth_async (const gchar *action, -+ const gchar *result, -+ SetTimeCallbackData *data) -+{ -+ DBusGConnection *bus; -+ DBusGProxy *proxy; -+ -+ g_debug ("helper refused; returned polkit_result='%s' and polkit_action='%s'", -+ result, action); -+ -+ /* Now ask the user for auth... */ -+ bus = get_session_bus (); -+ if (bus == NULL) -+ return; -+ -+ proxy = dbus_g_proxy_new_for_name (bus, -+ "org.gnome.PolicyKit", -+ "/org/gnome/PolicyKit/Manager", -+ "org.gnome.PolicyKit.Manager"); -+ -+ g_print ("beginning async ShowDialog call\n"); -+ data->ref_count++; -+ dbus_g_proxy_begin_call_with_timeout (proxy, -+ "ShowDialog", -+ auth_notify, -+ data, free_data, -+ INT_MAX, -+ G_TYPE_STRING, action, -+ G_TYPE_UINT, 0, -+ G_TYPE_INVALID); -+} -+ -+static void -+set_time_notify (DBusGProxy *proxy, -+ DBusGProxyCall *call, -+ void *user_data) -+{ -+ SetTimeCallbackData *data = user_data; -+ GError *error = NULL; -+ -+ g_print ("ending async SetTime call\n"); -+ if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) { -+ g_print ("calling user callback\n"); -+ if (data->callback) -+ data->callback (data->data, NULL); -+ } -+ else { -+ if (dbus_g_error_has_name (error, "org.gnome.ClockApplet.Mechanism.NotPrivileged")) { -+ gchar **tokens; -+ -+ tokens = g_strsplit (error->message, " ", 2); -+ g_error_free (error); -+ if (g_strv_length (tokens) == 2) -+ do_auth_async (tokens[0], tokens[1], data); -+ else -+ g_warning ("helper return string malformed"); -+ g_strfreev (tokens); -+ } -+ 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; -+ DBusGProxyCall *call; -+ -+ bus = get_system_bus (); -+ if (bus == NULL) -+ return; -+ -+ proxy = dbus_g_proxy_new_for_name (bus, -+ "org.gnome.ClockApplet.Mechanism", -+ "/", -+ "org.gnome.ClockApplet.Mechanism"); -+ -+ g_print ("beginning async SetTime call\n"); -+ data->ref_count++; -+ 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); -+} -+ -+void -+set_system_time_async (gint64 time, -+ GFunc callback, -+ gpointer d, -+ GDestroyNotify notify) -+{ -+ SetTimeCallbackData *data; -+ -+ if (time == -1) -+ return; -+ -+ data = g_new (SetTimeCallbackData, 1); -+ data->ref_count = 1; -+ data->time = time; -+ data->callback = callback; -+ data->data = d; -+ data->notify = notify; -+ -+ set_time_async (data); -+ free_data (data); -+} -diff --git a/src/set-timezone.h b/src/set-timezone.h -new file mode 100644 -index 0000000..c71622c ---- /dev/null -+++ b/src/set-timezone.h -@@ -0,0 +1,36 @@ -+/* -*- 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 -+ -+gboolean set_system_timezone (const char *filename, -+ GError **err); -+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); -+ -+#endif diff --git a/intlclock-changes-20071009.patch b/intlclock-changes-20071009.patch deleted file mode 100644 index 911110a..0000000 --- a/intlclock-changes-20071009.patch +++ /dev/null @@ -1,10832 +0,0 @@ -diff --git a/configure.in b/configure.in -index 4e818da..6c75db1 100644 ---- a/configure.in -+++ b/configure.in -@@ -59,7 +59,7 @@ if test -n "$LIBECAL_REQUIREMENT"; then - fi - AM_CONDITIONAL(HAVE_LIBECAL, test -n "$LIBECAL_REQUIREMENT") - --PKG_CHECK_MODULES(INTLCLOCK, [ glib-2.0 gobject-2.0 gtk+-2.0 gdk-2.0 librsvg-2.0 libpanelapplet-2.0 libgnome-2.0 gconf-2.0 $LIBECAL_REQUIREMENT ]) -+PKG_CHECK_MODULES(INTLCLOCK, [ glib-2.0 gobject-2.0 gtk+-2.0 gdk-2.0 librsvg-2.0 libpanelapplet-2.0 libgnome-2.0 gconf-2.0 $LIBECAL_REQUIREMENT dbus-glib-1 gweather libxml-2.0 polkit polkit-dbus ]) - - AC_SUBST(INTLCLOCK_CFLAGS) - AC_SUBST(INTLCLOCK_LIBS) -diff --git a/data/GNOME_IntlClockApplet.xml b/data/GNOME_IntlClockApplet.xml -index dd2e8b8..a88dc3d 100644 ---- a/data/GNOME_IntlClockApplet.xml -+++ b/data/GNOME_IntlClockApplet.xml -@@ -1,9 +1,14 @@ - - - -+ -+ -+ - -+ _label="Ad_just Date & Time" -+ pixtype="stock" pixname="gtk-preferences"/> - - -diff --git a/data/GNOME_IntlClockApplet_Factory.server.in.in b/data/GNOME_IntlClockApplet_Factory.server.in.in -index 1446822..705fb76 100644 ---- a/data/GNOME_IntlClockApplet_Factory.server.in.in -+++ b/data/GNOME_IntlClockApplet_Factory.server.in.in -@@ -20,7 +20,7 @@ - - - -- -+ - - - - -+ 6 - True - False - 0 - - -- -+ - 6 - True - True -@@ -37,194 +38,35 @@ - False - - -- -- 6 -+ -+ 12 - True -- 4 -- 3 - False -- 6 -- 6 -+ 18 - - -- -- True -- Clock options: -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 0 -- 1 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 2 -- 3 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 3 -- 4 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 2 -- 3 -- 3 -- 4 -- fill -- -- -- -- -- -- -- True -- True -- Show s_econds -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- -- -- 1 -- 3 -- 2 -- 3 -- fill -- -- -- -- -- -- -+ - True - False - 6 - - -- -+ - True -- True -- 12 _hour format -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -+ <b>Clock Options</b> -+ False -+ True -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 - - - 0 -@@ -234,138 +76,150 @@ - - - -- -+ - True -- True -- 24 h_our format -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- 12hr_radio -+ False -+ 0 -+ -+ -+ -+ True -+ -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ False -+ 13 -+ -+ -+ -+ True -+ True -+ 12 _hour format -+ True -+ GTK_RELIEF_NORMAL -+ True -+ False -+ False -+ True -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ True -+ 24 h_our format -+ True -+ GTK_RELIEF_NORMAL -+ True -+ False -+ False -+ True -+ 12hr_radio -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ Show the _date -+ True -+ GTK_RELIEF_NORMAL -+ True -+ False -+ False -+ True -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ True -+ Show _seconds -+ True -+ GTK_RELIEF_NORMAL -+ True -+ False -+ False -+ True -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ - - - 0 -- False -- False -+ True -+ True - - - - -- 1 -- 2 -- 0 -- 1 -- fill -- fill -- -- -- -- -- -- True -- True -- Show the _date -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- -- -- 1 -- 2 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 2 -- 3 -- 0 -- 1 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 2 -- 3 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 1 -- 2 -- 3 -- 4 -- fill -- -+ 0 -+ False -+ True - - - -@@ -376,7 +230,7 @@ - - - -- -+ - True - General - False -@@ -399,332 +253,105 @@ - - - -- -- 6 -+ -+ 12 - True -- 8 -- 4 - False -- 6 -- 6 -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 3 -- 4 -- 0 -- 1 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 3 -- 4 -- 1 -- 2 -- fill -- -- -- -+ 18 - - -- -+ - True -- True -- GTK_POLICY_NEVER -- GTK_POLICY_NEVER -- GTK_SHADOW_IN -- GTK_CORNER_TOP_LEFT -+ False -+ 12 - - -- -+ - True - True -- False -- False -- False -- True -- False -- False -- True -+ GTK_POLICY_NEVER -+ GTK_POLICY_NEVER -+ GTK_SHADOW_IN -+ GTK_CORNER_TOP_LEFT -+ -+ -+ -+ True -+ True -+ False -+ False -+ False -+ True -+ False -+ False -+ True -+ -+ - -+ -+ 0 -+ True -+ True -+ - -- -- -- 0 -- 3 -- 2 -- 8 -- fill -- -- -- -- -- -- True -- 0 -- 0.5 -- 0 -- 1 -- 0 -- 0 -- 0 -- 0 - - -- -+ - True -- False -+ GTK_BUTTONBOX_START - 6 - - -- -+ -+ 24 -+ 25 - True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0.5 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -+ True -+ True -+ gtk-add -+ True -+ GTK_RELIEF_NORMAL -+ True - -- -- 0 -- False -- False -- - - - -- -+ -+ 24 -+ 24 - True -- GTK_BUTTONBOX_START -- 6 -- -- -- -- 24 -- 25 -- True -- True -- True -- gtk-add -- True -- GTK_RELIEF_NORMAL -- True -- -- -- -- -- -- 24 -- 24 -- True -- True -- True -- gtk-edit -- True -- GTK_RELIEF_NORMAL -- True -- -- -- -- -- -- True -- True -- True -- gtk-remove -- True -- GTK_RELIEF_NORMAL -- True -- -- -+ True -+ True -+ gtk-edit -+ True -+ GTK_RELIEF_NORMAL -+ True - -- -- 0 -- False -- False -- - - - -- -+ - True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0.5 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -+ True -+ True -+ gtk-remove -+ True -+ GTK_RELIEF_NORMAL -+ True - -- -- 0 -- False -- False -- - - -+ -+ 0 -+ False -+ False -+ - - - -- 3 -- 4 -- 2 -- 8 -- -- fill -- -- -- -- -- -- True -- True -- Show the world _map in the clock -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- -- -- 0 -- 1 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0.5 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 2 -- 3 -- 1 -- 2 -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 1 -- 2 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- True -- S_how locations in the clock -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- -- -- 0 -- 3 -- 0 -- 1 -- fill -- -+ 0 -+ True -+ True - - - -@@ -735,7 +362,7 @@ - - - -- -+ - True - Locations - False -@@ -772,95 +399,20 @@ - 0 - - -- -- True -- GTK_BUTTONBOX_DEFAULT_STYLE -- 0 -- -- -- 0 -- False -- False -- -- -- -- -- -+ - True - GTK_BUTTONBOX_END - 6 - - -- -+ - True - True - True -+ Time Settings -+ True - GTK_RELIEF_NORMAL - True -- -- -- -- True -- 0.5 -- 0.5 -- 0 -- 0 -- 0 -- 0 -- 0 -- 0 -- -- -- -- True -- False -- 2 -- -- -- -- True -- gtk-properties -- 4 -- 0.5 -- 0.5 -- 0 -- 0 -- -- -- 0 -- False -- False -- -- -- -- -- -- True -- Time _Settings -- True -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0.5 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- False -- False -- -- -- -- -- -- - - - -@@ -910,13 +462,13 @@ - - - -+ 12 - True - False -- 0 -+ 24 - - - -- 6 - True - 1 - 3 -@@ -926,7 +478,6 @@ - - - -- 6 - True - False - 6 -@@ -974,62 +525,6 @@ - 6 - - -- -- True -- Timezone: -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 0 -- 1 -- fill -- -- -- -- -- -- -- True -- Location Name: -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 1 -- 2 -- fill -- -- -- -- -- - - True - True -@@ -1070,45 +565,6 @@ - - - -- -- True -- Dummy Item -- False -- True -- True -- -- -- 1 -- 4 -- 0 -- 1 -- fill -- fill -- -- -- -- -- -- True -- True -- True -- True -- 0 -- -- True -- -- False -- -- -- 1 -- 4 -- 1 -- 2 -- -- -- -- -- - - True - Longitude: -@@ -1145,7 +601,7 @@ - 0 - - True -- -+ - False - - -@@ -1258,7 +714,7 @@ South - 0 - - True -- -+ - False - - -@@ -1269,6 +725,131 @@ South - - - -+ -+ -+ -+ True -+ Location Name: -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ 1 -+ 0 -+ 1 -+ fill -+ -+ -+ -+ -+ -+ -+ True -+ Timezone: -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ 1 -+ 1 -+ 2 -+ fill -+ -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ True -+ True -+ True -+ 0 -+ -+ True -+ -+ False -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ Find... -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 1 -+ 4 -+ 0 -+ 1 -+ fill -+ fill -+ -+ -+ -+ -+ -+ True -+ Dummy Item -+ False -+ True -+ True -+ -+ -+ 1 -+ 4 -+ 1 -+ 2 -+ fill -+ fill -+ -+ - - - 0 -@@ -1294,60 +875,33 @@ South - - - -- -- 6 -+ - True -- False -- 0 -+ GTK_BUTTONBOX_END -+ 6 - - -- -+ - True -- GTK_BUTTONBOX_DEFAULT_STYLE -- 0 -+ True -+ True -+ gtk-cancel -+ True -+ GTK_RELIEF_NORMAL -+ True - -- -- 0 -- False -- False -- - - - -- -+ - True -- GTK_BUTTONBOX_END -- 6 -- -- -- -- True -- True -- True -- gtk-cancel -- True -- GTK_RELIEF_NORMAL -- True -- -- -- -- -- -- True -- True -- True -- gtk-ok -- True -- GTK_RELIEF_NORMAL -- True -- -- -+ True -+ True -+ gtk-ok -+ True -+ GTK_RELIEF_NORMAL -+ True - -- -- 0 -- True -- True -- - - - -@@ -1723,4 +1277,580 @@ South - - - -+ -+ -+ GTK_WINDOW_TOPLEVEL -+ GTK_WIN_POS_NONE -+ False -+ True -+ False -+ True -+ False -+ False -+ GDK_WINDOW_TYPE_HINT_NORMAL -+ GDK_GRAVITY_NORTH_WEST -+ True -+ False -+ -+ -+ -+ 12 -+ True -+ False -+ 24 -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ True -+ GTK_POLICY_AUTOMATIC -+ GTK_POLICY_AUTOMATIC -+ GTK_SHADOW_IN -+ GTK_CORNER_TOP_LEFT -+ -+ -+ -+ True -+ True -+ False -+ False -+ False -+ False -+ False -+ False -+ False -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ _Find: -+ True -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ find-location-entry -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ True -+ True -+ True -+ 0 -+ -+ True -+ -+ False -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ True -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ 0 -+ 0 -+ 0 -+ 0 -+ -+ -+ -+ True -+ False -+ 2 -+ -+ -+ -+ True -+ gtk-find -+ 4 -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ Find _Next -+ True -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ GTK_BUTTONBOX_END -+ 0 -+ -+ -+ -+ True -+ True -+ True -+ gtk-cancel -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ True -+ gtk-ok -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ -+ -+ 12 -+ Time Settings -+ GTK_WINDOW_TOPLEVEL -+ GTK_WIN_POS_NONE -+ False -+ True -+ False -+ True -+ False -+ False -+ GDK_WINDOW_TYPE_HINT_NORMAL -+ GDK_GRAVITY_NORTH_WEST -+ True -+ False -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ <b>Time Settings</b> -+ False -+ True -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ False -+ 0 -+ -+ -+ -+ True -+ -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ False -+ 12 -+ -+ -+ -+ True -+ True -+ GTK_CALENDAR_SHOW_HEADING -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ Current Time: -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ Time: -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ 23:59:59 -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ False -+ 0 -+ -+ -+ -+ True -+ True -+ 1 -+ 0 -+ True -+ GTK_UPDATE_ALWAYS -+ False -+ True -+ 23 0 23 1 12 12 -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ 1 -+ 0 -+ True -+ GTK_UPDATE_ALWAYS -+ False -+ True -+ 59 0 59 1 30 30 -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ 1 -+ 0 -+ True -+ GTK_UPDATE_ALWAYS -+ False -+ True -+ 59 0 59 1 30 30 -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ 0 -+ False -+ True -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ False -+ 0 -+ -+ -+ -+ True -+ GTK_BUTTONBOX_END -+ 6 -+ -+ -+ -+ True -+ True -+ True -+ gtk-cancel -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ Set System Time -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ 0 -+ False -+ False -+ GTK_PACK_END -+ -+ -+ -+ -+ -+ - -diff --git a/data/intlclock.schemas.in b/data/intlclock.schemas.in -index 2ab6772..00fee4f 100644 ---- a/data/intlclock.schemas.in -+++ b/data/intlclock.schemas.in -@@ -89,41 +89,54 @@ - - - -- /schemas/apps/intlclock_applet/prefs/show_locations -+ /schemas/apps/intlclock_applet/prefs/cities -+ clock-applet -+ list -+ string -+ [] -+ -+ List of cities for the clock. -+ -+ List of cities to display in the international clock. -+ -+ -+ -+ -+ -+ /schemas/apps/intlclock_applet/prefs/expand_locations - clock-applet - bool - true - -- Show other locations in clock -+ Expand the location section in clock - -- If true, show a list of locations in the international clock. -+ If true, expand the list of locations in the international clock. - - - - - -- /schemas/apps/intlclock_applet/prefs/show_map -+ /schemas/apps/intlclock_applet/prefs/expand_tasks - clock-applet - bool - true - -- Show world map in clock -+ Expand the tasks section in clock - -- If true, show the world map in the international clock. -+ If true, expand the list of tasks in the international clock. - - - - - -- /schemas/apps/intlclock_applet/prefs/cities -+ /schemas/apps/intlclock_applet/prefs/expand_appointments - clock-applet -- list -- string -- [] -+ bool -+ true - -- List of cities for the clock. -+ Expand the appointments section in clock - -- List of cities to display in the international clock. -+ If true, expand the list of appointments in the international clock. - - - -diff --git a/intltool-extract.in b/intltool-extract.in -deleted file mode 100755 -index bb6c368..340fc8d ---- a/intltool-extract.in -+++ /dev/null -@@ -1,841 +0,0 @@ --#!@INTLTOOL_PERL@ -w --# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- -- --# --# The Intltool Message Extractor --# --# Copyright (C) 2000-2001, 2003 Free Software Foundation. --# --# Intltool 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. --# --# Intltool 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., 675 Mass Ave, Cambridge, MA 02139, USA. --# --# As a special exception to the GNU General Public License, if you --# distribute this file as part of a program that contains a --# configuration script generated by Autoconf, you may include it under --# the same distribution terms that you use for the rest of that program. --# --# Authors: Kenneth Christiansen --# Darin Adler --# -- --## Release information --my $PROGRAM = "intltool-extract"; --my $PACKAGE = "intltool"; --my $VERSION = "0.35.0"; -- --## Loaded modules --use strict; --use File::Basename; --use Getopt::Long; -- --## Scalars used by the option stuff --my $TYPE_ARG = "0"; --my $LOCAL_ARG = "0"; --my $HELP_ARG = "0"; --my $VERSION_ARG = "0"; --my $UPDATE_ARG = "0"; --my $QUIET_ARG = "0"; --my $SRCDIR_ARG = "."; -- --my $FILE; --my $OUTFILE; -- --my $gettext_type = ""; --my $input; --my %messages = (); --my %loc = (); --my %count = (); --my %comments = (); --my $strcount = 0; -- --my $XMLCOMMENT = ""; -- --## Use this instead of \w for XML files to handle more possible characters. --my $w = "[-A-Za-z0-9._:]"; -- --## Always print first --$| = 1; -- --## Handle options --GetOptions ( -- "type=s" => \$TYPE_ARG, -- "local|l" => \$LOCAL_ARG, -- "help|h" => \$HELP_ARG, -- "version|v" => \$VERSION_ARG, -- "update" => \$UPDATE_ARG, -- "quiet|q" => \$QUIET_ARG, -- "srcdir=s" => \$SRCDIR_ARG, -- ) or &error; -- --&split_on_argument; -- -- --## Check for options. --## This section will check for the different options. -- --sub split_on_argument { -- -- if ($VERSION_ARG) { -- &version; -- -- } elsif ($HELP_ARG) { -- &help; -- -- } elsif ($LOCAL_ARG) { -- &place_local; -- &extract; -- -- } elsif ($UPDATE_ARG) { -- &place_normal; -- &extract; -- -- } elsif (@ARGV > 0) { -- &place_normal; -- &message; -- &extract; -- -- } else { -- &help; -- -- } --} -- --sub place_normal { -- $FILE = $ARGV[0]; -- $OUTFILE = "$FILE.h"; --} -- --sub place_local { -- $FILE = $ARGV[0]; -- $OUTFILE = fileparse($FILE, ()); -- if (!-e "tmp/") { -- system("mkdir tmp/"); -- } -- $OUTFILE = "./tmp/$OUTFILE.h" --} -- --sub determine_type { -- if ($TYPE_ARG =~ /^gettext\/(.*)/) { -- $gettext_type=$1 -- } --} -- --## Sub for printing release information --sub version{ -- print <<_EOF_; --${PROGRAM} (${PACKAGE}) $VERSION --Copyright (C) 2000, 2003 Free Software Foundation, Inc. --Written by Kenneth Christiansen, 2000. -- --This is free software; see the source for copying conditions. There is NO --warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. --_EOF_ -- exit; --} -- --## Sub for printing usage information --sub help { -- print <<_EOF_; --Usage: ${PROGRAM} [OPTION]... [FILENAME] --Generates a header file from an XML source file. -- --It grabs all strings between <_translatable_node> and its end tag in --XML files. Read manpage (man ${PROGRAM}) for more info. -- -- --type=TYPE Specify the file type of FILENAME. Currently supports: -- "gettext/glade", "gettext/ini", "gettext/keys" -- "gettext/rfc822deb", "gettext/schemas", -- "gettext/scheme", "gettext/xml" -- -l, --local Writes output into current working directory -- (conflicts with --update) -- --update Writes output into the same directory the source file -- reside (conflicts with --local) -- --srcdir Root of the source tree -- -v, --version Output version information and exit -- -h, --help Display this help and exit -- -q, --quiet Quiet mode -- --Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE") --or send email to . --_EOF_ -- exit; --} -- --## Sub for printing error messages --sub error{ -- print STDERR "Try `${PROGRAM} --help' for more information.\n"; -- exit; --} -- --sub message { -- print "Generating C format header file for translation.\n" unless $QUIET_ARG; --} -- --sub extract { -- &determine_type; -- -- &convert; -- -- open OUT, ">$OUTFILE"; -- binmode (OUT) if $^O eq 'MSWin32'; -- &msg_write; -- close OUT; -- -- print "Wrote $OUTFILE\n" unless $QUIET_ARG; --} -- --sub convert { -- -- ## Reading the file -- { -- local (*IN); -- local $/; #slurp mode -- open (IN, "<$SRCDIR_ARG/$FILE") || die "can't open $SRCDIR_ARG/$FILE: $!"; -- $input = ; -- } -- -- &type_ini if $gettext_type eq "ini"; -- &type_keys if $gettext_type eq "keys"; -- &type_xml if $gettext_type eq "xml"; -- &type_glade if $gettext_type eq "glade"; -- &type_scheme if $gettext_type eq "scheme"; -- &type_schemas if $gettext_type eq "schemas"; -- &type_rfc822deb if $gettext_type eq "rfc822deb"; --} -- --sub entity_decode_minimal --{ -- local ($_) = @_; -- -- s/'/'/g; # ' -- s/"/"/g; # " -- s/&/&/g; -- -- return $_; --} -- --sub entity_decode --{ -- local ($_) = @_; -- -- s/'/'/g; # ' -- s/"/"/g; # " -- s/&/&/g; -- s/<//g; -- -- return $_; --} -- --sub escape_char --{ -- return '\"' if $_ eq '"'; -- return '\n' if $_ eq "\n"; -- return '\\' if $_ eq '\\'; -- -- return $_; --} -- --sub escape --{ -- my ($string) = @_; -- return join "", map &escape_char, split //, $string; --} -- --sub type_ini { -- ### For generic translatable desktop files ### -- while ($input =~ /^_.*=(.*)$/mg) { -- $messages{$1} = []; -- } --} -- --sub type_keys { -- ### For generic translatable mime/keys files ### -- while ($input =~ /^\s*_\w+=(.*)$/mg) { -- $messages{$1} = []; -- } --} -- --sub type_xml { -- ### For generic translatable XML files ### -- my $tree = readXml($input); -- parseTree(0, $tree); --} -- --sub print_var { -- my $var = shift; -- my $vartype = ref $var; -- -- if ($vartype =~ /ARRAY/) { -- my @arr = @{$var}; -- print "[ "; -- foreach my $el (@arr) { -- print_var($el); -- print ", "; -- } -- print "] "; -- } elsif ($vartype =~ /HASH/) { -- my %hash = %{$var}; -- print "{ "; -- foreach my $key (keys %hash) { -- print "$key => "; -- print_var($hash{$key}); -- print ", "; -- } -- print "} "; -- } else { -- print $var; -- } --} -- --# Same syntax as getAttributeString in intltool-merge.in.in, similar logic (look for ## differences comment) --sub getAttributeString --{ -- my $sub = shift; -- my $do_translate = shift || 1; -- my $language = shift || ""; -- my $translate = shift; -- my $result = ""; -- foreach my $e (reverse(sort(keys %{ $sub }))) { -- my $key = $e; -- my $string = $sub->{$e}; -- my $quote = '"'; -- -- $string =~ s/^[\s]+//; -- $string =~ s/[\s]+$//; -- -- if ($string =~ /^'.*'$/) -- { -- $quote = "'"; -- } -- $string =~ s/^['"]//g; -- $string =~ s/['"]$//g; -- -- ## differences from intltool-merge.in.in -- if ($key =~ /^_/) { -- $comments{entity_decode($string)} = $XMLCOMMENT if $XMLCOMMENT; -- $messages{entity_decode($string)} = []; -- $$translate = 2; -- } -- ## differences end here from intltool-merge.in.in -- $result .= " $key=$quote$string$quote"; -- } -- return $result; --} -- --# Verbatim copy from intltool-merge.in.in --sub getXMLstring --{ -- my $ref = shift; -- my $spacepreserve = shift || 0; -- my @list = @{ $ref }; -- my $result = ""; -- -- my $count = scalar(@list); -- my $attrs = $list[0]; -- my $index = 1; -- -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); -- -- while ($index < $count) { -- my $type = $list[$index]; -- my $content = $list[$index+1]; -- if (! $type ) { -- # We've got CDATA -- if ($content) { -- # lets strip the whitespace here, and *ONLY* here -- $content =~ s/\s+/ /gs if (!$spacepreserve); -- $result .= $content; -- } -- } elsif ( "$type" ne "1" ) { -- # We've got another element -- $result .= "<$type"; -- $result .= getAttributeString(@{$content}[0], 0); # no nested translatable elements -- if ($content) { -- my $subresult = getXMLstring($content, $spacepreserve); -- if ($subresult) { -- $result .= ">".$subresult . ""; -- } else { -- $result .= "/>"; -- } -- } else { -- $result .= "/>"; -- } -- } -- $index += 2; -- } -- return $result; --} -- --# Verbatim copy from intltool-merge.in.in, except for MULTIPLE_OUTPUT handling removed --# Translate list of nodes if necessary --sub translate_subnodes --{ -- my $fh = shift; -- my $content = shift; -- my $language = shift || ""; -- my $singlelang = shift || 0; -- my $spacepreserve = shift || 0; -- -- my @nodes = @{ $content }; -- -- my $count = scalar(@nodes); -- my $index = 0; -- while ($index < $count) { -- my $type = $nodes[$index]; -- my $rest = $nodes[$index+1]; -- traverse($fh, $type, $rest, $language, $spacepreserve); -- $index += 2; -- } --} -- --# Based on traverse() in intltool-merge.in.in --sub traverse --{ -- my $fh = shift; # unused, to allow us to sync code between -merge and -extract -- my $nodename = shift; -- my $content = shift; -- my $language = shift || ""; -- my $spacepreserve = shift || 0; -- -- if ($nodename && "$nodename" eq "1") { -- $XMLCOMMENT = $content; -- } elsif ($nodename) { -- # element -- my @all = @{ $content }; -- my $attrs = shift @all; -- my $translate = 0; -- my $outattr = getAttributeString($attrs, 1, $language, \$translate); -- -- if ($nodename =~ /^_/) { -- $translate = 1; -- $nodename =~ s/^_//; -- } -- my $lookup = ''; -- -- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- -- if ($translate) { -- $lookup = getXMLstring($content, $spacepreserve); -- if (!$spacepreserve) { -- $lookup =~ s/^\s+//s; -- $lookup =~ s/\s+$//s; -- } -- -- if ($lookup && $translate != 2) { -- $comments{$lookup} = $XMLCOMMENT if $XMLCOMMENT; -- $messages{$lookup} = []; -- } elsif ($translate == 2) { -- translate_subnodes($fh, \@all, $language, 1, $spacepreserve); -- } -- } else { -- $XMLCOMMENT = ""; -- my $count = scalar(@all); -- if ($count > 0) { -- my $index = 0; -- while ($index < $count) { -- my $type = $all[$index]; -- my $rest = $all[$index+1]; -- traverse($fh, $type, $rest, $language, $spacepreserve); -- $index += 2; -- } -- } -- } -- $XMLCOMMENT = ""; -- } --} -- -- --# Verbatim copy from intltool-merge.in.in, $fh for compatibility --sub parseTree --{ -- my $fh = shift; -- my $ref = shift; -- my $language = shift || ""; -- -- my $name = shift @{ $ref }; -- my $cont = shift @{ $ref }; -- -- while (!$name || "$name" eq "1") { -- $name = shift @{ $ref }; -- $cont = shift @{ $ref }; -- } -- -- my $spacepreserve = 0; -- my $attrs = @{$cont}[0]; -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- -- traverse($fh, $name, $cont, $language, $spacepreserve); --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_comment --{ -- my $expat = shift; -- my $data = $expat->original_string(); -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- $data =~ s/^$//s; -- push @$clist, 1 => $data; --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_cdatastart --{ -- my $expat = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- push @$clist, 0 => $expat->original_string(); --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_cdataend --{ -- my $expat = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- $clist->[$pos] .= $expat->original_string(); --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_char --{ -- my $expat = shift; -- my $text = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- # Use original_string so that we retain escaped entities -- # in CDATA sections. -- # -- if ($pos > 0 and $clist->[$pos - 1] eq '0') { -- $clist->[$pos] .= $expat->original_string(); -- } else { -- push @$clist, 0 => $expat->original_string(); -- } --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_start --{ -- my $expat = shift; -- my $tag = shift; -- my @origlist = (); -- -- # Use original_string so that we retain escaped entities -- # in attribute values. We must convert the string to an -- # @origlist array to conform to the structure of the Tree -- # Style. -- # -- my @original_array = split /\x/, $expat->original_string(); -- my $source = $expat->original_string(); -- -- # Remove leading tag. -- # -- $source =~ s|^\s*<\s*(\S+)||s; -- -- # Grab attribute key/value pairs and push onto @origlist array. -- # -- while ($source) -- { -- if ($source =~ /^\s*([\w:-]+)\s*[=]\s*["]/) -- { -- $source =~ s|^\s*([\w:-]+)\s*[=]\s*["]([^"]*)["]||s; -- push @origlist, $1; -- push @origlist, '"' . $2 . '"'; -- } -- elsif ($source =~ /^\s*([\w:-]+)\s*[=]\s*[']/) -- { -- $source =~ s|^\s*([\w:-]+)\s*[=]\s*[']([^']*)[']||s; -- push @origlist, $1; -- push @origlist, "'" . $2 . "'"; -- } -- else -- { -- last; -- } -- } -- -- my $ol = [ { @origlist } ]; -- -- push @{ $expat->{Lists} }, $expat->{Curlist}; -- push @{ $expat->{Curlist} }, $tag => $ol; -- $expat->{Curlist} = $ol; --} -- --# Copied from intltool-merge.in.in and added comment handler. --sub readXml --{ -- my $xmldoc = shift || return; -- my $ret = eval 'require XML::Parser'; -- if(!$ret) { -- die "You must have XML::Parser installed to run $0\n\n"; -- } -- my $xp = new XML::Parser(Style => 'Tree'); -- $xp->setHandlers(Char => \&intltool_tree_char); -- $xp->setHandlers(Start => \&intltool_tree_start); -- $xp->setHandlers(CdataStart => \&intltool_tree_cdatastart); -- $xp->setHandlers(CdataEnd => \&intltool_tree_cdataend); -- -- ## differences from intltool-merge.in.in -- $xp->setHandlers(Comment => \&intltool_tree_comment); -- ## differences end here from intltool-merge.in.in -- -- my $tree = $xp->parse($xmldoc); -- #print_var($tree); -- --# Hello thereHowdydo --# would be: --# [foo, [{}, 1, "comment", head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]], bar, --# [{}, 0, "Howdy", ref, [{}]], 0, "do" ] ] -- -- return $tree; --} -- --sub type_schemas { -- ### For schemas XML files ### -- -- # FIXME: We should handle escaped < (less than) -- while ($input =~ / -- \s* -- (\s*(?:\s*)?(.*?)\s*<\/default>\s*)? -- (\s*(?:\s*)?(.*?)\s*<\/short>\s*)? -- (\s*(?:\s*)?(.*?)\s*<\/long>\s*)? -- <\/locale> -- /sgx) { -- my @totranslate = ($3,$6,$9); -- my @eachcomment = ($2,$5,$8); -- foreach (@totranslate) { -- my $currentcomment = shift @eachcomment; -- next if !$_; -- s/\s+/ /g; -- $messages{entity_decode_minimal($_)} = []; -- $comments{entity_decode_minimal($_)} = $currentcomment if (defined($currentcomment)); -- } -- } --} -- --sub type_rfc822deb { -- ### For rfc822-style Debian configuration files ### -- -- my $lineno = 1; -- my $type = ''; -- while ($input =~ /\G(.*?)(^|\n)(_+)([^:]+):[ \t]*(.*?)(?=\n\S|$)/sg) -- { -- my ($pre, $newline, $underscore, $tag, $text) = ($1, $2, $3, $4, $5); -- while ($pre =~ m/\n/g) -- { -- $lineno ++; -- } -- $lineno += length($newline); -- my @str_list = rfc822deb_split(length($underscore), $text); -- for my $str (@str_list) -- { -- $strcount++; -- $messages{$str} = []; -- $loc{$str} = $lineno; -- $count{$str} = $strcount; -- my $usercomment = ''; -- while($pre =~ s/(^|\n)#([^\n]*)$//s) -- { -- $usercomment = "\n" . $2 . $usercomment; -- } -- $comments{$str} = $tag . $usercomment; -- } -- $lineno += ($text =~ s/\n//g); -- } --} -- --sub rfc822deb_split { -- # Debian defines a special way to deal with rfc822-style files: -- # when a value contain newlines, it consists of -- # 1. a short form (first line) -- # 2. a long description, all lines begin with a space, -- # and paragraphs are separated by a single dot on a line -- # This routine returns an array of all paragraphs, and reformat -- # them. -- # When first argument is 2, the string is a comma separated list of -- # values. -- my $type = shift; -- my $text = shift; -- $text =~ s/^[ \t]//mg; -- return (split(/, */, $text, 0)) if $type ne 1; -- return ($text) if $text !~ /\n/; -- -- $text =~ s/([^\n]*)\n//; -- my @list = ($1); -- my $str = ''; -- for my $line (split (/\n/, $text)) -- { -- chomp $line; -- if ($line =~ /^\.\s*$/) -- { -- # New paragraph -- $str =~ s/\s*$//; -- push(@list, $str); -- $str = ''; -- } -- elsif ($line =~ /^\s/) -- { -- # Line which must not be reformatted -- $str .= "\n" if length ($str) && $str !~ /\n$/; -- $line =~ s/\s+$//; -- $str .= $line."\n"; -- } -- else -- { -- # Continuation line, remove newline -- $str .= " " if length ($str) && $str !~ /\n$/; -- $str .= $line; -- } -- } -- $str =~ s/\s*$//; -- push(@list, $str) if length ($str); -- return @list; --} -- --sub type_glade { -- ### For translatable Glade XML files ### -- -- my $tags = "label|title|text|format|copyright|comments|preview_text|tooltip|message"; -- -- while ($input =~ /<($tags)>([^<]+)<\/($tags)>/sg) { -- # Glade sometimes uses tags that normally mark translatable things for -- # little bits of non-translatable content. We work around this by not -- # translating strings that only includes something like label4 or window1. -- $messages{entity_decode($2)} = [] unless $2 =~ /^(window|label|dialog)[0-9]+$/; -- } -- -- while ($input =~ /(..[^<]*)<\/items>/sg) { -- for my $item (split (/\n/, $1)) { -- $messages{entity_decode($item)} = []; -- } -- } -- -- ## handle new glade files -- while ($input =~ /<(property|atkproperty)\s+[^>]*translatable\s*=\s*"yes"(?:\s+[^>]*comments\s*=\s*"([^"]*)")?[^>]*>([^<]+)<\/\1>/sg) { -- $messages{entity_decode($3)} = [] unless $3 =~ /^(window|label)[0-9]+$/; -- if (defined($2) and !($3 =~ /^(window|label)[0-9]+$/)) { -- $comments{entity_decode($3)} = entity_decode($2) ; -- } -- } -- while ($input =~ /]*)"\s+description="([^>]+)"\/>/sg) { -- $messages{entity_decode_minimal($2)} = []; -- } --} -- --sub type_scheme { -- my ($line, $i, $state, $str, $trcomment, $char); -- for $line (split(/\n/, $input)) { -- $i = 0; -- $state = 0; # 0 - nothing, 1 - string, 2 - translatable string -- while ($i < length($line)) { -- if (substr($line,$i,1) eq "\"") { -- if ($state == 2) { -- $comments{$str} = $trcomment if ($trcomment); -- $messages{$str} = []; -- $str = ''; -- $state = 0; $trcomment = ""; -- } elsif ($state == 1) { -- $str = ''; -- $state = 0; $trcomment = ""; -- } else { -- $state = 1; -- $str = ''; -- if ($i>0 && substr($line,$i-1,1) eq '_') { -- $state = 2; -- } -- } -- } elsif (!$state) { -- if (substr($line,$i,1) eq ";") { -- $trcomment = substr($line,$i+1); -- $trcomment =~ s/^;*\s*//; -- $i = length($line); -- } elsif ($trcomment && substr($line,$i,1) !~ /\s|\(|\)|_/) { -- $trcomment = ""; -- } -- } else { -- if (substr($line,$i,1) eq "\\") { -- $char = substr($line,$i+1,1); -- if ($char ne "\"" && $char ne "\\") { -- $str = $str . "\\"; -- } -- $i++; -- } -- $str = $str . substr($line,$i,1); -- } -- $i++; -- } -- } --} -- --sub msg_write { -- my @msgids; -- if (%count) -- { -- @msgids = sort { $count{$a} <=> $count{$b} } keys %count; -- } -- else -- { -- @msgids = sort keys %messages; -- } -- for my $message (@msgids) -- { -- my $offsetlines = 1; -- $offsetlines++ if $message =~ /%/; -- if (defined ($comments{$message})) -- { -- while ($comments{$message} =~ m/\n/g) -- { -- $offsetlines++; -- } -- } -- print OUT "# ".($loc{$message} - $offsetlines). " \"$FILE\"\n" -- if defined $loc{$message}; -- print OUT "/* ".$comments{$message}." */\n" -- if defined $comments{$message}; -- print OUT "/* xgettext:no-c-format */\n" if $message =~ /%/; -- -- my @lines = split (/\n/, $message, -1); -- for (my $n = 0; $n < @lines; $n++) -- { -- if ($n == 0) -- { -- print OUT "char *s = N_(\""; -- } -- else -- { -- print OUT " \""; -- } -- -- print OUT escape($lines[$n]); -- -- if ($n < @lines - 1) -- { -- print OUT "\\n\"\n"; -- } -- else -- { -- print OUT "\");\n"; -- } -- } -- } --} -- -diff --git a/intltool-extract.in b/intltool-extract.in -new file mode 120000 -index bb6c368..340fc8d ---- /dev/null -+++ b/intltool-extract.in -@@ -0,0 +1 @@ -+/usr/share/intltool/intltool-extract.in -\ No newline at end of file -diff --git a/intltool-merge.in b/intltool-merge.in -deleted file mode 100755 -index d0535ab..2238bbd ---- a/intltool-merge.in -+++ /dev/null -@@ -1,1356 +0,0 @@ --#!@INTLTOOL_PERL@ -w --# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- -- --# --# The Intltool Message Merger --# --# Copyright (C) 2000, 2003 Free Software Foundation. --# Copyright (C) 2000, 2001 Eazel, Inc --# --# Intltool is free software; you can redistribute it and/or --# modify it under the terms of the GNU General Public License --# version 2 published by the Free Software Foundation. --# --# Intltool 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., 675 Mass Ave, Cambridge, MA 02139, USA. --# --# As a special exception to the GNU General Public License, if you --# distribute this file as part of a program that contains a --# configuration script generated by Autoconf, you may include it under --# the same distribution terms that you use for the rest of that program. --# --# Authors: Maciej Stachowiak --# Kenneth Christiansen --# Darin Adler --# --# Proper XML UTF-8'ification written by Cyrille Chepelov --# -- --## Release information --my $PROGRAM = "intltool-merge"; --my $PACKAGE = "intltool"; --my $VERSION = "0.35.0"; -- --## Loaded modules --use strict; --use Getopt::Long; --use Text::Wrap; --use File::Basename; -- --my $must_end_tag = -1; --my $last_depth = -1; --my $translation_depth = -1; --my @tag_stack = (); --my @entered_tag = (); --my @translation_strings = (); --my $leading_space = ""; -- --## Scalars used by the option stuff --my $HELP_ARG = 0; --my $VERSION_ARG = 0; --my $BA_STYLE_ARG = 0; --my $XML_STYLE_ARG = 0; --my $KEYS_STYLE_ARG = 0; --my $DESKTOP_STYLE_ARG = 0; --my $SCHEMAS_STYLE_ARG = 0; --my $RFC822DEB_STYLE_ARG = 0; --my $QUIET_ARG = 0; --my $PASS_THROUGH_ARG = 0; --my $UTF8_ARG = 0; --my $MULTIPLE_OUTPUT = 0; --my $cache_file; -- --## Handle options --GetOptions --( -- "help" => \$HELP_ARG, -- "version" => \$VERSION_ARG, -- "quiet|q" => \$QUIET_ARG, -- "oaf-style|o" => \$BA_STYLE_ARG, ## for compatibility -- "ba-style|b" => \$BA_STYLE_ARG, -- "xml-style|x" => \$XML_STYLE_ARG, -- "keys-style|k" => \$KEYS_STYLE_ARG, -- "desktop-style|d" => \$DESKTOP_STYLE_ARG, -- "schemas-style|s" => \$SCHEMAS_STYLE_ARG, -- "rfc822deb-style|r" => \$RFC822DEB_STYLE_ARG, -- "pass-through|p" => \$PASS_THROUGH_ARG, -- "utf8|u" => \$UTF8_ARG, -- "multiple-output|m" => \$MULTIPLE_OUTPUT, -- "cache|c=s" => \$cache_file -- ) or &error; -- --my $PO_DIR; --my $FILE; --my $OUTFILE; -- --my %po_files_by_lang = (); --my %translations = (); --my $iconv = $ENV{"ICONV"} || $ENV{"INTLTOOL_ICONV"} || "@INTLTOOL_ICONV@"; --my $devnull = ($^O eq 'MSWin32' ? 'NUL:' : '/dev/null'); -- --# Use this instead of \w for XML files to handle more possible characters. --my $w = "[-A-Za-z0-9._:]"; -- --# XML quoted string contents --my $q = "[^\\\"]*"; -- --## Check for options. -- --if ($VERSION_ARG) --{ -- &print_version; --} --elsif ($HELP_ARG) --{ -- &print_help; --} --elsif ($BA_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &ba_merge_translations; -- &finalize; --} --elsif ($XML_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &xml_merge_output; -- &finalize; --} --elsif ($KEYS_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &keys_merge_translations; -- &finalize; --} --elsif ($DESKTOP_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &desktop_merge_translations; -- &finalize; --} --elsif ($SCHEMAS_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &schemas_merge_translations; -- &finalize; --} --elsif ($RFC822DEB_STYLE_ARG && @ARGV > 2) --{ -- &preparation; -- &print_message; -- &rfc822deb_merge_translations; -- &finalize; --} --else --{ -- &print_help; --} -- --exit; -- --## Sub for printing release information --sub print_version --{ -- print <<_EOF_; --${PROGRAM} (${PACKAGE}) ${VERSION} --Written by Maciej Stachowiak, Darin Adler and Kenneth Christiansen. -- --Copyright (C) 2000-2003 Free Software Foundation, Inc. --Copyright (C) 2000-2001 Eazel, Inc. --This is free software; see the source for copying conditions. There is NO --warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. --_EOF_ -- exit; --} -- --## Sub for printing usage information --sub print_help --{ -- print <<_EOF_; --Usage: ${PROGRAM} [OPTION]... PO_DIRECTORY FILENAME OUTPUT_FILE --Generates an output file that includes some localized attributes from an --untranslated source file. -- --Mandatory options: (exactly one must be specified) -- -b, --ba-style includes translations in the bonobo-activation style -- -d, --desktop-style includes translations in the desktop style -- -k, --keys-style includes translations in the keys style -- -s, --schemas-style includes translations in the schemas style -- -r, --rfc822deb-style includes translations in the RFC822 style -- -x, --xml-style includes translations in the standard xml style -- --Other options: -- -u, --utf8 convert all strings to UTF-8 before merging -- (default for everything except RFC822 style) -- -p, --pass-through deprecated, does nothing and issues a warning -- -m, --multiple-output output one localized file per locale, instead of -- a single file containing all localized elements -- -c, --cache=FILE specify cache file name -- (usually \$top_builddir/po/.intltool-merge-cache) -- -q, --quiet suppress most messages -- --help display this help and exit -- --version output version information and exit -- --Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE") --or send email to . --_EOF_ -- exit; --} -- -- --## Sub for printing error messages --sub print_error --{ -- print STDERR "Try `${PROGRAM} --help' for more information.\n"; -- exit; --} -- -- --sub print_message --{ -- print "Merging translations into $OUTFILE.\n" unless $QUIET_ARG; --} -- -- --sub preparation --{ -- $PO_DIR = $ARGV[0]; -- $FILE = $ARGV[1]; -- $OUTFILE = $ARGV[2]; -- -- &gather_po_files; -- &get_translation_database; --} -- --# General-purpose code for looking up translations in .po files -- --sub po_file2lang --{ -- my ($tmp) = @_; -- $tmp =~ s/^.*\/(.*)\.po$/$1/; -- return $tmp; --} -- --sub gather_po_files --{ -- for my $po_file (glob "$PO_DIR/*.po") { -- $po_files_by_lang{po_file2lang($po_file)} = $po_file; -- } --} -- --sub get_local_charset --{ -- my ($encoding) = @_; -- my $alias_file = $ENV{"G_CHARSET_ALIAS"} || "@INTLTOOL_LIBDIR@/charset.alias"; -- -- # seek character encoding aliases in charset.alias (glib) -- -- if (open CHARSET_ALIAS, $alias_file) -- { -- while () -- { -- next if /^\#/; -- return $1 if (/^\s*([-._a-zA-Z0-9]+)\s+$encoding\b/i) -- } -- -- close CHARSET_ALIAS; -- } -- -- # if not found, return input string -- -- return $encoding; --} -- --sub get_po_encoding --{ -- my ($in_po_file) = @_; -- my $encoding = ""; -- -- open IN_PO_FILE, $in_po_file or die; -- while () -- { -- ## example: "Content-Type: text/plain; charset=ISO-8859-1\n" -- if (/Content-Type\:.*charset=([-a-zA-Z0-9]+)\\n/) -- { -- $encoding = $1; -- last; -- } -- } -- close IN_PO_FILE; -- -- if (!$encoding) -- { -- print STDERR "Warning: no encoding found in $in_po_file. Assuming ISO-8859-1\n" unless $QUIET_ARG; -- $encoding = "ISO-8859-1"; -- } -- -- system ("$iconv -f $encoding -t UTF-8 <$devnull 2>$devnull"); -- if ($?) { -- $encoding = get_local_charset($encoding); -- } -- -- return $encoding --} -- --sub utf8_sanity_check --{ -- print STDERR "Warning: option --pass-through has been removed.\n" if $PASS_THROUGH_ARG; -- $UTF8_ARG = 1; --} -- --sub get_translation_database --{ -- if ($cache_file) { -- &get_cached_translation_database; -- } else { -- &create_translation_database; -- } --} -- --sub get_newest_po_age --{ -- my $newest_age; -- -- foreach my $file (values %po_files_by_lang) -- { -- my $file_age = -M $file; -- $newest_age = $file_age if !$newest_age || $file_age < $newest_age; -- } -- -- $newest_age = 0 if !$newest_age; -- -- return $newest_age; --} -- --sub create_cache --{ -- print "Generating and caching the translation database\n" unless $QUIET_ARG; -- -- &create_translation_database; -- -- open CACHE, ">$cache_file" || die; -- print CACHE join "\x01", %translations; -- close CACHE; --} -- --sub load_cache --{ -- print "Found cached translation database\n" unless $QUIET_ARG; -- -- my $contents; -- open CACHE, "<$cache_file" || die; -- { -- local $/; -- $contents = ; -- } -- close CACHE; -- %translations = split "\x01", $contents; --} -- --sub get_cached_translation_database --{ -- my $cache_file_age = -M $cache_file; -- if (defined $cache_file_age) -- { -- if ($cache_file_age <= &get_newest_po_age) -- { -- &load_cache; -- return; -- } -- print "Found too-old cached translation database\n" unless $QUIET_ARG; -- } -- -- &create_cache; --} -- --sub create_translation_database --{ -- for my $lang (keys %po_files_by_lang) -- { -- my $po_file = $po_files_by_lang{$lang}; -- -- if ($UTF8_ARG) -- { -- my $encoding = get_po_encoding ($po_file); -- -- if (lc $encoding eq "utf-8") -- { -- open PO_FILE, "<$po_file"; -- } -- else -- { -- print "NOTICE: $po_file is not in UTF-8 but $encoding, converting...\n" unless $QUIET_ARG;; -- -- open PO_FILE, "$iconv -f $encoding -t UTF-8 $po_file|"; -- } -- } -- else -- { -- open PO_FILE, "<$po_file"; -- } -- -- my $nextfuzzy = 0; -- my $inmsgid = 0; -- my $inmsgstr = 0; -- my $msgid = ""; -- my $msgstr = ""; -- -- while () -- { -- $nextfuzzy = 1 if /^#, fuzzy/; -- -- if (/^msgid "((\\.|[^\\])*)"/ ) -- { -- $translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr; -- $msgid = ""; -- $msgstr = ""; -- -- if ($nextfuzzy) { -- $inmsgid = 0; -- } else { -- $msgid = unescape_po_string($1); -- $inmsgid = 1; -- } -- $inmsgstr = 0; -- $nextfuzzy = 0; -- } -- -- if (/^msgstr "((\\.|[^\\])*)"/) -- { -- $msgstr = unescape_po_string($1); -- $inmsgstr = 1; -- $inmsgid = 0; -- } -- -- if (/^"((\\.|[^\\])*)"/) -- { -- $msgid .= unescape_po_string($1) if $inmsgid; -- $msgstr .= unescape_po_string($1) if $inmsgstr; -- } -- } -- $translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr; -- } --} -- --sub finalize --{ --} -- --sub unescape_one_sequence --{ -- my ($sequence) = @_; -- -- return "\\" if $sequence eq "\\\\"; -- return "\"" if $sequence eq "\\\""; -- return "\n" if $sequence eq "\\n"; -- return "\r" if $sequence eq "\\r"; -- return "\t" if $sequence eq "\\t"; -- return "\b" if $sequence eq "\\b"; -- return "\f" if $sequence eq "\\f"; -- return "\a" if $sequence eq "\\a"; -- return chr(11) if $sequence eq "\\v"; # vertical tab, see ascii(7) -- -- return chr(hex($1)) if ($sequence =~ /\\x([0-9a-fA-F]{2})/); -- return chr(oct($1)) if ($sequence =~ /\\([0-7]{3})/); -- -- # FIXME: Is \0 supported as well? Kenneth and Rodney don't want it, see bug #48489 -- -- return $sequence; --} -- --sub unescape_po_string --{ -- my ($string) = @_; -- -- $string =~ s/(\\x[0-9a-fA-F]{2}|\\[0-7]{3}|\\.)/unescape_one_sequence($1)/eg; -- -- return $string; --} -- --## NOTE: deal with < - < but not > - > because it seems its ok to have --## > in the entity. For further info please look at #84738. --sub entity_decode --{ -- local ($_) = @_; -- -- s/'/'/g; # ' -- s/"/"/g; # " -- s/&/&/g; -- s/</; -- close INPUT; -- } -- -- open OUTPUT, ">$OUTFILE" or die "can't open $OUTFILE: $!"; -- # Binmode so that selftest works ok if using a native Win32 Perl... -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- while ($source =~ s|^(.*?)([ \t]*<\s*$w+\s+($w+\s*=\s*"$q"\s*)+/?>)([ \t]*\n)?||s) -- { -- print OUTPUT $1; -- -- my $node = $2 . "\n"; -- -- my @strings = (); -- $_ = $node; -- while (s/(\s)_($w+\s*=\s*"($q)")/$1$2/s) { -- push @strings, entity_decode($3); -- } -- print OUTPUT; -- -- my %langs; -- for my $string (@strings) -- { -- for my $lang (keys %po_files_by_lang) -- { -- $langs{$lang} = 1 if $translations{$lang, $string}; -- } -- } -- -- for my $lang (sort keys %langs) -- { -- $_ = $node; -- s/(\sname\s*=\s*)"($q)"/$1"$2-$lang"/s; -- s/(\s)_($w+\s*=\s*")($q)"/$1 . $2 . entity_encoded_translation($lang, $3) . '"'/seg; -- print OUTPUT; -- } -- } -- -- print OUTPUT $source; -- -- close OUTPUT; --} -- -- --## XML (non-bonobo-activation) merge code -- -- --# Process tag attributes --# Only parameter is a HASH containing attributes -> values mapping --sub getAttributeString --{ -- my $sub = shift; -- my $do_translate = shift || 0; -- my $language = shift || ""; -- my $result = ""; -- my $translate = shift; -- foreach my $e (reverse(sort(keys %{ $sub }))) { -- my $key = $e; -- my $string = $sub->{$e}; -- my $quote = '"'; -- -- $string =~ s/^[\s]+//; -- $string =~ s/[\s]+$//; -- -- if ($string =~ /^'.*'$/) -- { -- $quote = "'"; -- } -- $string =~ s/^['"]//g; -- $string =~ s/['"]$//g; -- -- if ($do_translate && $key =~ /^_/) { -- $key =~ s|^_||g; -- if ($language) { -- # Handle translation -- my $decode_string = entity_decode($string); -- my $translation = $translations{$language, $decode_string}; -- if ($translation) { -- $translation = entity_encode($translation); -- $string = $translation; -- } -- $$translate = 2; -- } else { -- $$translate = 2 if ($translate && (!$$translate)); # watch not to "overwrite" $translate -- } -- } -- -- $result .= " $key=$quote$string$quote"; -- } -- return $result; --} -- --# Returns a translatable string from XML node, it works on contents of every node in XML::Parser tree --sub getXMLstring --{ -- my $ref = shift; -- my $spacepreserve = shift || 0; -- my @list = @{ $ref }; -- my $result = ""; -- -- my $count = scalar(@list); -- my $attrs = $list[0]; -- my $index = 1; -- -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); -- -- while ($index < $count) { -- my $type = $list[$index]; -- my $content = $list[$index+1]; -- if (! $type ) { -- # We've got CDATA -- if ($content) { -- # lets strip the whitespace here, and *ONLY* here -- $content =~ s/\s+/ /gs if (!$spacepreserve); -- $result .= $content; -- } -- } elsif ( "$type" ne "1" ) { -- # We've got another element -- $result .= "<$type"; -- $result .= getAttributeString(@{$content}[0], 0); # no nested translatable elements -- if ($content) { -- my $subresult = getXMLstring($content, $spacepreserve); -- if ($subresult) { -- $result .= ">".$subresult . ""; -- } else { -- $result .= "/>"; -- } -- } else { -- $result .= "/>"; -- } -- } -- $index += 2; -- } -- return $result; --} -- --# Translate list of nodes if necessary --sub translate_subnodes --{ -- my $fh = shift; -- my $content = shift; -- my $language = shift || ""; -- my $singlelang = shift || 0; -- my $spacepreserve = shift || 0; -- -- my @nodes = @{ $content }; -- -- my $count = scalar(@nodes); -- my $index = 0; -- while ($index < $count) { -- my $type = $nodes[$index]; -- my $rest = $nodes[$index+1]; -- if ($singlelang) { -- my $oldMO = $MULTIPLE_OUTPUT; -- $MULTIPLE_OUTPUT = 1; -- traverse($fh, $type, $rest, $language, $spacepreserve); -- $MULTIPLE_OUTPUT = $oldMO; -- } else { -- traverse($fh, $type, $rest, $language, $spacepreserve); -- } -- $index += 2; -- } --} -- --sub isWellFormedXmlFragment --{ -- my $ret = eval 'require XML::Parser'; -- if(!$ret) { -- die "You must have XML::Parser installed to run $0\n\n"; -- } -- -- my $fragment = shift; -- return 0 if (!$fragment); -- -- $fragment = "$fragment"; -- my $xp = new XML::Parser(Style => 'Tree'); -- my $tree = 0; -- eval { $tree = $xp->parse($fragment); }; -- return $tree; --} -- --sub traverse --{ -- my $fh = shift; -- my $nodename = shift; -- my $content = shift; -- my $language = shift || ""; -- my $spacepreserve = shift || 0; -- -- if (!$nodename) { -- if ($content =~ /^[\s]*$/) { -- $leading_space .= $content; -- } -- print $fh $content; -- } else { -- # element -- my @all = @{ $content }; -- my $attrs = shift @all; -- my $translate = 0; -- my $outattr = getAttributeString($attrs, 1, $language, \$translate); -- -- if ($nodename =~ /^_/) { -- $translate = 1; -- $nodename =~ s/^_//; -- } -- my $lookup = ''; -- -- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- -- print $fh "<$nodename", $outattr; -- if ($translate) { -- $lookup = getXMLstring($content, $spacepreserve); -- if (!$spacepreserve) { -- $lookup =~ s/^\s+//s; -- $lookup =~ s/\s+$//s; -- } -- -- if ($lookup || $translate == 2) { -- my $translation = $translations{$language, $lookup} if isWellFormedXmlFragment($translations{$language, $lookup}); -- if ($MULTIPLE_OUTPUT && ($translation || $translate == 2)) { -- $translation = $lookup if (!$translation); -- print $fh " xml:lang=\"", $language, "\"" if $language; -- print $fh ">"; -- if ($translate == 2) { -- translate_subnodes($fh, \@all, $language, 1, $spacepreserve); -- } else { -- print $fh $translation; -- } -- print $fh ""; -- -- return; # this means there will be no same translation with xml:lang="$language"... -- # if we want them both, just remove this "return" -- } else { -- print $fh ">"; -- if ($translate == 2) { -- translate_subnodes($fh, \@all, $language, 1, $spacepreserve); -- } else { -- print $fh $lookup; -- } -- print $fh ""; -- } -- } else { -- print $fh "/>"; -- } -- -- for my $lang (sort keys %po_files_by_lang) { -- if ($MULTIPLE_OUTPUT && $lang ne "$language") { -- next; -- } -- if ($lang) { -- # Handle translation -- # -- my $translate = 0; -- my $localattrs = getAttributeString($attrs, 1, $lang, \$translate); -- my $translation = $translations{$lang, $lookup} if isWellFormedXmlFragment($translations{$lang, $lookup}); -- if ($translate && !$translation) { -- $translation = $lookup; -- } -- -- if ($translation || $translate) { -- print $fh "\n"; -- $leading_space =~ s/.*\n//g; -- print $fh $leading_space; -- print $fh "<", $nodename, " xml:lang=\"", $lang, "\"", $localattrs, ">"; -- if ($translate == 2) { -- translate_subnodes($fh, \@all, $lang, 1, $spacepreserve); -- } else { -- print $fh $translation; -- } -- print $fh ""; -- } -- } -- } -- -- } else { -- my $count = scalar(@all); -- if ($count > 0) { -- print $fh ">"; -- my $index = 0; -- while ($index < $count) { -- my $type = $all[$index]; -- my $rest = $all[$index+1]; -- traverse($fh, $type, $rest, $language, $spacepreserve); -- $index += 2; -- } -- print $fh ""; -- } else { -- print $fh "/>"; -- } -- } -- } --} -- --sub intltool_tree_comment --{ -- my $expat = shift; -- my $data = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- push @$clist, 1 => $data; --} -- --sub intltool_tree_cdatastart --{ -- my $expat = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- push @$clist, 0 => $expat->original_string(); --} -- --sub intltool_tree_cdataend --{ -- my $expat = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- $clist->[$pos] .= $expat->original_string(); --} -- --sub intltool_tree_char --{ -- my $expat = shift; -- my $text = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- # Use original_string so that we retain escaped entities -- # in CDATA sections. -- # -- if ($pos > 0 and $clist->[$pos - 1] eq '0') { -- $clist->[$pos] .= $expat->original_string(); -- } else { -- push @$clist, 0 => $expat->original_string(); -- } --} -- --sub intltool_tree_start --{ -- my $expat = shift; -- my $tag = shift; -- my @origlist = (); -- -- # Use original_string so that we retain escaped entities -- # in attribute values. We must convert the string to an -- # @origlist array to conform to the structure of the Tree -- # Style. -- # -- my @original_array = split /\x/, $expat->original_string(); -- my $source = $expat->original_string(); -- -- # Remove leading tag. -- # -- $source =~ s|^\s*<\s*(\S+)||s; -- -- # Grab attribute key/value pairs and push onto @origlist array. -- # -- while ($source) -- { -- if ($source =~ /^\s*([\w:-]+)\s*[=]\s*["]/) -- { -- $source =~ s|^\s*([\w:-]+)\s*[=]\s*["]([^"]*)["]||s; -- push @origlist, $1; -- push @origlist, '"' . $2 . '"'; -- } -- elsif ($source =~ /^\s*([\w:-]+)\s*[=]\s*[']/) -- { -- $source =~ s|^\s*([\w:-]+)\s*[=]\s*[']([^']*)[']||s; -- push @origlist, $1; -- push @origlist, "'" . $2 . "'"; -- } -- else -- { -- last; -- } -- } -- -- my $ol = [ { @origlist } ]; -- -- push @{ $expat->{Lists} }, $expat->{Curlist}; -- push @{ $expat->{Curlist} }, $tag => $ol; -- $expat->{Curlist} = $ol; --} -- --sub readXml --{ -- my $filename = shift || return; -- if(!-f $filename) { -- die "ERROR Cannot find filename: $filename\n"; -- } -- -- my $ret = eval 'require XML::Parser'; -- if(!$ret) { -- die "You must have XML::Parser installed to run $0\n\n"; -- } -- my $xp = new XML::Parser(Style => 'Tree'); -- $xp->setHandlers(Char => \&intltool_tree_char); -- $xp->setHandlers(Start => \&intltool_tree_start); -- $xp->setHandlers(CdataStart => \&intltool_tree_cdatastart); -- $xp->setHandlers(CdataEnd => \&intltool_tree_cdataend); -- my $tree = $xp->parsefile($filename); -- --# Hello thereHowdydo --# would be: --# [foo, [{}, head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]], bar, [{}, --# 0, "Howdy", ref, [{}]], 0, "do" ] ] -- -- return $tree; --} -- --sub print_header --{ -- my $infile = shift; -- my $fh = shift; -- my $source; -- -- if(!-f $infile) { -- die "ERROR Cannot find filename: $infile\n"; -- } -- -- print $fh qq{\n}; -- { -- local $/; -- open DOCINPUT, "<${FILE}" or die; -- $source = ; -- close DOCINPUT; -- } -- if ($source =~ /()/s) -- { -- print $fh "$1\n"; -- } -- elsif ($source =~ /(]*>)/s) -- { -- print $fh "$1\n"; -- } --} -- --sub parseTree --{ -- my $fh = shift; -- my $ref = shift; -- my $language = shift || ""; -- -- my $name = shift @{ $ref }; -- my $cont = shift @{ $ref }; -- -- while (!$name || "$name" eq "1") { -- $name = shift @{ $ref }; -- $cont = shift @{ $ref }; -- } -- -- my $spacepreserve = 0; -- my $attrs = @{$cont}[0]; -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- -- traverse($fh, $name, $cont, $language, $spacepreserve); --} -- --sub xml_merge_output --{ -- my $source; -- -- if ($MULTIPLE_OUTPUT) { -- for my $lang (sort keys %po_files_by_lang) { -- if ( ! -e $lang ) { -- mkdir $lang or die "Cannot create subdirectory $lang: $!\n"; -- } -- open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n"; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- my $tree = readXml($FILE); -- print_header($FILE, \*OUTPUT); -- parseTree(\*OUTPUT, $tree, $lang); -- close OUTPUT; -- print "CREATED $lang/$OUTFILE\n" unless $QUIET_ARG; -- } -- } -- open OUTPUT, ">$OUTFILE" or die "Cannot open $OUTFILE: $!\n"; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- my $tree = readXml($FILE); -- print_header($FILE, \*OUTPUT); -- parseTree(\*OUTPUT, $tree); -- close OUTPUT; -- print "CREATED $OUTFILE\n" unless $QUIET_ARG; --} -- --sub keys_merge_translations --{ -- open INPUT, "<${FILE}" or die; -- open OUTPUT, ">${OUTFILE}" or die; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- while () -- { -- if (s/^(\s*)_(\w+=(.*))/$1$2/) -- { -- my $string = $3; -- -- print OUTPUT; -- -- my $non_translated_line = $_; -- -- for my $lang (sort keys %po_files_by_lang) -- { -- my $translation = $translations{$lang, $string}; -- next if !$translation; -- -- $_ = $non_translated_line; -- s/(\w+)=.*/[$lang]$1=$translation/; -- print OUTPUT; -- } -- } -- else -- { -- print OUTPUT; -- } -- } -- -- close OUTPUT; -- close INPUT; --} -- --sub desktop_merge_translations --{ -- open INPUT, "<${FILE}" or die; -- open OUTPUT, ">${OUTFILE}" or die; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- while () -- { -- if (s/^(\s*)_(\w+=(.*))/$1$2/) -- { -- my $string = $3; -- -- print OUTPUT; -- -- my $non_translated_line = $_; -- -- for my $lang (sort keys %po_files_by_lang) -- { -- my $translation = $translations{$lang, $string}; -- next if !$translation; -- -- $_ = $non_translated_line; -- s/(\w+)=.*/${1}[$lang]=$translation/; -- print OUTPUT; -- } -- } -- else -- { -- print OUTPUT; -- } -- } -- -- close OUTPUT; -- close INPUT; --} -- --sub schemas_merge_translations --{ -- my $source; -- -- { -- local $/; # slurp mode -- open INPUT, "<$FILE" or die "can't open $FILE: $!"; -- $source = ; -- close INPUT; -- } -- -- open OUTPUT, ">$OUTFILE" or die; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- # FIXME: support attribute translations -- -- # Empty nodes never need translation, so unmark all of them. -- # For example, <_foo/> is just replaced by . -- $source =~ s|<\s*_($w+)\s*/>|<$1/>|g; -- -- while ($source =~ s/ -- (.*?) -- (\s+)((\s*) -- (\s*(?:\s*)?(.*?)\s*<\/default>)?(\s*) -- (\s*(?:\s*)?(.*?)\s*<\/short>)?(\s*) -- (\s*(?:\s*)?(.*?)\s*<\/long>)?(\s*) -- <\/locale>) -- //sx) -- { -- print OUTPUT $1; -- -- my $locale_start_spaces = $2 ? $2 : ''; -- my $default_spaces = $4 ? $4 : ''; -- my $short_spaces = $7 ? $7 : ''; -- my $long_spaces = $10 ? $10 : ''; -- my $locale_end_spaces = $13 ? $13 : ''; -- my $c_default_block = $3 ? $3 : ''; -- my $default_string = $6 ? $6 : ''; -- my $short_string = $9 ? $9 : ''; -- my $long_string = $12 ? $12 : ''; -- -- print OUTPUT "$locale_start_spaces$c_default_block"; -- -- $default_string =~ s/\s+/ /g; -- $default_string = entity_decode($default_string); -- $short_string =~ s/\s+/ /g; -- $short_string = entity_decode($short_string); -- $long_string =~ s/\s+/ /g; -- $long_string = entity_decode($long_string); -- -- for my $lang (sort keys %po_files_by_lang) -- { -- my $default_translation = $translations{$lang, $default_string}; -- my $short_translation = $translations{$lang, $short_string}; -- my $long_translation = $translations{$lang, $long_string}; -- -- next if (!$default_translation && !$short_translation && -- !$long_translation); -- -- print OUTPUT "\n$locale_start_spaces"; -- -- print OUTPUT "$default_spaces"; -- -- if ($default_translation) -- { -- $default_translation = entity_encode($default_translation); -- print OUTPUT "$default_translation"; -- } -- -- print OUTPUT "$short_spaces"; -- -- if ($short_translation) -- { -- $short_translation = entity_encode($short_translation); -- print OUTPUT "$short_translation"; -- } -- -- print OUTPUT "$long_spaces"; -- -- if ($long_translation) -- { -- $long_translation = entity_encode($long_translation); -- print OUTPUT "$long_translation"; -- } -- -- print OUTPUT "$locale_end_spaces"; -- } -- } -- -- print OUTPUT $source; -- -- close OUTPUT; --} -- --sub rfc822deb_merge_translations --{ -- my %encodings = (); -- for my $lang (keys %po_files_by_lang) { -- $encodings{$lang} = ($UTF8_ARG ? 'UTF-8' : get_po_encoding($po_files_by_lang{$lang})); -- } -- -- my $source; -- -- $Text::Wrap::huge = 'overflow'; -- $Text::Wrap::break = qr/\n|\s(?=\S)/; -- -- { -- local $/; # slurp mode -- open INPUT, "<$FILE" or die "can't open $FILE: $!"; -- $source = ; -- close INPUT; -- } -- -- open OUTPUT, ">${OUTFILE}" or die; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- while ($source =~ /(^|\n+)(_*)([^:\s]+)(:[ \t]*)(.*?)(?=\n[\S\n]|$)/sg) -- { -- my $sep = $1; -- my $non_translated_line = $3.$4; -- my $string = $5; -- my $underscore = length($2); -- next if $underscore eq 0 && $non_translated_line =~ /^#/; -- # Remove [] dummy strings -- my $stripped = $string; -- $stripped =~ s/\[\s[^\[\]]*\],/,/g if $underscore eq 2; -- $stripped =~ s/\[\s[^\[\]]*\]$//; -- $non_translated_line .= $stripped; -- -- print OUTPUT $sep.$non_translated_line; -- -- if ($underscore) -- { -- my @str_list = rfc822deb_split($underscore, $string); -- -- for my $lang (sort keys %po_files_by_lang) -- { -- my $is_translated = 1; -- my $str_translated = ''; -- my $first = 1; -- -- for my $str (@str_list) -- { -- my $translation = $translations{$lang, $str}; -- -- if (!$translation) -- { -- $is_translated = 0; -- last; -- } -- -- # $translation may also contain [] dummy -- # strings, mostly to indicate an empty string -- $translation =~ s/\[\s[^\[\]]*\]$//; -- -- if ($first) -- { -- if ($underscore eq 2) -- { -- $str_translated .= $translation; -- } -- else -- { -- $str_translated .= -- Text::Tabs::expand($translation) . -- "\n"; -- } -- } -- else -- { -- if ($underscore eq 2) -- { -- $str_translated .= ', ' . $translation; -- } -- else -- { -- $str_translated .= Text::Tabs::expand( -- Text::Wrap::wrap(' ', ' ', $translation)) . -- "\n .\n"; -- } -- } -- $first = 0; -- -- # To fix some problems with Text::Wrap::wrap -- $str_translated =~ s/(\n )+\n/\n .\n/g; -- } -- next unless $is_translated; -- -- $str_translated =~ s/\n \.\n$//; -- $str_translated =~ s/\s+$//; -- -- $_ = $non_translated_line; -- s/^(\w+):\s*.*/$sep${1}-$lang.$encodings{$lang}: $str_translated/s; -- print OUTPUT; -- } -- } -- } -- print OUTPUT "\n"; -- -- close OUTPUT; -- close INPUT; --} -- --sub rfc822deb_split --{ -- # Debian defines a special way to deal with rfc822-style files: -- # when a value contain newlines, it consists of -- # 1. a short form (first line) -- # 2. a long description, all lines begin with a space, -- # and paragraphs are separated by a single dot on a line -- # This routine returns an array of all paragraphs, and reformat -- # them. -- # When first argument is 2, the string is a comma separated list of -- # values. -- my $type = shift; -- my $text = shift; -- $text =~ s/^[ \t]//mg; -- return (split(/, */, $text, 0)) if $type ne 1; -- return ($text) if $text !~ /\n/; -- -- $text =~ s/([^\n]*)\n//; -- my @list = ($1); -- my $str = ''; -- -- for my $line (split (/\n/, $text)) -- { -- chomp $line; -- if ($line =~ /^\.\s*$/) -- { -- # New paragraph -- $str =~ s/\s*$//; -- push(@list, $str); -- $str = ''; -- } -- elsif ($line =~ /^\s/) -- { -- # Line which must not be reformatted -- $str .= "\n" if length ($str) && $str !~ /\n$/; -- $line =~ s/\s+$//; -- $str .= $line."\n"; -- } -- else -- { -- # Continuation line, remove newline -- $str .= " " if length ($str) && $str !~ /\n$/; -- $str .= $line; -- } -- } -- -- $str =~ s/\s*$//; -- push(@list, $str) if length ($str); -- -- return @list; --} -- -diff --git a/intltool-merge.in b/intltool-merge.in -new file mode 120000 -index d0535ab..2238bbd ---- /dev/null -+++ b/intltool-merge.in -@@ -0,0 +1 @@ -+/usr/share/intltool/intltool-merge.in -\ No newline at end of file -diff --git a/intltool-update.in b/intltool-update.in -deleted file mode 100755 -index 661d8fe..0b1800f ---- a/intltool-update.in -+++ /dev/null -@@ -1,1089 +0,0 @@ --#!@INTLTOOL_PERL@ -w --# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- -- --# --# The Intltool Message Updater --# --# Copyright (C) 2000-2003 Free Software Foundation. --# --# Intltool is free software; you can redistribute it and/or --# modify it under the terms of the GNU General Public License --# version 2 published by the Free Software Foundation. --# --# Intltool 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., 675 Mass Ave, Cambridge, MA 02139, USA. --# --# As a special exception to the GNU General Public License, if you --# distribute this file as part of a program that contains a --# configuration script generated by Autoconf, you may include it under --# the same distribution terms that you use for the rest of that program. --# --# Authors: Kenneth Christiansen --# Maciej Stachowiak --# Darin Adler -- --## Release information --my $PROGRAM = "intltool-update"; --my $VERSION = "0.35.0"; --my $PACKAGE = "intltool"; -- --## Loaded modules --use strict; --use Getopt::Long; --use Cwd; --use File::Copy; --use File::Find; -- --## Scalars used by the option stuff --my $HELP_ARG = 0; --my $VERSION_ARG = 0; --my $DIST_ARG = 0; --my $POT_ARG = 0; --my $HEADERS_ARG = 0; --my $MAINTAIN_ARG = 0; --my $REPORT_ARG = 0; --my $VERBOSE = 0; --my $GETTEXT_PACKAGE = ""; --my $OUTPUT_FILE = ""; -- --my @languages; --my %varhash = (); --my %po_files_by_lang = (); -- --# Regular expressions to categorize file types. --# FIXME: Please check if the following is correct -- --my $xml_support = --"xml(?:\\.in)*|". # http://www.w3.org/XML/ (Note: .in is not required) --"ui|". # Bonobo specific - User Interface desc. files --"lang|". # ? --"glade2?(?:\\.in)*|". # Glade specific - User Interface desc. files (Note: .in is not required) --"scm(?:\\.in)*|". # ? (Note: .in is not required) --"oaf(?:\\.in)+|". # DEPRECATED: Replaces by Bonobo .server files --"etspec|". # ? --"server(?:\\.in)+|". # Bonobo specific --"sheet(?:\\.in)+|". # ? --"schemas(?:\\.in)+|". # GConf specific --"pong(?:\\.in)+|". # DEPRECATED: PONG is not used [by GNOME] any longer. --"kbd(?:\\.in)+"; # GOK specific. -- --my $ini_support = --"icon(?:\\.in)+|". # http://www.freedesktop.org/Standards/icon-theme-spec --"desktop(?:\\.in)+|". # http://www.freedesktop.org/Standards/menu-spec --"caves(?:\\.in)+|". # GNOME Games specific --"directory(?:\\.in)+|". # http://www.freedesktop.org/Standards/menu-spec --"soundlist(?:\\.in)+|". # GNOME specific --"keys(?:\\.in)+|". # GNOME Mime database specific --"theme(?:\\.in)+|". # http://www.freedesktop.org/Standards/icon-theme-spec --"service(?:\\.in)+"; # DBus specific -- --my $buildin_gettext_support = --"c|y|cs|cc|cpp|c\\+\\+|h|hh|gob|py"; -- --## Always flush buffer when printing --$| = 1; -- --## Sometimes the source tree will be rooted somewhere else. --my $SRCDIR = "."; --my $POTFILES_in; -- --$SRCDIR = $ENV{"srcdir"} if $ENV{"srcdir"}; --$POTFILES_in = "<$SRCDIR/POTFILES.in"; -- --my $devnull = ($^O eq 'MSWin32' ? 'NUL:' : '/dev/null'); -- --## Handle options --GetOptions --( -- "help" => \$HELP_ARG, -- "version" => \$VERSION_ARG, -- "dist|d" => \$DIST_ARG, -- "pot|p" => \$POT_ARG, -- "headers|s" => \$HEADERS_ARG, -- "maintain|m" => \$MAINTAIN_ARG, -- "report|r" => \$REPORT_ARG, -- "verbose|x" => \$VERBOSE, -- "gettext-package|g=s" => \$GETTEXT_PACKAGE, -- "output-file|o=s" => \$OUTPUT_FILE, -- ) or &Console_WriteError_InvalidOption; -- --&Console_Write_IntltoolHelp if $HELP_ARG; --&Console_Write_IntltoolVersion if $VERSION_ARG; -- --my $arg_count = ($DIST_ARG > 0) -- + ($POT_ARG > 0) -- + ($HEADERS_ARG > 0) -- + ($MAINTAIN_ARG > 0) -- + ($REPORT_ARG > 0); -- --&Console_Write_IntltoolHelp if $arg_count > 1; -- --# --version and --help don't require a module name --my $MODULE = $GETTEXT_PACKAGE || &FindPackageName || "unknown"; -- --if ($POT_ARG) --{ -- &GenerateHeaders; -- &GeneratePOTemplate; --} --elsif ($HEADERS_ARG) --{ -- &GenerateHeaders; --} --elsif ($MAINTAIN_ARG) --{ -- &FindLeftoutFiles; --} --elsif ($REPORT_ARG) --{ -- &GenerateHeaders; -- &GeneratePOTemplate; -- &Console_Write_CoverageReport; --} --elsif ((defined $ARGV[0]) && $ARGV[0] =~ /^[a-z]/) --{ -- my $lang = $ARGV[0]; -- -- ## Report error if the language file supplied -- ## to the command line is non-existent -- &Console_WriteError_NotExisting("$SRCDIR/$lang.po") -- if ! -s "$SRCDIR/$lang.po"; -- -- if (!$DIST_ARG) -- { -- print "Working, please wait..." if $VERBOSE; -- &GenerateHeaders; -- &GeneratePOTemplate; -- } -- &POFile_Update ($lang, $OUTPUT_FILE); -- &Console_Write_TranslationStatus ($lang, $OUTPUT_FILE); --} --else --{ -- &Console_Write_IntltoolHelp; --} -- --exit; -- --######### -- --sub Console_Write_IntltoolVersion --{ -- print <<_EOF_; --${PROGRAM} (${PACKAGE}) $VERSION --Written by Kenneth Christiansen, Maciej Stachowiak, and Darin Adler. -- --Copyright (C) 2000-2003 Free Software Foundation, Inc. --This is free software; see the source for copying conditions. There is NO --warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. --_EOF_ -- exit; --} -- --sub Console_Write_IntltoolHelp --{ -- print <<_EOF_; --Usage: ${PROGRAM} [OPTION]... LANGCODE --Updates PO template files and merge them with the translations. -- --Mode of operation (only one is allowed): -- -p, --pot generate the PO template only -- -s, --headers generate the header files in POTFILES.in -- -m, --maintain search for left out files from POTFILES.in -- -r, --report display a status report for the module -- -d, --dist merge LANGCODE.po with existing PO template -- --Extra options: -- -g, --gettext-package=NAME override PO template name, useful with --pot -- -o, --output-file=FILE write merged translation to FILE -- -x, --verbose display lots of feedback -- --help display this help and exit -- --version output version information and exit -- --Examples of use: --${PROGRAM} --pot just create a new PO template --${PROGRAM} xy create new PO template and merge xy.po with it -- --Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE") --or send email to . --_EOF_ -- exit; --} -- --sub echo_n --{ -- my $str = shift; -- my $ret = `echo "$str"`; -- -- $ret =~ s/\n$//; # do we need the "s" flag? -- -- return $ret; --} -- --sub POFile_DetermineType ($) --{ -- my $type = $_; -- my $gettext_type; -- -- my $xml_regex = "(?:" . $xml_support . ")"; -- my $ini_regex = "(?:" . $ini_support . ")"; -- my $buildin_regex = "(?:" . $buildin_gettext_support . ")"; -- -- if ($type =~ /\[type: gettext\/([^\]].*)]/) -- { -- $gettext_type=$1; -- } -- elsif ($type =~ /schemas(\.in)+$/) -- { -- $gettext_type="schemas"; -- } -- elsif ($type =~ /glade2?(\.in)*$/) -- { -- $gettext_type="glade"; -- } -- elsif ($type =~ /scm(\.in)*$/) -- { -- $gettext_type="scheme"; -- } -- elsif ($type =~ /keys(\.in)+$/) -- { -- $gettext_type="keys"; -- } -- -- # bucket types -- -- elsif ($type =~ /$xml_regex$/) -- { -- $gettext_type="xml"; -- } -- elsif ($type =~ /$ini_regex$/) -- { -- $gettext_type="ini"; -- } -- elsif ($type =~ /$buildin_regex$/) -- { -- $gettext_type="buildin"; -- } -- else -- { -- $gettext_type="unknown"; -- } -- -- return "gettext\/$gettext_type"; --} -- --sub TextFile_DetermineEncoding ($) --{ -- my $gettext_code="ASCII"; # All files are ASCII by default -- my $filetype=`file $_ | cut -d ' ' -f 2`; -- -- if ($? eq "0") -- { -- if ($filetype =~ /^(ISO|UTF)/) -- { -- chomp ($gettext_code = $filetype); -- } -- elsif ($filetype =~ /^XML/) -- { -- $gettext_code="UTF-8"; # We asume that .glade and other .xml files are UTF-8 -- } -- } -- -- return $gettext_code; --} -- --sub isNotValidMissing --{ -- my ($file) = @_; -- -- return if $file =~ /^\{arch\}\/.*$/; -- return if $file =~ /^$varhash{"PACKAGE"}-$varhash{"VERSION"}\/.*$/; --} -- --sub FindLeftoutFiles --{ -- my (@buf_i18n_plain, -- @buf_i18n_xml, -- @buf_i18n_xml_unmarked, -- @buf_i18n_ini, -- @buf_potfiles, -- @buf_potfiles_ignore, -- @buf_allfiles, -- @buf_allfiles_sorted, -- @buf_potfiles_sorted -- ); -- -- ## Search and find all translatable files -- find sub { -- push @buf_i18n_plain, "$File::Find::name" if /\.($buildin_gettext_support)$/; -- push @buf_i18n_xml, "$File::Find::name" if /\.($xml_support)$/; -- push @buf_i18n_ini, "$File::Find::name" if /\.($ini_support)$/; -- push @buf_i18n_xml_unmarked, "$File::Find::name" if /\.(schemas(\.in)+)$/; -- }, ".."; -- -- -- open POTFILES, $POTFILES_in or die "$PROGRAM: there's no POTFILES.in!\n"; -- @buf_potfiles = grep !/^(#|\s*$)/, ; -- close POTFILES; -- -- foreach (@buf_potfiles) { -- s/^\[.*]\s*//; -- } -- -- print "Searching for missing translatable files...\n" if $VERBOSE; -- -- ## Check if we should ignore some found files, when -- ## comparing with POTFILES.in -- foreach my $ignore ("POTFILES.skip", "POTFILES.ignore") -- { -- (-s $ignore) or next; -- -- if ("$ignore" eq "POTFILES.ignore") -- { -- print "The usage of POTFILES.ignore is deprecated. Please consider moving the\n". -- "content of this file to POTFILES.skip.\n"; -- } -- -- print "Found $ignore: Ignoring files...\n" if $VERBOSE; -- open FILE, "<$ignore" or die "ERROR: Failed to open $ignore!\n"; -- -- while () -- { -- push @buf_potfiles_ignore, $_ unless /^(#|\s*$)/; -- } -- close FILE; -- -- @buf_potfiles = (@buf_potfiles_ignore, @buf_potfiles); -- } -- -- foreach my $file (@buf_i18n_plain) -- { -- my $in_comment = 0; -- my $in_macro = 0; -- -- open FILE, "<$file"; -- while () -- { -- # Handle continued multi-line comment. -- if ($in_comment) -- { -- next unless s-.*\*/--; -- $in_comment = 0; -- } -- -- # Handle continued macro. -- if ($in_macro) -- { -- $in_macro = 0 unless /\\$/; -- next; -- } -- -- # Handle start of macro (or any preprocessor directive). -- if (/^\s*\#/) -- { -- $in_macro = 1 if /^([^\\]|\\.)*\\$/; -- next; -- } -- -- # Handle comments and quoted text. -- while (m-(/\*|//|\'|\")-) # \' and \" keep emacs perl mode happy -- { -- my $match = $1; -- if ($match eq "/*") -- { -- if (!s-/\*.*?\*/--) -- { -- s-/\*.*--; -- $in_comment = 1; -- } -- } -- elsif ($match eq "//") -- { -- s-//.*--; -- } -- else # ' or " -- { -- if (!s-$match([^\\]|\\.)*?$match-QUOTEDTEXT-) -- { -- warn "mismatched quotes at line $. in $file\n"; -- s-$match.*--; -- } -- } -- } -- -- if (/\.GetString ?\(QUOTEDTEXT/) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- ## Remove the first 3 chars and add newline -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- last; -- } -- -- if (/_\(QUOTEDTEXT/) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- ## Remove the first 3 chars and add newline -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- last; -- } -- } -- close FILE; -- } -- -- foreach my $file (@buf_i18n_xml) -- { -- open FILE, "<$file"; -- -- while () -- { -- # FIXME: share the pattern matching code with intltool-extract -- if (/\s_[-A-Za-z0-9._:]+\s*=\s*\"([^"]+)\"/ || /<_[^>]+>/ || /translatable=\"yes\"/) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- last; -- } -- } -- close FILE; -- } -- -- foreach my $file (@buf_i18n_ini) -- { -- open FILE, "<$file"; -- while () -- { -- if (/_(.*)=/) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- last; -- } -- } -- close FILE; -- } -- -- foreach my $file (@buf_i18n_xml_unmarked) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- } -- -- -- @buf_allfiles_sorted = sort (@buf_allfiles); -- @buf_potfiles_sorted = sort (@buf_potfiles); -- -- my %in2; -- foreach (@buf_potfiles_sorted) -- { -- $in2{$_} = 1; -- } -- -- my @result; -- -- foreach (@buf_allfiles_sorted) -- { -- if (!exists($in2{$_})) -- { -- push @result, $_ -- } -- } -- -- my @buf_potfiles_notexist; -- -- foreach (@buf_potfiles_sorted) -- { -- chomp (my $dummy = $_); -- if ("$dummy" ne "" and ! -f "../$dummy") -- { -- push @buf_potfiles_notexist, $_; -- } -- } -- -- ## Save file with information about the files missing -- ## if any, and give information about this procedure. -- if (@result + @buf_potfiles_notexist > 0) -- { -- if (@result) -- { -- print "\n" if $VERBOSE; -- unlink "missing"; -- open OUT, ">missing"; -- print OUT @result; -- close OUT; -- warn "\e[1mThe following files contain translations and are currently not in use. Please\e[0m\n". -- "\e[1mconsider adding these to the POTFILES.in file, located in the po/ directory.\e[0m\n\n"; -- print STDERR @result, "\n"; -- warn "If some of these files are left out on purpose then please add them to\n". -- "POTFILES.skip instead of POTFILES.in. A file \e[1m'missing'\e[0m containing this list\n". -- "of left out files has been written in the current directory.\n"; -- } -- if (@buf_potfiles_notexist) -- { -- unlink "notexist"; -- open OUT, ">notexist"; -- print OUT @buf_potfiles_notexist; -- close OUT; -- warn "\n" if ($VERBOSE or @result); -- warn "\e[1mThe following files do not exist anymore:\e[0m\n\n"; -- warn @buf_potfiles_notexist, "\n"; -- warn "Please remove them from POTFILES.in or POTFILES.skip. A file \e[1m'notexist'\e[0m\n". -- "containing this list of absent files has been written in the current directory.\n"; -- } -- } -- -- ## If there is nothing to complain about, notify the user -- else { -- print "\nAll files containing translations are present in POTFILES.in.\n" if $VERBOSE; -- } --} -- --sub Console_WriteError_InvalidOption --{ -- ## Handle invalid arguments -- print STDERR "Try `${PROGRAM} --help' for more information.\n"; -- exit 1; --} -- --sub GenerateHeaders --{ -- my $EXTRACT = "@INTLTOOL_EXTRACT@"; -- chomp $EXTRACT; -- -- $EXTRACT = $ENV{"INTLTOOL_EXTRACT"} if $ENV{"INTLTOOL_EXTRACT"}; -- -- ## Generate the .h header files, so we can allow glade and -- ## xml translation support -- if (! -x "$EXTRACT") -- { -- print STDERR "\n *** The intltool-extract script wasn't found!" -- ."\n *** Without it, intltool-update can not generate files.\n"; -- exit; -- } -- else -- { -- open (FILE, $POTFILES_in) or die "$PROGRAM: POTFILES.in not found.\n"; -- -- while () -- { -- chomp; -- next if /^\[\s*encoding/; -- -- ## Find xml files in POTFILES.in and generate the -- ## files with help from the extract script -- -- my $gettext_type= &POFile_DetermineType ($1); -- -- if (/\.($xml_support|$ini_support)$/ || /^\[/) -- { -- s/^\[[^\[].*]\s*//; -- -- my $filename = "../$_"; -- -- if ($VERBOSE) -- { -- system ($EXTRACT, "--update", "--srcdir=$SRCDIR", -- "--type=$gettext_type", $filename); -- } -- else -- { -- system ($EXTRACT, "--update", "--type=$gettext_type", -- "--srcdir=$SRCDIR", "--quiet", $filename); -- } -- } -- } -- close FILE; -- } --} -- --# --# Generate .pot file from POTFILES.in --# --sub GeneratePOTemplate --{ -- my $XGETTEXT = $ENV{"XGETTEXT"} || "@INTLTOOL_XGETTEXT@"; -- my $XGETTEXT_ARGS = $ENV{"XGETTEXT_ARGS"} || ''; -- chomp $XGETTEXT; -- -- if (! -x $XGETTEXT) -- { -- print STDERR " *** xgettext is not found on this system!\n". -- " *** Without it, intltool-update can not extract strings.\n"; -- exit; -- } -- -- print "Building $MODULE.pot...\n" if $VERBOSE; -- -- open INFILE, $POTFILES_in; -- unlink "POTFILES.in.temp"; -- open OUTFILE, ">POTFILES.in.temp" or die("Cannot open POTFILES.in.temp for writing"); -- -- my $gettext_support_nonascii = 0; -- -- # checks for GNU gettext >= 0.12 -- my $dummy = `$XGETTEXT --version --from-code=UTF-8 >$devnull 2>$devnull`; -- if ($? == 0) -- { -- $gettext_support_nonascii = 1; -- } -- else -- { -- # urge everybody to upgrade gettext -- print STDERR "WARNING: This version of gettext does not support extracting non-ASCII\n". -- " strings. That means you should install a version of gettext\n". -- " that supports non-ASCII strings (such as GNU gettext >= 0.12),\n". -- " or have to let non-ASCII strings untranslated. (If there is any)\n"; -- } -- -- my $encoding = "ASCII"; -- my $forced_gettext_code; -- my @temp_headers; -- my $encoding_problem_is_reported = 0; -- -- while () -- { -- next if (/^#/ or /^\s*$/); -- -- chomp; -- -- my $gettext_code; -- -- if (/^\[\s*encoding:\s*(.*)\s*\]/) -- { -- $forced_gettext_code=$1; -- } -- elsif (/\.($xml_support|$ini_support)$/ || /^\[/) -- { -- s/^\[.*]\s*//; -- print OUTFILE "../$_.h\n"; -- push @temp_headers, "../$_.h"; -- $gettext_code = &TextFile_DetermineEncoding ("../$_.h") if ($gettext_support_nonascii and not defined $forced_gettext_code); -- } -- else -- { -- if ($SRCDIR eq ".") { -- print OUTFILE "../$_\n"; -- } else { -- print OUTFILE "$SRCDIR/../$_\n"; -- } -- $gettext_code = &TextFile_DetermineEncoding ("../$_") if ($gettext_support_nonascii and not defined $forced_gettext_code); -- } -- -- next if (! $gettext_support_nonascii); -- -- if (defined $forced_gettext_code) -- { -- $encoding=$forced_gettext_code; -- } -- elsif (defined $gettext_code and "$encoding" ne "$gettext_code") -- { -- if ($encoding eq "ASCII") -- { -- $encoding=$gettext_code; -- } -- elsif ($gettext_code ne "ASCII") -- { -- # Only report once because the message is quite long -- if (! $encoding_problem_is_reported) -- { -- print STDERR "WARNING: You should use the same file encoding for all your project files,\n". -- " but $PROGRAM thinks that most of the source files are in\n". -- " $encoding encoding, while \"$_\" is (likely) in\n". -- " $gettext_code encoding. If you are sure that all translatable strings\n". -- " are in same encoding (say UTF-8), please \e[1m*prepend*\e[0m the following\n". -- " line to POTFILES.in:\n\n". -- " [encoding: UTF-8]\n\n". -- " and make sure that configure.in/ac checks for $PACKAGE >= 0.27 .\n". -- "(such warning message will only be reported once.)\n"; -- $encoding_problem_is_reported = 1; -- } -- } -- } -- } -- -- close OUTFILE; -- close INFILE; -- -- unlink "$MODULE.pot"; -- my @xgettext_argument=("$XGETTEXT", -- "--add-comments", -- "--directory\=\.", -- "--output\=$MODULE\.pot", -- "--files-from\=\.\/POTFILES\.in\.temp"); -- my $XGETTEXT_KEYWORDS = &FindPOTKeywords; -- push @xgettext_argument, $XGETTEXT_KEYWORDS; -- my $MSGID_BUGS_ADDRESS = &FindMakevarsBugAddress; -- push @xgettext_argument, "--msgid-bugs-address\=$MSGID_BUGS_ADDRESS" if $MSGID_BUGS_ADDRESS; -- push @xgettext_argument, "--from-code\=$encoding" if ($gettext_support_nonascii); -- push @xgettext_argument, $XGETTEXT_ARGS if $XGETTEXT_ARGS; -- my $xgettext_command = join ' ', @xgettext_argument; -- -- # intercept xgettext error message -- print "Running $xgettext_command\n" if $VERBOSE; -- my $xgettext_error_msg = `$xgettext_command 2>\&1`; -- my $command_failed = $?; -- -- unlink "POTFILES.in.temp"; -- -- print "Removing generated header (.h) files..." if $VERBOSE; -- unlink foreach (@temp_headers); -- print "done.\n" if $VERBOSE; -- -- if (! $command_failed) -- { -- if (! -e "$MODULE.pot") -- { -- print "None of the files in POTFILES.in contain strings marked for translation.\n" if $VERBOSE; -- } -- else -- { -- print "Wrote $MODULE.pot\n" if $VERBOSE; -- } -- } -- else -- { -- if ($xgettext_error_msg =~ /--from-code/) -- { -- # replace non-ASCII error message with a more useful one. -- print STDERR "ERROR: xgettext failed to generate PO template file because there is non-ASCII\n". -- " string marked for translation. Please make sure that all strings marked\n". -- " for translation are in uniform encoding (say UTF-8), then \e[1m*prepend*\e[0m the\n". -- " following line to POTFILES.in and rerun $PROGRAM:\n\n". -- " [encoding: UTF-8]\n\n"; -- } -- else -- { -- print STDERR "$xgettext_error_msg"; -- if (-e "$MODULE.pot") -- { -- # is this possible? -- print STDERR "ERROR: xgettext failed but still managed to generate PO template file.\n". -- " Please consult error message above if there is any.\n"; -- } -- else -- { -- print STDERR "ERROR: xgettext failed to generate PO template file. Please consult\n". -- " error message above if there is any.\n"; -- } -- } -- exit (1); -- } --} -- --sub POFile_Update --{ -- -f "$MODULE.pot" or die "$PROGRAM: $MODULE.pot does not exist.\n"; -- -- my $MSGMERGE = $ENV{"MSGMERGE"} || "@INTLTOOL_MSGMERGE@"; -- my ($lang, $outfile) = @_; -- -- print "Merging $SRCDIR/$lang.po with $MODULE.pot..." if $VERBOSE; -- -- my $infile = "$SRCDIR/$lang.po"; -- $outfile = "$SRCDIR/$lang.po" if ($outfile eq ""); -- -- # I think msgmerge won't overwrite old file if merge is not successful -- system ("$MSGMERGE", "-o", $outfile, $infile, "$MODULE.pot"); --} -- --sub Console_WriteError_NotExisting --{ -- my ($file) = @_; -- -- ## Report error if supplied language file is non-existing -- print STDERR "$PROGRAM: $file does not exist!\n"; -- print STDERR "Try '$PROGRAM --help' for more information.\n"; -- exit; --} -- --sub GatherPOFiles --{ -- my @po_files = glob ("./*.po"); -- -- @languages = map (&POFile_GetLanguage, @po_files); -- -- foreach my $lang (@languages) -- { -- $po_files_by_lang{$lang} = shift (@po_files); -- } --} -- --sub POFile_GetLanguage ($) --{ -- s/^(.*\/)?(.+)\.po$/$2/; -- return $_; --} -- --sub Console_Write_TranslationStatus --{ -- my ($lang, $output_file) = @_; -- my $MSGFMT = $ENV{"MSGFMT"} || "@INTLTOOL_MSGFMT@"; -- -- $output_file = "$SRCDIR/$lang.po" if ($output_file eq ""); -- -- system ("$MSGFMT", "-o", "$devnull", "--verbose", $output_file); --} -- --sub Console_Write_CoverageReport --{ -- my $MSGFMT = $ENV{"MSGFMT"} || "@INTLTOOL_MSGFMT@"; -- -- &GatherPOFiles; -- -- foreach my $lang (@languages) -- { -- print "$lang: "; -- &POFile_Update ($lang, ""); -- } -- -- print "\n\n * Current translation support in $MODULE \n\n"; -- -- foreach my $lang (@languages) -- { -- print "$lang: "; -- system ("$MSGFMT", "-o", "$devnull", "--verbose", "$SRCDIR/$lang.po"); -- } --} -- --sub SubstituteVariable --{ -- my ($str) = @_; -- -- # always need to rewind file whenever it has been accessed -- seek (CONF, 0, 0); -- -- # cache each variable. varhash is global to we can add -- # variables elsewhere. -- while () -- { -- if (/^(\w+)=(.*)$/) -- { -- ($varhash{$1} = $2) =~ s/^["'](.*)["']$/$1/; -- } -- } -- -- if ($str =~ /^(.*)\${?([A-Z_]+)}?(.*)$/) -- { -- my $rest = $3; -- my $untouched = $1; -- my $sub = ""; -- # Ignore recursive definitions of variables -- $sub = $varhash{$2} if defined $varhash{$2} and $varhash{$2} !~ /\${?$2}?/; -- -- return SubstituteVariable ("$untouched$sub$rest"); -- } -- -- # We're using Perl backticks ` and "echo -n" here in order to -- # expand any shell escapes (such as backticks themselves) in every variable -- return echo_n ($str); --} -- --sub CONF_Handle_Open --{ -- my $base_dirname = getcwd(); -- $base_dirname =~ s@.*/@@; -- -- my ($conf_in, $src_dir); -- -- if ($base_dirname =~ /^po(-.+)?$/) -- { -- if (-f "Makevars") -- { -- my $makefile_source; -- -- local (*IN); -- open (IN, ") -- { -- if (/^top_builddir[ \t]*=/) -- { -- $src_dir = $_; -- $src_dir =~ s/^top_builddir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/; -- -- chomp $src_dir; -- if (-f "$src_dir" . "/configure.ac") { -- $conf_in = "$src_dir" . "/configure.ac" . "\n"; -- } else { -- $conf_in = "$src_dir" . "/configure.in" . "\n"; -- } -- last; -- } -- } -- close IN; -- -- $conf_in || die "Cannot find top_builddir in Makevars."; -- } -- elsif (-f "../configure.ac") -- { -- $conf_in = "../configure.ac"; -- } -- elsif (-f "../configure.in") -- { -- $conf_in = "../configure.in"; -- } -- else -- { -- my $makefile_source; -- -- local (*IN); -- open (IN, ") -- { -- if (/^top_srcdir[ \t]*=/) -- { -- $src_dir = $_; -- $src_dir =~ s/^top_srcdir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/; -- -- chomp $src_dir; -- $conf_in = "$src_dir" . "/configure.in" . "\n"; -- -- last; -- } -- } -- close IN; -- -- $conf_in || die "Cannot find top_srcdir in Makefile."; -- } -- -- open (CONF, "<$conf_in"); -- } -- else -- { -- print STDERR "$PROGRAM: Unable to proceed.\n" . -- "Make sure to run this script inside the po directory.\n"; -- exit; -- } --} -- --sub FindPackageName --{ -- my $version; -- my $domain = &FindMakevarsDomain; -- my $name = $domain || "untitled"; -- -- &CONF_Handle_Open; -- -- my $conf_source; { -- local (*IN); -- open (IN, "<&CONF") || return $name; -- seek (IN, 0, 0); -- local $/; # slurp mode -- $conf_source = ; -- close IN; -- } -- -- # priority for getting package name: -- # 1. GETTEXT_PACKAGE -- # 2. first argument of AC_INIT (with >= 2 arguments) -- # 3. first argument of AM_INIT_AUTOMAKE (with >= 2 argument) -- -- # /^AM_INIT_AUTOMAKE\([\s\[]*([^,\)\s\]]+)/m -- # the \s makes this not work, why? -- if ($conf_source =~ /^AM_INIT_AUTOMAKE\(([^,\)]+),([^,\)]+)/m) -- { -- ($name, $version) = ($1, $2); -- $name =~ s/[\[\]\s]//g; -- $version =~ s/[\[\]\s]//g; -- $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/); -- $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/); -- $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/); -- $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/); -- } -- -- if ($conf_source =~ /^AC_INIT\(([^,\)]+),([^,\)]+)/m) -- { -- ($name, $version) = ($1, $2); -- $name =~ s/[\[\]\s]//g; -- $version =~ s/[\[\]\s]//g; -- $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/); -- $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/); -- $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/); -- $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/); -- } -- -- # \s makes this not work, why? -- $name = $1 if $conf_source =~ /^GETTEXT_PACKAGE=\[?([^\n\]]+)/m; -- -- # m4 macros AC_PACKAGE_NAME, AC_PACKAGE_VERSION etc. have same value -- # as corresponding $PACKAGE_NAME, $PACKAGE_VERSION etc. shell variables. -- $name =~ s/\bAC_PACKAGE_/\$PACKAGE_/g; -- -- $name = $domain if $domain; -- -- $name = SubstituteVariable ($name); -- $name =~ s/^["'](.*)["']$/$1/; -- -- return $name if $name; --} -- -- --sub FindPOTKeywords --{ -- -- my $keywords = "--keyword\=\_ --keyword\=N\_ --keyword\=U\_ --keyword\=Q\_"; -- my $varname = "XGETTEXT_OPTIONS"; -- my $make_source; { -- local (*IN); -- open (IN, "; -- close IN; -- } -- -- $keywords = $1 if $make_source =~ /^$varname[ ]*=\[?([^\n\]]+)/m; -- -- return $keywords; --} -- --sub FindMakevarsDomain --{ -- -- my $domain = ""; -- my $makevars_source; { -- local (*IN); -- open (IN, "; -- close IN; -- } -- -- $domain = $1 if $makevars_source =~ /^DOMAIN[ ]*=\[?([^\n\]\$]+)/m; -- $domain =~ s/^\s+//; -- $domain =~ s/\s+$//; -- -- return $domain; --} -- --sub FindMakevarsBugAddress --{ -- -- my $address = ""; -- my $makevars_source; { -- local (*IN); -- open (IN, "; -- close IN; -- } -- -- $address = $1 if $makevars_source =~ /^MSGID_BUGS_ADDRESS[ ]*=\[?([^\n\]\$]+)/m; -- $address =~ s/^\s+//; -- $address =~ s/\s+$//; -- -- return $address; --} -diff --git a/intltool-update.in b/intltool-update.in -new file mode 120000 -index 661d8fe..0b1800f ---- /dev/null -+++ b/intltool-update.in -@@ -0,0 +1 @@ -+/usr/share/intltool/intltool-update.in -\ No newline at end of file -diff --git a/pixmaps/intlclock-map-location-current.png b/pixmaps/intlclock-map-location-current.png -new file mode 100644 -index 0000000..5c505d1 -Binary files /dev/null and b/pixmaps/intlclock-map-location-current.png differ -diff --git a/pixmaps/intlclock-map-location-current.svg b/pixmaps/intlclock-map-location-current.svg -new file mode 100644 -index 0000000..93b5188 ---- /dev/null -+++ b/pixmaps/intlclock-map-location-current.svg -@@ -0,0 +1,76 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ image/svg+xml -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/pixmaps/intlclock-map-location-hilight.png b/pixmaps/intlclock-map-location-hilight.png -new file mode 100644 -index 0000000..d7de5b7 -Binary files /dev/null and b/pixmaps/intlclock-map-location-hilight.png differ -diff --git a/pixmaps/intlclock-map-location-hilight.svg b/pixmaps/intlclock-map-location-hilight.svg -new file mode 100644 -index 0000000..4a245e0 ---- /dev/null -+++ b/pixmaps/intlclock-map-location-hilight.svg -@@ -0,0 +1,90 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ image/svg+xml -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/pixmaps/intlclock-map-location-marker.png b/pixmaps/intlclock-map-location-marker.png -new file mode 100644 -index 0000000..48d2184 -Binary files /dev/null and b/pixmaps/intlclock-map-location-marker.png differ -diff --git a/po/Makefile.in.in b/po/Makefile.in.in -deleted file mode 100755 -index d2d4e4c..e4713cf ---- a/po/Makefile.in.in -+++ /dev/null -@@ -1,221 +0,0 @@ --# Makefile for program source directory in GNU NLS utilities package. --# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper --# --# This file file be copied and used freely without restrictions. It can --# be used in projects which are not available under the GNU Public License --# but which still want to provide support for the GNU gettext functionality. --# Please note that the actual code is *not* freely available. --# --# - Modified by Owen Taylor to use GETTEXT_PACKAGE --# instead of PACKAGE and to look for po2tbl in ./ not in intl/ --# --# - Modified by jacob berkman to install --# Makefile.in.in and po2tbl.sed.in for use with glib-gettextize --# --# - Modified by Rodney Dawes for use with intltool --# --# We have the following line for use by intltoolize: --# INTLTOOL_MAKEFILE -- --GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ --PACKAGE = @PACKAGE@ --VERSION = @VERSION@ -- --SHELL = /bin/sh -- --srcdir = @srcdir@ --top_srcdir = @top_srcdir@ --top_builddir = .. --VPATH = @srcdir@ -- --prefix = @prefix@ --exec_prefix = @exec_prefix@ --datadir = @datadir@ --datarootdir = @datarootdir@ --libdir = @libdir@ --DATADIRNAME = @DATADIRNAME@ --itlocaledir = $(prefix)/$(DATADIRNAME)/locale --subdir = po --install_sh = @install_sh@ --# Automake >= 1.8 provides @mkdir_p@. --# Until it can be supposed, use the safe fallback: --mkdir_p = $(install_sh) -d -- --INSTALL = @INSTALL@ --INSTALL_DATA = @INSTALL_DATA@ -- --GMSGFMT = @GMSGFMT@ --MSGFMT = @MSGFMT@ --XGETTEXT = @XGETTEXT@ --INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ --INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ --MSGMERGE = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist --GENPOT = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot -- --ALL_LINGUAS = @ALL_LINGUAS@ -- --PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; fi) -- --POFILES=$(shell if test -n "$(PO_LINGUAS)"; then LINGUAS="$(PO_LINGUAS)"; else LINGUAS="$(ALL_LINGUAS)"; fi; for lang in $$LINGUAS; do printf "$$lang.po "; done) -- --DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(POFILES) --EXTRA_DISTFILES = POTFILES.skip Makevars LINGUAS -- --POTFILES = \ --#This Gets Replace for some reason -- --CATALOGS=$(shell if test -n "$(PO_LINGUAS)"; then LINGUAS="$(PO_LINGUAS)"; else LINGUAS="$(ALL_LINGUAS)"; fi; for lang in $$LINGUAS; do printf "$$lang.gmo "; done) -- --.SUFFIXES: --.SUFFIXES: .po .pox .gmo .mo .msg .cat -- --.po.pox: -- $(MAKE) $(GETTEXT_PACKAGE).pot -- $(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox -- --.po.mo: -- $(MSGFMT) -o $@ $< -- --.po.gmo: -- file=`echo $* | sed 's,.*/,,'`.gmo \ -- && rm -f $$file && $(GMSGFMT) -o $$file $< -- --.po.cat: -- sed -f ../intl/po2msg.sed < $< > $*.msg \ -- && rm -f $@ && gencat $@ $*.msg -- -- --all: all-@USE_NLS@ -- --all-yes: $(CATALOGS) --all-no: -- --$(GETTEXT_PACKAGE).pot: $(POTFILES) -- $(GENPOT) -- --install: install-data --install-data: install-data-@USE_NLS@ --install-data-no: all --install-data-yes: all -- $(mkdir_p) $(DESTDIR)$(itlocaledir) -- if test -n "$(PO_LINGUAS)"; then \ -- linguas="$(PO_LINGUAS)"; \ -- else \ -- linguas="$(ALL_LINGUAS)"; \ -- fi; \ -- for lang in $$linguas; do \ -- dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \ -- $(mkdir_p) $$dir; \ -- if test -r $$lang.gmo; then \ -- $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ -- echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \ -- else \ -- $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ -- echo "installing $(srcdir)/$$lang.gmo as" \ -- "$$dir/$(GETTEXT_PACKAGE).mo"; \ -- fi; \ -- if test -r $$lang.gmo.m; then \ -- $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ -- echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ -- else \ -- if test -r $(srcdir)/$$lang.gmo.m ; then \ -- $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \ -- $$dir/$(GETTEXT_PACKAGE).mo.m; \ -- echo "installing $(srcdir)/$$lang.gmo.m as" \ -- "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ -- else \ -- true; \ -- fi; \ -- fi; \ -- done -- --# Empty stubs to satisfy archaic automake needs --dvi info tags TAGS ID: -- --# Define this as empty until I found a useful application. --installcheck: -- --uninstall: -- if test -n "$(PO_LINGUAS)"; then \ -- linguas="$(PO_LINGUAS)"; \ -- else \ -- linguas="$(ALL_LINGUAS)"; \ -- fi; \ -- for lang in $$linguas; do \ -- rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ -- rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ -- done -- --check: all $(GETTEXT_PACKAGE).pot -- --mostlyclean: -- rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp -- rm -f .intltool-merge-cache -- --clean: mostlyclean -- --distclean: clean -- rm -f Makefile Makefile.in POTFILES stamp-it -- rm -f *.mo *.msg *.cat *.cat.m *.gmo -- --maintainer-clean: distclean -- @echo "This command is intended for maintainers to use;" -- @echo "it deletes files that may require special tools to rebuild." -- rm -f Makefile.in.in -- --distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) --dist distdir: $(DISTFILES) -- dists="$(DISTFILES)"; \ -- extra_dists="$(EXTRA_DISTFILES)"; \ -- for file in $$extra_dists; do \ -- test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ -- done; \ -- for file in $$dists; do \ -- test -f $$file || file="$(srcdir)/$$file"; \ -- ln $$file $(distdir) 2> /dev/null \ -- || cp -p $$file $(distdir); \ -- done -- --update-po: Makefile -- $(MAKE) $(GETTEXT_PACKAGE).pot -- tmpdir=`pwd`; \ -- if test -n "$(PO_LINGUAS)"; then \ -- linguas="$(PO_LINGUAS)"; \ -- else \ -- linguas="$(ALL_LINGUAS)"; \ -- fi; \ -- for lang in $$linguas; do \ -- echo "$$lang:"; \ -- result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \ -- if $$result; then \ -- if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ -- rm -f $$tmpdir/$$lang.new.po; \ -- else \ -- if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ -- :; \ -- else \ -- echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ -- rm -f $$tmpdir/$$lang.new.po; \ -- exit 1; \ -- fi; \ -- fi; \ -- else \ -- echo "msgmerge for $$lang.gmo failed!"; \ -- rm -f $$tmpdir/$$lang.new.po; \ -- fi; \ -- done -- --Makefile POTFILES: stamp-it -- @if test ! -f $@; then \ -- rm -f stamp-it; \ -- $(MAKE) stamp-it; \ -- fi -- --stamp-it: Makefile.in.in ../config.status POTFILES.in -- cd .. \ -- && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ -- $(SHELL) ./config.status -- --# Tell versions [3.59,3.63) of GNU make not to export all variables. --# Otherwise a system limit (for SysV at least) may be exceeded. --.NOEXPORT: -diff --git a/po/Makefile.in.in b/po/Makefile.in.in -new file mode 120000 -index d2d4e4c..e4713cf ---- /dev/null -+++ b/po/Makefile.in.in -@@ -0,0 +1 @@ -+/usr/share/intltool/Makefile.in.in -\ No newline at end of file -diff --git a/src/Makefile.am b/src/Makefile.am -index 80d1419..d681d39 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -3,7 +3,7 @@ - INCLUDES = \ - $(INTLCLOCK_CFLAGS) \ - -DGNOMELOCALEDIR=\"$(prefix)/$(DATADIRNAME)/locale\" \ -- -DEVOLUTION_TEXTDOMAIN=\"evolution-2.6\" \ -+ -DEVOLUTION_TEXTDOMAIN=\"evolution-2.12\" \ - -DINTLCLOCK_TEXTDOMAIN=\"gnome-panel-2.0\" \ - -DINTLCLOCK_ICONDIR=\"$(pkgdatadir)\" \ - -DINTLCLOCK_DATADIR=\"$(pkgdatadir)\" \ -@@ -60,7 +60,11 @@ COMMON_SOURCES = \ - intlclock-zoneinfo.c \ - intlclock-zoneinfo.h \ - intlclock-zonetable.c \ -- intlclock-zonetable.h -+ intlclock-zonetable.h \ -+ set-timezone.c \ -+ set-timezone.h \ -+ gweather-xml.c \ -+ gweather-xml.h - - - intlclock_applet_SOURCES = \ -diff --git a/src/gweather-xml.c b/src/gweather-xml.c -new file mode 100644 -index 0000000..94b275d ---- /dev/null -+++ b/src/gweather-xml.c -@@ -0,0 +1,490 @@ -+/* gweather-xml.c - Locations.xml parsing code -+ * -+ * Copyright (C) 2005 Ryan Lortie, 2004 Gareth Owen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+ -+/* There is very little error checking in the parsing code below, it relies -+ * heavily on the locations file being in the correct format. If you have -+ * elements within a parent element, they must come first and be -+ * grouped together. -+ * The format is as follows: -+ * -+ * -+ * -+ * Name of the region -+ * Translated Name -+ * Another Translated Name -+ * -+ * Name of the country -+ * -+ * Name of the location -+ * IWIN code -+ * Forecast code (North America, Australia, UK only) -+ * Weather.com radar map code (North America only) -+ * Latitude and longitude as DD-MM[-SS][H] pair -+ * -+ * -+ * -+ * .... -+ * -+ * -+ * Name of city with multiple locations -+ * Forecast code -+ * Radar Map code -+ * -+ * ... -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * The thing to note is that each country can either contain different locations -+ * or be split into "states" which in turn contain a list of locations. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "gweather-xml.h" -+ -+static gint -+gweather_xml_location_sort_func( GtkTreeModel *model, GtkTreeIter *a, -+ GtkTreeIter *b, gpointer user_data ) -+{ -+ gint res; -+ gchar *name_a, *name_b; -+ gchar *fold_a, *fold_b; -+ -+ gtk_tree_model_get (model, a, GWEATHER_XML_COL_LOC, &name_a, -1); -+ gtk_tree_model_get (model, b, GWEATHER_XML_COL_LOC, &name_b, -1); -+ -+ fold_a = g_utf8_casefold(name_a, -1); -+ fold_b = g_utf8_casefold(name_b, -1); -+ -+ res = g_utf8_collate(fold_a, fold_b); -+ -+ g_free(name_a); -+ g_free(name_b); -+ g_free(fold_a); -+ g_free(fold_b); -+ -+ return res; -+} -+ -+static char* -+gweather_xml_get_value( xmlTextReaderPtr xml ) -+{ -+ char* value; -+ -+ /* check for null node */ -+ if ( xmlTextReaderIsEmptyElement( xml ) ) -+ return NULL; -+ -+ /* the next "node" is the text node containing the value we want to get */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ return NULL; -+ -+ value = (char *) xmlTextReaderValue( xml ); -+ -+ /* move on to the end of this node */ -+ while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_END_ELEMENT ) -+ if( xmlTextReaderRead( xml ) != 1 ) -+ { -+ xmlFree( value ); -+ return NULL; -+ } -+ -+ /* consume the end element too */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ { -+ xmlFree( value ); -+ return NULL; -+ } -+ -+ return value; -+} -+ -+static char * -+gweather_xml_parse_name( xmlTextReaderPtr xml ) -+{ -+ const char * const *locales; -+ const char *this_language; -+ int best_match = INT_MAX; -+ char *lang, *tagname; -+ gboolean keep_going; -+ char *name = NULL; -+ int i; -+ -+ locales = g_get_language_names(); -+ -+ do -+ { -+ /* First let's get the language */ -+ lang = (char *) xmlTextReaderXmlLang( xml ); -+ -+ if( lang == NULL ) -+ this_language = "C"; -+ else -+ this_language = lang; -+ -+ /* the next "node" is text node containing the actual name */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ { -+ xmlFree( lang ); -+ return NULL; -+ } -+ -+ for( i = 0; locales[i] && i < best_match; i++ ) -+ if( !strcmp( locales[i], this_language ) ) -+ { -+ /* if we've already encounted a less accurate -+ translation, then free it */ -+ xmlFree( name ); -+ -+ name = (char *) xmlTextReaderValue( xml ); -+ best_match = i; -+ -+ break; -+ } -+ -+ xmlFree( lang ); -+ -+ while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_ELEMENT ) -+ if( xmlTextReaderRead( xml ) != 1 ) -+ { -+ xmlFree( name ); -+ return NULL; -+ } -+ -+ /* if the next tag is another then keep going */ -+ tagname = (char *) xmlTextReaderName( xml ); -+ keep_going = !strcmp( tagname, "name" ); -+ xmlFree( tagname ); -+ -+ } while( keep_going ); -+ -+ return name; -+} -+ -+static int -+gweather_xml_parse_node (GtkTreeView *view, GtkTreeIter *parent, -+ xmlTextReaderPtr xml, WeatherLocation *current, -+ const char *dflt_radar, const char *dflt_zone, -+ const char *cityname) -+{ -+ GtkTreeStore *store = GTK_TREE_STORE( gtk_tree_view_get_model( view ) ); -+ char *name, *code, *zone, *radar, *coordinates; -+ char **city, *nocity = NULL; -+ GtkTreeIter iter, *self; -+ gboolean is_location; -+ char *tagname; -+ int ret = -1; -+ int tagtype; -+ -+ if( (tagname = (char *) xmlTextReaderName( xml )) == NULL ) -+ return -1; -+ -+ if( !strcmp( tagname, "city" ) ) -+ city = &name; -+ else -+ city = &nocity; -+ -+ is_location = !strcmp( tagname, "location" ); -+ -+ /* if we're processing the top-level, then don't create a new iter */ -+ if( !strcmp( tagname, "gweather" ) ) -+ self = NULL; -+ else -+ { -+ self = &iter; -+ /* insert this node into the tree */ -+ gtk_tree_store_append( store, self, parent ); -+ } -+ -+ xmlFree( tagname ); -+ -+ coordinates = NULL; -+ radar = NULL; -+ zone = NULL; -+ code = NULL; -+ name = NULL; -+ -+ /* absorb the start tag */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ goto error_out; -+ -+ /* start parsing the actual contents of the node */ -+ while( (tagtype = xmlTextReaderNodeType( xml )) != -+ XML_READER_TYPE_END_ELEMENT ) -+ { -+ -+ /* skip non-element types */ -+ if( tagtype != XML_READER_TYPE_ELEMENT ) -+ { -+ if( xmlTextReaderRead( xml ) != 1 ) -+ goto error_out; -+ -+ continue; -+ } -+ -+ tagname = (char *) xmlTextReaderName( xml ); -+ -+ if( !strcmp( tagname, "region" ) || !strcmp( tagname, "country" ) || -+ !strcmp( tagname, "state" ) || !strcmp( tagname, "city" ) || -+ !strcmp( tagname, "location" ) ) -+ { -+ /* recursively handle sub-sections */ -+ if( gweather_xml_parse_node( view, self, xml, current, -+ radar, zone, *city ) ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "name" ) ) -+ { -+ xmlFree( name ); -+ if( (name = gweather_xml_parse_name( xml )) == NULL ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "code" ) ) -+ { -+ xmlFree( code ); -+ if( (code = gweather_xml_get_value( xml )) == NULL ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "zone" ) ) -+ { -+ xmlFree( zone ); -+ if( (zone = gweather_xml_get_value( xml )) == NULL ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "radar" ) ) -+ { -+ xmlFree( radar ); -+ if( (radar = gweather_xml_get_value( xml )) == NULL ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "coordinates" ) ) -+ { -+ xmlFree( coordinates ); -+ if( (coordinates = gweather_xml_get_value( xml )) == NULL ) -+ goto error_out; -+ } -+ else /* some strange tag */ -+ { -+ /* skip past it */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ goto error_out; -+ } -+ -+ xmlFree( tagname ); -+ } -+ -+ if( self ) -+ gtk_tree_store_set( store, self, GWEATHER_XML_COL_LOC, name, -1 ); -+ -+ /* absorb the end tag. in the case of processing a then 'self' -+ is NULL. In this case, we let this fail since we might be at EOF */ -+ if( xmlTextReaderRead( xml ) != 1 && self ) -+ goto error_out; -+ -+ /* if this is an actual location, setup the WeatherLocation for it */ -+ if( is_location ) -+ { -+ WeatherLocation *new_loc; -+ -+ if( cityname == NULL ) -+ cityname = name; -+ -+ if( radar != NULL ) -+ dflt_radar = radar; -+ -+ if( zone != NULL ) -+ dflt_zone = zone; -+ -+ new_loc = weather_location_new( cityname, code, dflt_zone, -+ dflt_radar, coordinates ); -+ -+ gtk_tree_store_set( store, &iter, GWEATHER_XML_COL_POINTER, new_loc, -1 ); -+ -+ /* If this location is actually the currently selected one, select it */ -+ if( current && weather_location_equal( new_loc, current ) ) -+ { -+ GtkTreePath *path; -+ -+ path = gtk_tree_model_get_path( GTK_TREE_MODEL (store), &iter ); -+ gtk_tree_view_expand_to_path( view, path ); -+ gtk_tree_view_set_cursor( view, path, NULL, FALSE ); -+ gtk_tree_view_scroll_to_cell( view, path, NULL, TRUE, 0.5, 0.5 ); -+ gtk_tree_path_free( path ); -+ } -+ } -+ -+ ret = 0; -+ -+error_out: -+ xmlFree( name ); -+ xmlFree( code ); -+ xmlFree( zone ); -+ xmlFree( radar ); -+ xmlFree( coordinates ); -+ -+ return ret; -+} -+ -+/***************************************************************************** -+ * Func: gweather_xml_load_locations() -+ * Desc: Main entry point for loading the locations from the XML file -+ * Parm: -+ * *tree: tree to view locations -+ * *current: currently selected location -+ */ -+int -+gweather_xml_load_locations( GtkTreeView *tree, WeatherLocation *current ) -+{ -+ char *tagname, *format; -+ GtkTreeSortable *sortable; -+ xmlTextReaderPtr xml; -+ int keep_going; -+ int ret = -1; -+ -+ /* Open the xml file containing the different locations */ -+#ifdef GWEATHER_XML_LOCATION -+ xml = xmlNewTextReaderFilename (GWEATHER_XML_LOCATION "Locations.xml"); -+#else -+ xml = xmlNewTextReaderFilename ("/usr/share/gnome-applets/gweather/Locations.xml"); -+#endif -+ if( xml == NULL ) -+ goto error_out; -+ -+ /* fast forward to the first element */ -+ do -+ { -+ /* if we encounter a problem here, exit right away */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ goto error_out; -+ } while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_ELEMENT ); -+ -+ /* check the name and format */ -+ tagname = (char *) xmlTextReaderName( xml ); -+ keep_going = tagname && !strcmp( tagname, "gweather" ); -+ xmlFree( tagname ); -+ -+ if( !keep_going ) -+ goto error_out; -+ -+ format = (char *) xmlTextReaderGetAttribute( xml, (xmlChar *) "format" ); -+ keep_going = format && !strcmp( format, "1.0" ); -+ xmlFree( format ); -+ -+ if( !keep_going ) -+ goto error_out; -+ -+ ret = gweather_xml_parse_node( tree, NULL, xml, current, NULL, NULL, NULL ); -+ -+ if( ret ) -+ goto error_out; -+ -+ /* Sort the tree */ -+ sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model( tree )); -+ gtk_tree_sortable_set_default_sort_func( sortable, -+ &gweather_xml_location_sort_func, -+ NULL, NULL); -+ gtk_tree_sortable_set_sort_column_id( sortable, -+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, -+ GTK_SORT_ASCENDING ); -+error_out: -+ xmlFreeTextReader( xml ); -+ -+ return ret; -+} -+ -+typedef struct { -+ const gchar *name; -+ gdouble latitude; -+ gdouble longitude; -+ gdouble distance; -+ WeatherLocation *location; -+} SearchData; -+ -+ -+static gdouble -+distance (gdouble lat1, gdouble lon1, -+ gdouble lat2, gdouble lon2) -+{ -+ gdouble radius = 6372.795; -+ -+ return acos (cos (lat1) * cos (lat2) * cos (lon1 - lon2) + sin (lat1) * sin (lat2)) * radius; -+} -+ -+gboolean -+compare_location (GtkTreeModel *model, -+ GtkTreePath *path, -+ GtkTreeIter *iter, -+ gpointer user_data) -+{ -+ SearchData *data = user_data; -+ WeatherLocation *loc; -+ gdouble d; -+ -+ gtk_tree_model_get (model, iter, GWEATHER_XML_COL_POINTER, &loc, -1); -+ -+ if (!loc) -+ return FALSE; -+ -+ d = distance (data->latitude, data->longitude, loc->latitude, loc->longitude); -+ -+ if (d < data->distance) { -+ data->distance = d; -+ data->location = loc; -+ } -+ -+ return FALSE; -+} -+ -+gchar * -+find_weather_code (GtkTreeModel *model, -+ const gchar *name, -+ gdouble lat, -+ gdouble lon) -+{ -+ SearchData data; -+ gchar *code; -+ -+ data.name = name; -+ data.latitude = lat; -+ data.longitude = lon; -+ data.distance = 1e6; -+ data.location = NULL; -+ -+ gtk_tree_model_foreach (GTK_TREE_MODEL (model), compare_location, &data); -+ -+ if (data.distance < 50) -+ code = g_strdup (data.location->code); -+ else -+ code = g_strdup ("-"); -+ -+ g_debug ("distance: %f\nin: %s\nlat, lon: %f, %f\nout: %s\nDMS: %s\ncode: %s\n", -+ data.distance, name, lat, lon, data.location->name, data.location->coordinates, code); -+ -+ return code; -+} -diff --git a/src/gweather-xml.h b/src/gweather-xml.h -new file mode 100644 -index 0000000..d65b651 ---- /dev/null -+++ b/src/gweather-xml.h -@@ -0,0 +1,37 @@ -+/* gweather-xml.h -+ * -+ * Copyright (C) 2004 Gareth Owen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#ifndef __GWEATHER_XML_H__ -+#define __GWEATHER_XML_H__ -+ -+#include -+#include -+ -+enum -+{ -+ GWEATHER_XML_COL_LOC = 0, -+ GWEATHER_XML_COL_POINTER, -+ GWEATHER_XML_NUM_COLUMNS -+}; -+ -+int gweather_xml_load_locations( GtkTreeView *tree, WeatherLocation *current ); -+gchar *find_weather_code (GtkTreeModel *model, const gchar *name, gdouble lat, gdouble lon); -+ -+ -+#endif /* __GWEATHER_XML_H__ */ -diff --git a/src/intlclock-events-popup.c b/src/intlclock-events-popup.c -index 4276f81..a54f6e3 100644 ---- a/src/intlclock-events-popup.c -+++ b/src/intlclock-events-popup.c -@@ -1,6 +1,8 @@ - #include - #include - #include -+#include -+#include - - #ifdef HAVE_CONFIG_H - #include "config.h" -@@ -11,12 +13,18 @@ - #endif - - #include "intlclock-events-popup.h" -+#include "intlclock-ui.h" -+ -+#define KEY_EXPAND_LOCATIONS "expand_locations" -+#define KEY_EXPAND_TASKS "expand_tasks" -+#define KEY_EXPAND_APPOINTMENTS "expand_appointments" - - G_DEFINE_TYPE (IntlClockEventsPopup, intlclock_events_popup, GTK_TYPE_WINDOW) - - typedef struct { - IntlClock *clock; - PanelApplet *panel_applet; -+ IntlClockUI *ui; - - GtkWidget *calendar; - GtkWidget *main_section; -@@ -126,7 +134,7 @@ intlclock_events_popup_size_allocate_cb (GtkWidget *widget, GtkAllocation *alloc - } - - IntlClockEventsPopup * --intlclock_events_popup_new (IntlClock *clock, PanelApplet *panel_applet) -+intlclock_events_popup_new (IntlClock *clock, PanelApplet *panel_applet, IntlClockUI *ui) - { - IntlClockEventsPopup *this; - IntlClockEventsPopupPrivate *priv; -@@ -138,6 +146,7 @@ intlclock_events_popup_new (IntlClock *clock, PanelApplet *panel_applet) - - priv->clock = g_object_ref (clock); - priv->panel_applet = panel_applet; -+ priv->ui = ui; - - gtk_widget_set_name (GTK_WIDGET (this), "intlclock-events-window"); - gtk_container_set_border_width (GTK_CONTAINER (this), 0); -@@ -275,6 +284,21 @@ intlclock_events_popup_tick (IntlClock *clock, IntlClockEventsPopup *this) - gmtime (&priv->current_time); - } - -+static GtkWidget * create_hig_frame (IntlClockEventsPopup *this, -+ const char *title, -+ const char *button_label, -+ const char *key, -+ GCallback callback); -+ -+ -+static void -+edit_locations (IntlClockEventsPopup *this) -+{ -+ IntlClockEventsPopupPrivate *priv = PRIVATE (this); -+ -+ intlclock_ui_edit_locations (priv->ui); -+} -+ - static void - intlclock_events_popup_fill (IntlClockEventsPopup *this) - { -@@ -296,7 +320,10 @@ intlclock_events_popup_fill (IntlClockEventsPopup *this) - - orient = panel_applet_get_orient (priv->panel_applet); - -- priv->clock_container = gtk_vbox_new (FALSE, 0); -+ priv->clock_container = create_hig_frame (this, -+ _("Locations"), _("Edit"), -+ KEY_EXPAND_LOCATIONS, -+ G_CALLBACK (edit_locations)); - - switch (orient) { - case PANEL_APPLET_ORIENT_UP: -@@ -642,28 +669,167 @@ modify_task_text_attributes (GtkTreeModel *model, - g_value_take_boxed (value, attr_list); - } - -+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 -+expander_activated (GtkExpander *expander, -+ gpointer data) -+{ -+ IntlClockEventsPopup *this = data; -+ IntlClockEventsPopupPrivate *priv = PRIVATE (this); -+ const gchar *key; -+ gboolean expanded; -+ -+ key = (const gchar*)g_object_get_data (G_OBJECT (expander), "gconf-key"); -+ expanded = gtk_expander_get_expanded (expander); -+ -+ panel_applet_gconf_set_bool (priv->panel_applet, key, expanded, NULL); -+} -+ -+static void -+expanded_changed (GConfClient *client, -+ guint cnxn_id, -+ GConfEntry *entry, -+ GtkExpander *expander) -+{ -+ if (!entry->value || entry->value->type != GCONF_VALUE_BOOL) -+ return; -+ -+ gtk_expander_set_expanded (expander, -+ gconf_value_get_bool (entry->value)); -+} -+ -+static void -+remove_listener (gpointer data) -+{ -+ GConfClient *client; -+ -+ client = gconf_client_get_default (); -+ gconf_client_notify_remove (client, GPOINTER_TO_UINT (data)); -+ g_object_unref (client); -+} -+ -+static void -+connect_expander_with_gconf (IntlClockEventsPopup *this, -+ GtkWidget *expander, -+ const gchar *key) -+{ -+ IntlClockEventsPopupPrivate *priv = PRIVATE (this); -+ GConfClient *client; -+ gboolean expanded; -+ guint listener; -+ gchar *full_key; -+ -+ g_object_set_data (G_OBJECT (expander), "gconf-key", (gpointer)key); -+ -+ expanded = panel_applet_gconf_get_bool (priv->panel_applet, key, NULL); -+ gtk_expander_set_expanded (GTK_EXPANDER (expander), expanded); -+ -+ g_signal_connect_after (expander, "activate", -+ G_CALLBACK (expander_activated), -+ this); -+ -+ client = gconf_client_get_default (); -+ full_key = panel_applet_gconf_get_full_key (priv->panel_applet, key); -+ listener = gconf_client_notify_add (client, full_key, -+ (GConfClientNotifyFunc)expanded_changed, -+ expander, NULL, NULL); -+ g_object_set_data_full (G_OBJECT (expander), "listener-id", -+ GUINT_TO_POINTER (listener), remove_listener); -+ g_object_unref (client); -+} -+ -+static void add_child (GtkContainer *container, -+ GtkWidget *child, -+ GtkExpander *expander) -+{ -+ gboolean expanded; -+ -+ expanded = gtk_expander_get_expanded (expander); -+ g_object_set (child, "visible", expanded, NULL); -+} -+ - static GtkWidget * --create_hig_frame (const char *title) -+create_hig_frame (IntlClockEventsPopup *this, -+ 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); -- -- alignment = gtk_alignment_new (0, 0.5, 0, 0); -- gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0); -- gtk_widget_show (alignment); -- -- label = gtk_label_new (bold_title); -- gtk_label_set_use_markup (GTK_LABEL (label), TRUE); -- gtk_container_add (GTK_CONTAINER (alignment), label); -- gtk_widget_show (label); -- -+ expander = gtk_expander_new (""); -+ gtk_expander_set_label (GTK_EXPANDER (expander), 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, this); -+ } -+ -+ connect_expander_with_gconf (this, expander, key); - - return vbox; - } -@@ -791,6 +957,12 @@ compare_tasks (GtkTreeModel *model, - } - } - -+static void -+edit_tasks (IntlClockEventsPopup *this) -+{ -+ clock_launch_evolution (this, "--component=tasks"); -+} -+ - static GtkWidget * - create_task_list (IntlClockEventsPopup *this, - GtkWidget **tree_view, -@@ -804,7 +976,9 @@ create_task_list (IntlClockEventsPopup *this, - GtkCellRenderer *cell; - GtkTreeViewColumn *column; - -- vbox = create_hig_frame (_("Tasks")); -+ vbox = create_hig_frame (this, _("Tasks"), _("Edit"), -+ KEY_EXPAND_TASKS, -+ G_CALLBACK (edit_tasks)); - - *scrolled_window = scrolled = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), -@@ -812,8 +986,8 @@ create_task_list (IntlClockEventsPopup *this, - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), - GTK_POLICY_NEVER, - GTK_POLICY_AUTOMATIC); -- gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0); - gtk_widget_show (scrolled); -+ gtk_container_add (GTK_CONTAINER (vbox), scrolled); - - if (!priv->tasks_model) { - GType column_types [N_TASK_COLUMNS] = { -@@ -984,6 +1158,12 @@ handle_appointments_changed (IntlClockEventsPopup *this) - update_frame_visibility (priv->appointment_list, GTK_TREE_MODEL (priv->appointments_model)); - } - -+static void -+edit_appointments (IntlClockEventsPopup *this) -+{ -+ clock_launch_evolution (this, "--component=calendar"); -+} -+ - static GtkWidget * - create_appointment_list (IntlClockEventsPopup *this, - GtkWidget **tree_view, -@@ -997,7 +1177,9 @@ create_appointment_list (IntlClockEventsPopup *this, - GtkCellRenderer *cell; - GtkTreeViewColumn *column; - -- vbox = create_hig_frame ( _("Appointments")); -+ vbox = create_hig_frame (this, _("Appointments"), _("Edit"), -+ KEY_EXPAND_APPOINTMENTS, -+ G_CALLBACK (edit_appointments)); - - *scrolled_window = scrolled = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), -@@ -1005,8 +1187,8 @@ create_appointment_list (IntlClockEventsPopup *this, - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), - GTK_POLICY_NEVER, - GTK_POLICY_AUTOMATIC); -- gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0); - gtk_widget_show (scrolled); -+ gtk_container_add (GTK_CONTAINER (vbox), scrolled); - - if (!priv->appointments_model) { - priv->appointments_model = -diff --git a/src/intlclock-events-popup.h b/src/intlclock-events-popup.h -index 84a5183..b88e4c7 100644 ---- a/src/intlclock-events-popup.h -+++ b/src/intlclock-events-popup.h -@@ -2,6 +2,7 @@ - #define __INTLCLOCK_EVENTS_POPUP_H__ - - #include "intlclock.h" -+#include "intlclock-ui.h" - - #include - #include -@@ -29,7 +30,8 @@ typedef struct - GType intlclock_events_popup_get_type (void); - - IntlClockEventsPopup *intlclock_events_popup_new (IntlClock *clock, -- PanelApplet *panel_applet); -+ PanelApplet *panel_applet, -+ IntlClockUI *ui); - void intlclock_events_popup_set_date (IntlClockEventsPopup *this, - guint year, guint month, guint mday); - GtkWidget *intlclock_events_popup_get_clock_container (IntlClockEventsPopup *this); -diff --git a/src/intlclock-location-tile.c b/src/intlclock-location-tile.c -index 40d96e3..7f64fee 100644 ---- a/src/intlclock-location-tile.c -+++ b/src/intlclock-location-tile.c -@@ -23,9 +23,18 @@ typedef struct { - - IntlClockFaceSize size; - -+ GtkWidget *box; - GtkWidget *clock_face; - GtkWidget *city_label; - GtkWidget *time_label; -+ -+ GtkWidget *current_button; -+ GtkWidget *current_label; -+ GtkWidget *current_marker; -+ GtkSizeGroup *button_group; -+ -+ GtkWidget *weather_icon; -+ - } IntlClockLocationTilePrivate; - - static void intlclock_location_tile_finalize (GObject *); -@@ -36,6 +45,12 @@ static void intlclock_location_tile_refresh (IntlClockLocationTile *this); - #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INTLCLOCK_LOCATION_TILE_TYPE, IntlClockLocationTilePrivate)) - - static void intlclock_location_tile_fill (IntlClockLocationTile *this); -+static void update_weather_icon (IntlClockLocation *loc, WeatherInfo *info, gpointer data); -+static gboolean weather_tooltip (GtkWidget *widget, -+ gint x, gint y, -+ gboolean keyboard_mode, -+ GtkTooltip *tooltip, -+ gpointer data); - - IntlClockLocationTile * - intlclock_location_tile_new (IntlClock *clock, IntlClockUI *ui, -@@ -56,13 +71,17 @@ intlclock_location_tile_new (IntlClock *clock, IntlClockUI *ui, - priv->location = g_object_ref (loc); - priv->size = size; - -- gtk_alignment_set (GTK_ALIGNMENT (this), 0.0, 0.0, 0.0, 0.0); -- gtk_alignment_set_padding (GTK_ALIGNMENT (this), 3, 3, 3, 3); -- - intlclock_location_tile_fill (this); - -- g_signal_connect (G_OBJECT (priv->clock), "tick", -- G_CALLBACK (intlclock_location_tile_tick), this); -+ update_weather_icon (loc, intlclock_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); -+ g_signal_connect (G_OBJECT (loc), "weather-updated", -+ G_CALLBACK (update_weather_icon), this); -+ g_signal_connect (G_OBJECT (priv->clock), "tick", -+ G_CALLBACK (intlclock_location_tile_tick), this); - - return this; - } -@@ -133,13 +152,99 @@ intlclock_location_tile_finalize (GObject *g_obj) - priv->location = NULL; - } - -+ if (priv->button_group) { -+ g_object_unref (priv->button_group); -+ priv->button_group = NULL; -+ } -+ - G_OBJECT_CLASS (intlclock_location_tile_parent_class)->finalize (g_obj); - } - -+static gboolean -+press_on_tile (GtkWidget *widget, -+ GdkEventButton *event, -+ IntlClockLocationTile *tile) -+{ -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ -+ intlclock_blink_location (priv->clock, priv->location); -+ -+ return TRUE; -+} -+ -+static void -+make_current (GtkWidget *widget, IntlClockLocationTile *tile) -+{ -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ GError *error = NULL; -+ GtkWidget *dialog; -+ -+ if (intlclock_location_make_current (priv->location, &error)) { -+ g_signal_emit_by_name (priv->clock, "current-timezone-changed", 0); -+ } -+ else if (error) { -+ dialog = gtk_message_dialog_new (NULL, -+ 0, -+ GTK_MESSAGE_ERROR, -+ GTK_BUTTONS_OK, -+ _("Failed to set the system timezone")); -+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), error->message); -+ g_signal_connect (dialog, "response", -+ G_CALLBACK (gtk_widget_destroy), NULL); -+ gtk_window_present (GTK_WINDOW (dialog)); -+ -+ g_error_free (error); -+ } -+} -+ -+static gboolean -+enter_or_leave_tile (GtkWidget *widget, -+ GdkEventCrossing *event, -+ IntlClockLocationTile *tile) -+{ -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ -+ if (event->type == GDK_ENTER_NOTIFY) { -+ gint can_set; -+ -+ can_set = can_set_system_timezone (); -+ if (!intlclock_location_is_current (priv->location) && -+ can_set != 0) { -+ gtk_label_set_markup (GTK_LABEL (priv->current_label), -+ can_set == 1 ? -+ _("Set...") : -+ _("Set")); -+ gtk_widget_show (priv->current_button); -+ } -+ } -+ else { -+ if (event->detail != GDK_NOTIFY_INFERIOR) -+ gtk_widget_hide (priv->current_button); -+ } -+ -+ return TRUE; -+} -+ - static void - intlclock_location_tile_fill (IntlClockLocationTile *this) - { - IntlClockLocationTilePrivate *priv = PRIVATE (this); -+ GtkWidget *align; -+ GtkWidget *strut; -+ GtkWidget *box; -+ -+ 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); -+ -+ GtkWidget *alignment = gtk_alignment_new (0, 0, 1, 0); -+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 3, 3, 3, 0); - - GtkWidget *tile = gtk_hbox_new (FALSE, 6); - GtkWidget *head_section = gtk_vbox_new (FALSE, 0); -@@ -147,21 +252,55 @@ intlclock_location_tile_fill (IntlClockLocationTile *this) - 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); - -- gtk_box_pack_start (GTK_BOX (head_section), priv->city_label, -- FALSE, FALSE, 0); -- gtk_box_pack_start (GTK_BOX (head_section), priv->time_label, -- FALSE, FALSE, 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 (); -+ 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 as current timezone for this computer")); -+ -+ priv->current_marker = gtk_image_new_from_icon_name ("go-home", GTK_ICON_SIZE_BUTTON); -+ gtk_widget_set_no_show_all (priv->current_marker, TRUE); -+ -+ align = gtk_alignment_new (1, 1, 0, 0); -+ 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); -+ 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); -+ -+ g_signal_connect (priv->current_button, "clicked", -+ G_CALLBACK (make_current), this); - - priv->clock_face = intlclock_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, FALSE, FALSE, 0); -+ gtk_box_pack_start (GTK_BOX (tile), head_section, TRUE, TRUE, 0); - -- gtk_container_add (GTK_CONTAINER (this), tile); -+ gtk_container_add (GTK_CONTAINER (alignment), tile); -+ gtk_container_add (GTK_CONTAINER (priv->box), alignment); -+ gtk_container_add (GTK_CONTAINER (this), priv->box); - - intlclock_location_tile_refresh (this); - } -@@ -231,6 +370,21 @@ intlclock_location_tile_refresh (IntlClockLocationTile *this) - char buf[256]; - struct tm now; - -+ if (intlclock_location_is_current (priv->location)) { -+ if (!GTK_WIDGET_VISIBLE (priv->current_marker)) { -+ GdkPixbuf *pixbuf; -+ -+ pixbuf = gtk_image_get_pixbuf (GTK_IMAGE (priv->weather_icon)); -+ intlclock_ui_update_weather_icon (priv->ui, pixbuf); -+ } -+ -+ gtk_widget_hide (priv->current_button); -+ gtk_widget_show (priv->current_marker); -+ } -+ else { -+ gtk_widget_hide (priv->current_marker); -+ } -+ - if (intlclock_needs_face_refresh (this)) { - intlclock_face_refresh (INTLCLOCK_FACE (priv->clock_face)); - } -@@ -271,3 +425,87 @@ intlclock_location_tile_tick (IntlClock *clock, - - intlclock_location_tile_refresh (this); - } -+ -+static gboolean -+weather_tooltip (GtkWidget *widget, -+ gint x, -+ gint y, -+ gboolean keyboard_mode, -+ GtkTooltip *tooltip, -+ gpointer data) -+{ -+ IntlClockLocationTile *tile = data; -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ WeatherInfo *info; -+ GdkPixbuf *pixbuf = NULL; -+ gchar *conditions, *temp, *apparent, *wind; -+ gchar *line1, *line2, *line3, *line4, *tip; -+ -+ info = intlclock_location_get_weather_info (priv->location); -+ -+ if (!info || !weather_info_is_valid (info)) -+ return FALSE; -+ -+ weather_info_get_pixbuf (info, &pixbuf); -+ 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)); -+ -+ temp = weather_info_get_temp (info); -+ apparent = weather_info_get_apparent (info); -+ if (strcmp (apparent, temp) != 0 && -+ /* FIXME libgweather needs some real api */ -+ strcmp (apparent, dgettext ("gnome-applets-2.0", "Unknown")) != 0) -+ line2 = g_strdup_printf (_("%s, feels like %s"), temp, apparent); -+ else -+ line2 = g_strdup (temp); -+ -+ wind = weather_info_get_wind (info); -+ if (strcmp (apparent, dgettext ("gnome-applets-2.0", "Unknown")) != 0) -+ line3 = g_strdup_printf ("%s\n", wind); -+ else -+ line3 = g_strdup (""); -+ -+ line4 = g_strdup_printf (_("Sunrise: %s / Sunset: %s"), -+ weather_info_get_sunrise (info), -+ weather_info_get_sunset (info)); -+ -+ 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); -+ -+ return TRUE; -+} -+ -+ -+static void -+update_weather_icon (IntlClockLocation *loc, WeatherInfo *info, gpointer data) -+{ -+ IntlClockLocationTile *tile = data; -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ GdkPixbuf *pixbuf = NULL; -+ -+ if (!info || !weather_info_is_valid (info)) -+ return; -+ -+ weather_info_get_pixbuf_mini (info, &pixbuf); -+ -+ 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); -+ if (intlclock_location_is_current (loc)) -+ intlclock_ui_update_weather_icon (priv->ui, pixbuf); -+ } -+} -+ -diff --git a/src/intlclock-location.c b/src/intlclock-location.c -index 384b2aa..0a37b48 100644 ---- a/src/intlclock-location.c -+++ b/src/intlclock-location.c -@@ -1,4 +1,3 @@ --#include "intlclock-location.h" - - #ifdef HAVE_CONFIG_H - #include -@@ -13,9 +12,16 @@ - #include - #include - #include -+#include - - #include - #include -+#include -+ -+#include "intlclock-location.h" -+#include "intlclock-marshallers.h" -+#include "set-timezone.h" -+#include "gweather-xml.h" - - G_DEFINE_TYPE (IntlClockLocation, intlclock_location, G_TYPE_OBJECT) - -@@ -29,17 +35,31 @@ typedef struct { - - gfloat latitude; - gfloat longitude; -+ -+ gchar *weather_code; -+ WeatherInfo *weather_info; -+ guint weather_timeout; -+ - } IntlClockLocationPrivate; - -+enum { -+ WEATHER_UPDATED, -+ LAST_SIGNAL -+}; -+ -+static guint location_signals[LAST_SIGNAL] = { 0 }; -+ - static void intlclock_location_finalize (GObject *); - static void intlclock_location_set_tz (IntlClockLocation *this); - static void intlclock_location_unset_tz (IntlClockLocation *this); -+static void setup_weather_updates (IntlClockLocation *loc); - - #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INTLCLOCK_LOCATION_TYPE, IntlClockLocationPrivate)) - - IntlClockLocation * - intlclock_location_new (const gchar *name, const gchar *timezone, -- gfloat latitude, gfloat longitude) -+ gfloat latitude, gfloat longitude, -+ const gchar *code) - { - IntlClockLocation *this; - IntlClockLocationPrivate *priv; -@@ -62,6 +82,9 @@ intlclock_location_new (const gchar *name, const gchar *timezone, - priv->latitude = latitude; - priv->longitude = longitude; - -+ priv->weather_code = g_strdup (code); -+ setup_weather_updates (this); -+ - return this; - } - -@@ -193,6 +216,77 @@ guess_zone_from_tree (const gchar *localtime, IntlClockZoneTable *zones) - return ret; - } - -+static const gchar *current_zone = NULL; -+static GnomeVFSMonitorHandle *monitor = NULL; -+ -+static void -+parse_etc_sysconfig_clock (void) -+{ -+ gchar *data; -+ gsize len; -+ gchar **lines; -+ gchar *res; -+ gint i; -+ gchar *p, *q; -+ -+ lines = NULL; -+ res = NULL; -+ if (g_file_test ("/etc/sysconfig/clock", -+ G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { -+ if (!g_file_get_contents ("/etc/sysconfig/clock", -+ &data, &len, NULL)) -+ goto out; -+ -+ lines = g_strsplit (data, "\n", 0); -+ g_free (data); -+ -+ for (i = 0; lines[i] && !res; i++) { -+ if (g_str_has_prefix (lines[i], "ZONE=")) { -+ p = lines[i] + strlen ("ZONE="); -+ if (p[0] != '\"') -+ goto out; -+ p++; -+ q = strchr (p, '\"'); -+ q[0] = '\0'; -+ res = g_strdup (p); -+ } -+ } -+ } -+ -+out: -+ if (lines) -+ g_strfreev (lines); -+ -+ g_free (current_zone); -+ current_zone = res; -+} -+ -+static void -+monitor_etc_sysconfig_clock (GnomeVFSMonitorHandle *handle, -+ const gchar *monitor_uri, -+ const gchar *info_uri, -+ GnomeVFSMonitorEventType event_type, -+ gpointer user_data) -+{ -+ parse_etc_sysconfig_clock (); -+} -+ -+static const gchar * -+zone_from_etc_sysconfig_clock (void) -+{ -+ if (monitor == NULL) { -+ parse_etc_sysconfig_clock (); -+ -+ gnome_vfs_monitor_add (&monitor, -+ "/etc/sysconfig/clock", -+ GNOME_VFS_MONITOR_FILE, -+ monitor_etc_sysconfig_clock, -+ NULL); -+ } -+ -+ return current_zone; -+} -+ - static gchar * - intlclock_location_guess_zone (IntlClockZoneTable *zones) - { -@@ -200,6 +294,12 @@ intlclock_location_guess_zone (IntlClockZoneTable *zones) - const char *localtime = "/etc/localtime"; - gchar *linkfile = NULL; - GError *err = NULL; -+ gchar *zone; -+ -+ /* look for /etc/sysconfig/clock */ -+ if ((zone = zone_from_etc_sysconfig_clock ())) { -+ return g_strdup (zone); -+ } - - /* guess the current time zone by readlink() on /etc/localtime */ - linkfile = g_file_read_link (localtime, &err); -@@ -235,14 +335,14 @@ intlclock_location_new_from_env (IntlClockZoneTable *zones) - - if (zone == NULL) { - /* make a fake location with a null TZ */ -- return intlclock_location_new (_("Unknown Location"), NULL, 0.0, 0.0); -+ return intlclock_location_new (_("Unknown Location"), NULL, 0.0, 0.0, NULL); - } - - info = intlclock_zonetable_get_zone (zones, zone); - - if (info == NULL) { - /* make a fake location with the current TZ */ -- return intlclock_location_new (_("Unknown Location"), zone, 0.0, 0.0); -+ return intlclock_location_new (_("Unknown Location"), zone, 0.0, 0.0, NULL); - } - - g_free (zone); -@@ -260,7 +360,7 @@ intlclock_location_new_from_env (IntlClockZoneTable *zones) - } - - ret = intlclock_location_new (name, intlclock_zoneinfo_get_name (info), -- lat, lon); -+ lat, lon, NULL); - - g_free (name); - -@@ -274,6 +374,15 @@ intlclock_location_class_init (IntlClockLocationClass *this_class) - - g_obj_class->finalize = intlclock_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 (IntlClockLocationClass, weather_updated), -+ NULL, NULL, -+ _intlclock_marshal_VOID__POINTER, -+ G_TYPE_NONE, 1, G_TYPE_POINTER); -+ - g_type_class_add_private (this_class, sizeof (IntlClockLocationPrivate)); - } - -@@ -318,6 +427,21 @@ intlclock_location_finalize (GObject *g_obj) - 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 (intlclock_location_parent_class)->finalize (g_obj); - } - -@@ -467,3 +591,179 @@ intlclock_location_localtime (IntlClockLocation *loc, struct tm *tm) - - intlclock_location_unset_tz (loc); - } -+ -+gboolean -+intlclock_location_is_current (IntlClockLocation *loc) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ gboolean current; -+ long sys_timezone; -+ const char *zone; -+ -+ if ((zone = zone_from_etc_sysconfig_clock ())) -+ return strcmp (zone, priv->timezone) == 0; -+ -+ unsetenv ("TZ"); -+ tzset (); -+ sys_timezone = timezone; -+ -+ setenv ("TZ", priv->timezone, 1); -+ tzset(); -+ -+ current = sys_timezone == timezone; -+ -+ if (priv->sys_timezone) { -+ setenv ("TZ", priv->sys_timezone, 1); -+ } else { -+ unsetenv ("TZ"); -+ } -+ tzset(); -+ -+ return current; -+} -+ -+gboolean -+intlclock_location_make_current (IntlClockLocation *loc, GError **error) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ gchar *filename; -+ gboolean ret; -+ -+ filename = g_build_filename (SYSTEM_ZONEINFODIR, priv->timezone, NULL); -+ ret = set_system_timezone (filename, error); -+ g_free (filename); -+ -+ if (ret) { -+ /* FIXME this ugly shortcut is necessary until we move the -+ * current timezone tracking to intlclock.c and emit the -+ * signal from there -+ */ -+ g_free (current_zone); -+ current_zone = g_strdup (priv->timezone); -+ } -+ -+ return ret; -+} -+ -+const gchar * -+intlclock_location_get_weather_code (IntlClockLocation *loc) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ -+ return priv->weather_code; -+} -+ -+void -+intlclock_location_set_weather_code (IntlClockLocation *loc, const gchar *code) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ -+ g_free (priv->weather_code); -+ priv->weather_code = g_strdup (code); -+ -+ setup_weather_updates (loc); -+} -+ -+WeatherInfo * -+intlclock_location_get_weather_info (IntlClockLocation *loc) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ -+ return priv->weather_info; -+} -+ -+static void -+weather_info_updated (WeatherInfo *info, gpointer data) -+{ -+ IntlClockLocation *loc = data; -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ -+ g_signal_emit (loc, location_signals[WEATHER_UPDATED], -+ 0, priv->weather_info); -+} -+ -+static gboolean -+update_weather_info (gpointer data) -+{ -+ IntlClockLocation *loc = data; -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ WeatherPrefs prefs = { -+ FORECAST_STATE, -+ FALSE, -+ NULL, -+ TEMP_UNIT_CENTIGRADE, -+ SPEED_UNIT_MS, -+ PRESSURE_UNIT_MB, -+ DISTANCE_UNIT_KM -+ }; -+ -+ 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 void -+setup_weather_updates (IntlClockLocation *loc) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ const gchar *code; -+ WeatherLocation *wl; -+ WeatherPrefs prefs = { -+ FORECAST_STATE, -+ FALSE, -+ NULL, -+ TEMP_UNIT_CENTIGRADE, -+ SPEED_UNIT_MS, -+ PRESSURE_UNIT_MB, -+ DISTANCE_UNIT_KM -+ }; -+ gfloat lat, lon; -+ gchar *dms; -+ -+ 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, "-") == 0) -+ return; -+ -+ dms = rad2dms (priv->latitude, priv->longitude); -+ wl = weather_location_new (priv->name, priv->weather_code, -+ NULL, NULL, dms); -+ -+ priv->weather_info = -+ weather_info_new (wl, &prefs, weather_info_updated, loc); -+ -+ priv->weather_timeout = -+ g_timeout_add_seconds (1800, update_weather_info, loc); -+ -+ weather_location_free (wl); -+ g_free (dms); -+} -+ -diff --git a/src/intlclock-location.h b/src/intlclock-location.h -index 824ee3c..deb7074 100644 ---- a/src/intlclock-location.h -+++ b/src/intlclock-location.h -@@ -4,6 +4,7 @@ - #include - #include - #include -+#include - - #include "intlclock-zonetable.h" - -@@ -24,12 +25,16 @@ typedef struct - typedef struct - { - GObjectClass g_object_class; -+ -+ void (* weather_updated) (IntlClockLocation *location, WeatherInfo *info); -+ - } IntlClockLocationClass; - - GType intlclock_location_get_type (void); - - IntlClockLocation *intlclock_location_new (const gchar *name, const gchar *timezone, -- gfloat latitude, gfloat longitude); -+ gfloat latitude, gfloat longitude, -+ const gchar *code); - - IntlClockLocation *intlclock_location_new_from_env (IntlClockZoneTable *zones); - -@@ -46,5 +51,12 @@ void intlclock_location_set_coords (IntlClockLocation *loc, gfloat latitude, gfl - - void intlclock_location_localtime (IntlClockLocation *loc, struct tm *tm); - -+gboolean intlclock_location_is_current (IntlClockLocation *loc); -+gboolean intlclock_location_make_current (IntlClockLocation *loc, GError **error); -+ -+const gchar *intlclock_location_get_weather_code (IntlClockLocation *loc); -+void intlclock_location_set_weather_code (IntlClockLocation *loc, const gchar *code); -+WeatherInfo *intlclock_location_get_weather_info (IntlClockLocation *loc); -+ - G_END_DECLS - #endif /* __INTLCLOCK_LOCATION_H__ */ -diff --git a/src/intlclock-map.c b/src/intlclock-map.c -index 2d72975..9ded127 100644 ---- a/src/intlclock-map.c -+++ b/src/intlclock-map.c -@@ -25,7 +25,7 @@ typedef struct { - gint height; - - GdkPixbuf *stock_map_pixbuf; -- GdkPixbuf *location_marker_pixbuf; -+ GdkPixbuf *location_marker_pixbuf[3]; - - GdkPixbuf *location_map_pixbuf; - -@@ -54,6 +54,7 @@ static void intlclock_map_display (IntlClockMap *this); - - - static void intlclock_map_locations_changed (IntlClock *clock, IntlClockMap *this); -+static void intlclock_map_blink_location (IntlClock *clock, IntlClockLocation *loc, IntlClockMap *this); - static void intlclock_map_tick (IntlClock *clock, IntlClockMap *this); - - #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INTLCLOCK_MAP_TYPE, IntlClockMapPrivate)) -@@ -69,8 +70,12 @@ intlclock_map_new (IntlClock *clock) - - priv->clock = g_object_ref (clock); - -- priv->location_marker_pixbuf = rsvg_pixbuf_from_file -- (INTLCLOCK_ICONDIR "/intlclock-map-location-marker.svg", NULL); -+ priv->location_marker_pixbuf[0] = gdk_pixbuf_new_from_file -+ (INTLCLOCK_ICONDIR "/intlclock-map-location-marker.png", NULL); -+ priv->location_marker_pixbuf[1] = gdk_pixbuf_new_from_file -+ (INTLCLOCK_ICONDIR "/intlclock-map-location-hilight.png", NULL); -+ priv->location_marker_pixbuf[2] = gdk_pixbuf_new_from_file -+ (INTLCLOCK_ICONDIR "/intlclock-map-location-current.png", NULL); - - g_signal_connect (G_OBJECT (priv->clock), "tick", - G_CALLBACK (intlclock_map_tick), this); -@@ -78,6 +83,12 @@ intlclock_map_new (IntlClock *clock) - g_signal_connect (G_OBJECT (priv->clock), "locations_changed", - G_CALLBACK (intlclock_map_locations_changed), this); - -+ g_signal_connect (G_OBJECT (priv->clock), "current_timezone_changed", -+ G_CALLBACK (intlclock_map_locations_changed), this); -+ -+ g_signal_connect (G_OBJECT (priv->clock), "blink_location", -+ G_CALLBACK (intlclock_map_blink_location), this); -+ - intlclock_map_refresh (this); - - return this; -@@ -109,13 +120,16 @@ intlclock_map_init (IntlClockMap *this) - priv->clock = NULL; - - priv->stock_map_pixbuf = NULL; -- priv->location_marker_pixbuf = NULL; -+ priv->location_marker_pixbuf[0] = NULL; -+ priv->location_marker_pixbuf[1] = NULL; -+ priv->location_marker_pixbuf[2] = NULL; - } - - static void - intlclock_map_finalize (GObject *g_obj) - { - IntlClockMapPrivate *priv = PRIVATE (g_obj); -+ int i; - - g_signal_handlers_disconnect_by_func - (priv->clock, G_CALLBACK (intlclock_map_tick), g_obj); -@@ -130,10 +144,12 @@ intlclock_map_finalize (GObject *g_obj) - priv->stock_map_pixbuf = NULL; - } - -- if (priv->location_marker_pixbuf) { -- gdk_pixbuf_unref (priv->location_marker_pixbuf); -- priv->location_marker_pixbuf = NULL; -- } -+ for (i = 0; i < 3; i++) { -+ if (priv->location_marker_pixbuf[i]) { -+ gdk_pixbuf_unref (priv->location_marker_pixbuf[i]); -+ priv->location_marker_pixbuf[i] = NULL; -+ } -+ } - - if (priv->location_map_pixbuf) { - gdk_pixbuf_unref (priv->location_map_pixbuf); -@@ -164,12 +180,13 @@ intlclock_map_refresh (IntlClockMap *this) - IntlClockMapPrivate *priv = PRIVATE (this); - GtkWidget *widget = GTK_WIDGET (this); - GtkWidget *parent = gtk_widget_get_parent (widget); -+ GtkRequisition req; - gint width; - gint height; - -- gtk_widget_size_request (widget, &(widget->requisition)); -- width = widget->requisition.width; -- height = widget->requisition.height; -+ gtk_widget_size_request (widget, &req); -+ width = req.width; -+ height = req.height; - - if (parent) { - if (widget->allocation.width != 1) { -@@ -276,10 +293,10 @@ intlclock_map_size_allocate (GtkWidget *this, GtkAllocation *allocation) - } - - static void --intlclock_map_mark (IntlClockMap *this, gfloat latitude, gfloat longitude) -+intlclock_map_mark (IntlClockMap *this, gfloat latitude, gfloat longitude, gint mark) - { - IntlClockMapPrivate *priv = PRIVATE (this); -- GdkPixbuf *marker = priv->location_marker_pixbuf; -+ GdkPixbuf *marker = priv->location_marker_pixbuf[mark]; - GdkPixbuf *partial = NULL; - - int x, y; -@@ -395,14 +412,22 @@ intlclock_map_mark (IntlClockMap *this, gfloat latitude, gfloat longitude) - } - - static void --intlclock_map_place_location (IntlClockMap *this, IntlClockLocation *loc) -+intlclock_map_place_location (IntlClockMap *this, IntlClockLocation *loc, gboolean hilight) - { - IntlClockMapPrivate *priv = PRIVATE (this); - gfloat latitude, longitude; -+ gint marker; - - intlclock_location_get_coords (loc, &latitude, &longitude); - -- intlclock_map_mark (this, latitude, longitude); -+ if (hilight) -+ marker = 1; -+ else if (intlclock_location_is_current (loc)) -+ marker = 2; -+ else -+ marker = 0; -+ -+ intlclock_map_mark (this, latitude, longitude, marker); - } - - static void -@@ -428,7 +453,7 @@ intlclock_map_place_locations (IntlClockMap *this) - while (locs) { - loc = INTLCLOCK_LOCATION (locs->data); - -- intlclock_map_place_location (this, loc); -+ intlclock_map_place_location (this, loc, FALSE); - - locs = locs->next; - } -@@ -633,16 +658,12 @@ intlclock_map_rotate (IntlClockMap *this) - static void - intlclock_map_display (IntlClockMap *this) - { -- IntlClockMapPrivate *priv = PRIVATE (this); -- - gtk_widget_queue_draw (GTK_WIDGET (this)); - } - - static void - intlclock_map_locations_changed (IntlClock *clock, IntlClockMap *this) - { -- IntlClockMapPrivate *priv = PRIVATE (this); -- - intlclock_map_place_locations (this); - - intlclock_map_render_shadow (this); -@@ -651,6 +672,49 @@ intlclock_map_locations_changed (IntlClock *clock, IntlClockMap *this) - intlclock_map_display (this); - } - -+typedef struct { -+ IntlClockMap *map; -+ IntlClockLocation *location; -+ int count; -+} BlinkData; -+ -+static gboolean -+highlight (gpointer user_data) -+{ -+ BlinkData *data = user_data; -+ -+ if (data->count == 6) { -+ g_free (data); -+ return FALSE; -+ } -+ -+ if (data->count % 2 == 0) -+ intlclock_map_place_location (data->map, data->location, TRUE); -+ else -+ intlclock_map_place_locations (data->map); -+ intlclock_map_render_shadow (data->map); -+ intlclock_map_rotate (data->map); -+ intlclock_map_display (data->map); -+ -+ data->count++; -+ -+ return TRUE; -+} -+ -+static void -+intlclock_map_blink_location (IntlClock *clock, IntlClockLocation *loc, IntlClockMap *this) -+{ -+ BlinkData *data; -+ -+ data = g_new0 (BlinkData, 1); -+ data->map = this; -+ data->location = loc; -+ -+ highlight (data); -+ -+ g_timeout_add (300, highlight, data); -+} -+ - static gboolean - intlclock_map_needs_refresh (IntlClockMap *this) - { -diff --git a/src/intlclock-marshallers.c b/src/intlclock-marshallers.c -deleted file mode 100644 -index 8f01ab8..0000000 ---- a/src/intlclock-marshallers.c -+++ /dev/null -@@ -1,51 +0,0 @@ -- --#include -- -- --#ifdef G_ENABLE_DEBUG --#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) --#define g_marshal_value_peek_char(v) g_value_get_char (v) --#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) --#define g_marshal_value_peek_int(v) g_value_get_int (v) --#define g_marshal_value_peek_uint(v) g_value_get_uint (v) --#define g_marshal_value_peek_long(v) g_value_get_long (v) --#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) --#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) --#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) --#define g_marshal_value_peek_enum(v) g_value_get_enum (v) --#define g_marshal_value_peek_flags(v) g_value_get_flags (v) --#define g_marshal_value_peek_float(v) g_value_get_float (v) --#define g_marshal_value_peek_double(v) g_value_get_double (v) --#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) --#define g_marshal_value_peek_param(v) g_value_get_param (v) --#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) --#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) --#define g_marshal_value_peek_object(v) g_value_get_object (v) --#else /* !G_ENABLE_DEBUG */ --/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. -- * Do not access GValues directly in your code. Instead, use the -- * g_value_get_*() functions -- */ --#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int --#define g_marshal_value_peek_char(v) (v)->data[0].v_int --#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint --#define g_marshal_value_peek_int(v) (v)->data[0].v_int --#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint --#define g_marshal_value_peek_long(v) (v)->data[0].v_long --#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong --#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 --#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 --#define g_marshal_value_peek_enum(v) (v)->data[0].v_long --#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong --#define g_marshal_value_peek_float(v) (v)->data[0].v_float --#define g_marshal_value_peek_double(v) (v)->data[0].v_double --#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer --#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer --#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer --#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer --#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer --#endif /* !G_ENABLE_DEBUG */ -- -- --/* VOID:VOID (intlclock-marshallers.list:1) */ -- -diff --git a/src/intlclock-marshallers.h b/src/intlclock-marshallers.h -deleted file mode 100644 -index c022a3e..0000000 ---- a/src/intlclock-marshallers.h -+++ /dev/null -@@ -1,15 +0,0 @@ -- --#ifndef ___intlclock_marshal_MARSHAL_H__ --#define ___intlclock_marshal_MARSHAL_H__ -- --#include -- --G_BEGIN_DECLS -- --/* VOID:VOID (intlclock-marshallers.list:1) */ --#define _intlclock_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID -- --G_END_DECLS -- --#endif /* ___intlclock_marshal_MARSHAL_H__ */ -- -diff --git a/src/intlclock-marshallers.list b/src/intlclock-marshallers.list -index 5b76282..e737cac 100644 ---- a/src/intlclock-marshallers.list -+++ b/src/intlclock-marshallers.list -@@ -1 +1,3 @@ - VOID:VOID -+VOID:OBJECT -+VOID:POINTER -diff --git a/src/intlclock-sunpos.c b/src/intlclock-sunpos.c -index 942617b..89d4cc1 100644 ---- a/src/intlclock-sunpos.c -+++ b/src/intlclock-sunpos.c -@@ -1,348 +1,196 @@ - /* -- * sunpos.c -- * kirk johnson -- * july 1993 -+ * Copyright (C) 2007 Red Hat, Inc. - * -- * includes revisions from Frank T. Solensky, february 1999 -+ * 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. - * -- * code for calculating the position on the earth's surface for which -- * the sun is directly overhead (adapted from _practical astronomy -- * with your calculator, third edition_, peter duffett-smith, -- * cambridge university press, 1988.) -+ * 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. - * -- * Copyright (C) 1989, 1990, 1993-1995, 1999 Kirk Lauritz Johnson -+ * 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. - * -- * Parts of the source code (as marked) are: -- * Copyright (C) 1989, 1990, 1991 by Jim Frost -- * Copyright (C) 1992 by Jamie Zawinski -- * -- * Permission to use, copy, modify and freely distribute xearth for -- * non-commercial and not-for-profit purposes is hereby granted -- * without fee, provided that both the above copyright notice and this -- * permission notice appear in all copies and in supporting -- * documentation. -- * -- * Unisys Corporation holds worldwide patent rights on the Lempel Zev -- * Welch (LZW) compression technique employed in the CompuServe GIF -- * image file format as well as in other formats. Unisys has made it -- * clear, however, that it does not require licensing or fees to be -- * paid for freely distributed, non-commercial applications (such as -- * xearth) that employ LZW/GIF technology. Those wishing further -- * information about licensing the LZW patent should contact Unisys -- * directly at (lzw_info@unisys.com) or by writing to -- * -- * Unisys Corporation -- * Welch Licensing Department -- * M/S-C1SW19 -- * P.O. Box 500 -- * Blue Bell, PA 19424 -- * -- * The author makes no representations about the suitability of this -- * software for any purpose. It is provided "as is" without express or -- * implied warranty. -- * -- * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, -- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT -- * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ * Authors: -+ * Jonathan Blandford -+ * Matthias Clasen - */ -- --#include --#include -+ - #include -+#include -+#include - --#include "intlclock-sunpos.h" -- --#define TWOPI (2*M_PI) --#define DegsToRads(x) ((x)*(TWOPI/360)) -- --/* -- * the epoch upon which these astronomical calculations are based is -- * 1990 january 0.0, 631065600 seconds since the beginning of the -- * "unix epoch" (00:00:00 GMT, Jan. 1, 1970) -- * -- * given a number of seconds since the start of the unix epoch, -- * DaysSinceEpoch() computes the number of days since the start of the -- * astronomical epoch (1990 january 0.0) -- */ -- --#define EpochStart (631065600) --#define DaysSinceEpoch(secs) (((secs)-EpochStart)*(1.0/(24*3600))) -- --/* -- * assuming the apparent orbit of the sun about the earth is circular, -- * the rate at which the orbit progresses is given by RadsPerDay -- -- * TWOPI radians per orbit divided by 365.242191 days per year: -- */ -- --#define RadsPerDay (TWOPI/365.242191) -- --/* -- * details of sun's apparent orbit at epoch 1990.0 (after -- * duffett-smith, table 6, section 46) -- * -- * Epsilon_g (ecliptic longitude at epoch 1990.0) 279.403303 degrees -- * OmegaBar_g (ecliptic longitude of perigee) 282.768422 degrees -- * Eccentricity (eccentricity of orbit) 0.016713 -+/* 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 orbit at epoch 1990.0 */ - --#define Epsilon_g (DegsToRads(279.403303)) --#define OmegaBar_g (DegsToRads(282.768422)) --#define Eccentricity (0.016713) -+#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 perigree */ -+#define ECCENTRICITY 0.016713 /* eccentricity of orbit */ -+#define R_0 149598500 /* km */ /* semi-major access */ -+#define THETA_0 0.533128 /* degrees */ /* angular diameter at r = r_0 */ -+#define MEAN_OBLIQUITY 23.440592 /* degrees */ /* mean obliquity of earths axis at epoch 1990.0 */ - --/* -- * MeanObliquity gives the mean obliquity of the earth's axis at epoch -- * 1990.0 (computed as 23.440592 degrees according to the method given -- * in duffett-smith, section 27) -- */ --#define MeanObliquity (23.440592*(TWOPI/360)) -+#define NORMALIZE(x) \ -+ while (x>360) x-=360; while (x<0) x+= 360; - --/* -- * Lunar parameters, epoch January 0, 1990.0 -- */ --#define MoonMeanLongitude DegsToRads(318.351648) --#define MoonMeanLongitudePerigee DegsToRads( 36.340410) --#define MoonMeanLongitudeNode DegsToRads(318.510107) --#define MoonInclination DegsToRads( 5.145396) -+#define DEG_TO_RADS(x) \ -+ (x * G_PI/180.0) - --#define SideralMonth (27.3217) -+#define RADS_TO_DEG(x) \ -+ (x * 180.0/G_PI) - --/* -- * Force an angular value into the range [-PI, +PI] -+/* Calculate number of days since 4713BC. - */ --#define Normalize(x) \ -- do { \ -- if ((x) < -M_PI) \ -- do (x) += TWOPI; while ((x) < -M_PI); \ -- else if ((x) > M_PI) \ -- do (x) -= TWOPI; while ((x) > M_PI); \ -- } while (0) -- --static double solve_keplers_equation (double); --static double mean_sun (double); --static double sun_ecliptic_longitude (time_t); --static void ecliptic_to_equatorial (double, double, double *, double *); --static double julian_date (int, int, int); --static double GST (time_t); -- --/* -- * solve Kepler's equation via Newton's method -- * (after duffett-smith, section 47) -- */ --static double solve_keplers_equation(M) -- double M; -+static gdouble -+unix_time_to_julian_date (gint unix_time) - { -- double E; -- double delta; -- -- E = M; -- while (1) -- { -- delta = E - Eccentricity*sin(E) - M; -- if (fabs(delta) <= 1e-10) break; -- E -= delta / (1 - Eccentricity*cos(E)); -- } -- -- return E; -+ 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 */ - --/* -- * Calculate the position of the mean sun: where the sun would -- * be if the earth's orbit were circular instead of ellipictal. -- */ -+#define ERROR_ACCURACY 1e-6 /* radians */ - --static double mean_sun (D) -- double D; /* days since ephemeris epoch */ -+static gdouble -+solve_keplers_equation (gdouble e, -+ gdouble M) - { -- double N, M; -+ gdouble d, E; - -- N = RadsPerDay * D; -- N = fmod(N, TWOPI); -- if (N < 0) N += TWOPI; -+ /* 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; -+ } - -- M = N + Epsilon_g - OmegaBar_g; -- if (M < 0) M += TWOPI; -- return M; -+ return E; - } - --/* -- * compute ecliptic longitude of sun (in radians) -- * (after duffett-smith, section 47) -- */ --static double sun_ecliptic_longitude(ssue) -- time_t ssue; /* seconds since unix epoch */ -+ /* convert the ecliptic longitude to right ascension and declination. Section 27. */ -+static void -+ecliptic_to_equatorial (gdouble lambda, -+ gdouble beta, -+ gdouble *ra, -+ gdouble *dec) - { -- double D; -- double M_sun, E; -- double v; -+ gdouble cos_mo; -+ gdouble sin_mo; - -- D = DaysSinceEpoch(ssue); -- M_sun = mean_sun(D); -+ g_assert (ra != NULL); -+ g_assert (dec != NULL); - -- E = solve_keplers_equation(M_sun); -- v = 2 * atan(sqrt((1+Eccentricity)/(1-Eccentricity)) * tan(E/2)); -+ sin_mo = sin (DEG_TO_RADS (MEAN_OBLIQUITY)); -+ cos_mo = cos (DEG_TO_RADS (MEAN_OBLIQUITY)); - -- return (v + OmegaBar_g); -+ *ra = atan2 (sin (lambda) * cos_mo - tan (beta) * sin_mo, cos (lambda)); -+ *dec = asin (sin (beta) * cos_mo + cos (beta) * sin_mo * sin (lambda)); - } - -- --/* -- * convert from ecliptic to equatorial coordinates -- * (after duffett-smith, section 27) -- */ --static void ecliptic_to_equatorial(lambda, beta, alpha, delta) -- double lambda; /* ecliptic longitude */ -- double beta; /* ecliptic latitude */ -- double *alpha; /* (return) right ascension */ -- double *delta; /* (return) declination */ -+/* calculate GST. Section 12 */ -+static gdouble -+greenwich_sidereal_time (gdouble unix_time) - { -- double sin_e, cos_e; -+ gdouble u, JD, T, T0, UT; - -- sin_e = sin(MeanObliquity); -- cos_e = cos(MeanObliquity); -+ 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); - -- *alpha = atan2(sin(lambda)*cos_e - tan(beta)*sin_e, cos(lambda)); -- *delta = asin(sin(beta)*cos_e + cos(beta)*sin_e*sin(lambda)); -+ return T0; - } - -- --/* -- * computing julian dates (assuming gregorian calendar, thus this is -- * only valid for dates of 1582 oct 15 or later) -- * (after duffett-smith, section 4) -- */ --static double julian_date(y, m, d) -- int y; /* year (e.g. 19xx) */ -- int m; /* month (jan=1, feb=2, ...) */ -- int d; /* day of month */ -+/* Calculate the position of the sun at a given time. pages 89-91 */ -+void -+sun_position (gint unix_time, gdouble *lat, gdouble *lon) - { -- int A, B, C, D; -- double JD; -+ gdouble jd, D, N, M, E, x, v, lambda; -+ gdouble ra, dec; -+ jd = unix_time_to_julian_date (unix_time); - -- /* lazy test to ensure gregorian calendar */ -- assert(y >= 1583); -+ /* Calculate number of days since the epoch */ -+ D = jd - EPOCH; - -- if ((m == 1) || (m == 2)) -- { -- y -= 1; -- m += 12; -- } -+ N = D*360/365.242191; - -- A = y / 100; -- B = 2 - A + (A / 4); -- C = 365.25 * y; -- D = 30.6001 * (m + 1); -+ /* normalize to 0 - 360 degrees */ -+ NORMALIZE (N); - -- JD = B + C + D + d + 1720994.5; -+ /* Step 4: */ -+ M = N + EPSILON_G - MU_G; -+ NORMALIZE (M); - -- return JD; --} -- -- --/* -- * compute greenwich mean sidereal time (GST) corresponding to a given -- * number of seconds since the unix epoch -- * (after duffett-smith, section 12) -- */ --static double GST(ssue) -- time_t ssue; /* seconds since unix epoch */ --{ -- double JD; -- double T, T0; -- double UT; -- struct tm *tm; -+ /* Step 5: convert to radians */ -+ M = DEG_TO_RADS (M); - -- tm = gmtime(&ssue); -+ /* Step 6: */ -+ E = solve_keplers_equation (ECCENTRICITY, M); - -- JD = julian_date(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday); -- T = (JD - 2451545) / 36525; -+ /* Step 7: */ -+ x = sqrt ((1 + ECCENTRICITY)/(1 - ECCENTRICITY)) * tan (E/2); - -- T0 = ((T + 2.5862e-5) * T + 2400.051336) * T + 6.697374558; -+ /* Step 8, 9 */ -+ v = 2 * RADS_TO_DEG (atan (x)); -+ NORMALIZE (v); - -- T0 = fmod(T0, 24.0); -- if (T0 < 0) T0 += 24; -+ /* Step 10 */ -+ lambda = v + MU_G; -+ NORMALIZE (lambda); - -- UT = tm->tm_hour + (tm->tm_min + tm->tm_sec / 60.0) / 60.0; -+ /* convert the ecliptic longitude to right ascension and declination */ -+ ecliptic_to_equatorial (DEG_TO_RADS (lambda), 0.0, &ra, &dec); - -- T0 += UT * 1.002737909; -- T0 = fmod(T0, 24.0); -- if (T0 < 0) T0 += 24; -+ ra = ra - (G_PI/12) * greenwich_sidereal_time (unix_time); -+ ra = RADS_TO_DEG (ra); -+ dec = RADS_TO_DEG (dec); -+ NORMALIZE (ra); -+ NORMALIZE (dec); - -- return T0; -+ *lat = dec; -+ *lon = ra; - } - - --/* -- * given a particular time (expressed in seconds since the unix -- * epoch), compute position on the earth (lat, lon) such that sun is -- * directly overhead. -- */ --void sun_position(ssue, lat, lon) -- time_t ssue; /* seconds since unix epoch */ -- double *lat; /* (return) latitude */ -- double *lon; /* (return) longitude */ -+#if 0 -+int -+main (int argc, char *argv[]) - { -- double lambda; -- double alpha, delta; -- double tmp; -+ gint i; -+ gint now; -+ GTimeVal timeval; -+ gdouble lat, lon; - -- lambda = sun_ecliptic_longitude(ssue); -- ecliptic_to_equatorial(lambda, 0.0, &alpha, &delta); -+ gtk_init (&argc, &argv); - -- tmp = alpha - (TWOPI/24)*GST(ssue); -- Normalize(tmp); -- *lon = tmp * (360/TWOPI); -- *lat = delta * (360/TWOPI); --} -+ 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); -+ } - --/* -- * given a particular time (expressed in seconds since the unix -- * epoch), compute position on the earth (lat, lon) such that the -- * moon is directly overhead. -- * -- * Based on duffett-smith **2nd ed** section 61; combines some steps -- * into single expressions to reduce the number of extra variables. -- */ --void moon_position(ssue, lat, lon) -- time_t ssue; /* seconds since unix epoch */ -- double *lat; /* (return) latitude */ -- double *lon; /* (return) longitude */ --{ -- double lambda, beta; -- double D, L, Ms, Mm, N, Ev, Ae, Ec, alpha, delta; -- -- D = DaysSinceEpoch(ssue); -- lambda = sun_ecliptic_longitude(ssue); -- Ms = mean_sun(D); -- -- L = fmod(D/SideralMonth, 1.0)*TWOPI + MoonMeanLongitude; -- Normalize(L); -- Mm = L - DegsToRads(0.1114041*D) - MoonMeanLongitudePerigee; -- Normalize(Mm); -- N = MoonMeanLongitudeNode - DegsToRads(0.0529539*D); -- Normalize(N); -- Ev = DegsToRads(1.2739) * sin(2.0*(L-lambda)-Mm); -- Ae = DegsToRads(0.1858) * sin(Ms); -- Mm += Ev - Ae - DegsToRads(0.37)*sin(Ms); -- Ec = DegsToRads(6.2886) * sin(Mm); -- L += Ev + Ec - Ae + DegsToRads(0.214) * sin(2.0*Mm); -- L += DegsToRads(0.6583) * sin(2.0*(L-lambda)); -- N -= DegsToRads(0.16) * sin(Ms); -- -- L -= N; -- lambda =(fabs(cos(L)) < 1e-12) ? -- (N + sin(L) * cos(MoonInclination) * M_PI/2) : -- (N + atan2(sin(L) * cos(MoonInclination), cos(L))); -- Normalize(lambda); -- beta = asin(sin(L) * sin(MoonInclination)); -- ecliptic_to_equatorial(lambda, beta, &alpha, &delta); -- alpha -= (TWOPI/24)*GST(ssue); -- Normalize(alpha); -- *lon = alpha * (360/TWOPI); -- *lat = delta * (360/TWOPI); -+ return 0; - } -+ -+#endif -diff --git a/src/intlclock-ui.c b/src/intlclock-ui.c -index f51e4de..f0d70bd 100644 ---- a/src/intlclock-ui.c -+++ b/src/intlclock-ui.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -26,18 +27,18 @@ - #include "intlclock-map.h" - #include "intlclock-zoneinfo.h" - #include "intlclock-zonetable.h" -+#include "set-timezone.h" -+#include "gweather-xml.h" - - G_DEFINE_TYPE (IntlClockUI, intlclock_ui, G_TYPE_OBJECT) - - /* GConf keys for compatibility with the older GNOME clock */ --#define N_GCONF_PREFS 7 -+#define N_GCONF_PREFS 5 - static const char *KEY_CITIES = "cities"; - static const char *KEY_FORMAT = "format"; - static const char *KEY_SHOW_SECONDS = "show_seconds"; - static const char *KEY_SHOW_DATE = "show_date"; - static const char *KEY_SHOW_WEEK = "show_week_numbers"; --static const char *KEY_SHOW_LOCATIONS = "show_locations"; --static const char *KEY_SHOW_MAP = "show_map"; - - /* Needs to match the indices in the combo */ - typedef enum { -@@ -78,12 +79,14 @@ typedef struct { - GtkWidget *panel_box; - GtkWidget *panel_button; - GtkWidget *panel_label; -+ GtkWidget *panel_weather_icon; - - GtkTooltips *panel_tips; - - GtkWidget *panel_button_popup; - - GtkWidget *clock_vbox; -+ GtkSizeGroup *clock_group; - - GtkWidget *main_section; - GtkWidget *clock_calendar; -@@ -97,17 +100,34 @@ typedef struct { - - GtkListStore *cities_store; - -- gboolean show_locations; -- gboolean show_map; -- - GtkWidget *prefs_window; - GtkTreeView *prefs_locations; - -+ GtkWidget *prefs_location_add_button; -+ GtkWidget *prefs_location_edit_button; -+ GtkWidget *prefs_location_remove_button; -+ -+ GtkWidget *location_tree; -+ GtkWidget *find_next_location_button; -+ GtkWidget *find_location_entry; -+ GtkWidget *find_location_ok_button; -+ -+ GtkWidget *set_time_window; -+ GtkWidget *hours_spin; -+ GtkWidget *minutes_spin; -+ GtkWidget *seconds_spin; -+ GtkWidget *calendar; -+ GtkWidget *current_time_label; -+ GtkWidget *set_time_button; -+ GtkWidget *time_settings_button; -+ - gboolean format_12hr; - gboolean format_show_seconds; - gboolean format_show_date; - gboolean format_show_week; - -+ gulong zone_combo_changed; -+ - guint listeners [N_GCONF_PREFS]; - } IntlClockUIPrivate; - -@@ -118,51 +138,51 @@ static gboolean update_panel_label (gpointer this); - static void setup_gconf (IntlClockUI *this); - static void load_gconf_settings (IntlClockUI *this); - --static void bonobo_run_time_configuration (BonoboUIComponent *uic, -- IntlClockUI *this, -- const gchar *verbname); - static void bonobo_display_properties_dialog (BonoboUIComponent *uic, - IntlClockUI *this, - const gchar *verbname); --static void display_help_dialog (BonoboUIComponent *uic, -- IntlClockUI *this, -- const gchar *verbname); --static void display_about_dialog (BonoboUIComponent *uic, -- IntlClockUI *this, -- const gchar *verbname); -- --static void config_date (BonoboUIComponent *uic, -- IntlClockUI *this, -- const gchar *verbname); - - static void intlclock_reposition_events_window (IntlClockUI *this); -- - static void position_popup_window (IntlClockUI *this, - GtkWindow *window, - GtkWidget *origin); - --static void display_prefs_window_cb (GtkButton *button, gpointer this); --static void run_time_configuration (IntlClockUI *this); --static void run_time_configuration_cb (GtkButton *button, gpointer this); -+static void display_prefs_window (IntlClockUI *this, gboolean locations); - static void run_prefs_locations_add (GtkButton *button, gpointer this); - static void run_prefs_locations_edit (GtkButton *button, gpointer this); - static void run_prefs_locations_remove (GtkButton *button, gpointer this); - static void run_prefs_edit_save (GtkButton *button, gpointer this); -- -+static void run_find_location (GtkButton *button, gpointer this); -+static void run_find_location_save (GtkButton *button, gpointer this); -+static void intlclock_edit_hide (GtkWidget *widget, IntlClockUI *this); -+static void intlclock_find_hide (GtkWidget *widget, IntlClockUI *this); - static void intlclock_ui_save_cities_store (IntlClockUI *this); - - static void intlclock_ui_locations_changed (IntlClock *clock, IntlClockUI *this); - - static void create_cities_section (IntlClockUI *this); - static void create_events_window (IntlClockUI *this); --static void create_main_section (IntlClockUI *this); - static void create_map_section (IntlClockUI *this); - - static void zone_combo_changed (GtkComboBox *widget, gpointer this); -+static void update_coords (IntlClockUI *this, gboolean valid, gfloat lat, gfloat lon); -+static void fill_location_tree (IntlClockUI *this); -+static void copy_time (BonoboUIComponent *uic, -+ IntlClockUI *this, -+ const gchar *verbname); -+static void copy_date (BonoboUIComponent *uic, -+ IntlClockUI *this, -+ const gchar *verbname); -+static void config_date (BonoboUIComponent *uic, -+ IntlClockUI *this, -+ const gchar *verbname); -+ - - static const BonoboUIVerb intlclock_menu_verbs [] = { - BONOBO_UI_UNSAFE_VERB ("IntlClockPreferences", bonobo_display_properties_dialog), -- BONOBO_UI_UNSAFE_VERB ("IntlClockConfig", bonobo_run_time_configuration), -+ BONOBO_UI_UNSAFE_VERB ("ClockCopyTime", copy_time), -+ BONOBO_UI_UNSAFE_VERB ("ClockCopyDate", copy_date), -+ BONOBO_UI_UNSAFE_VERB ("ClockConfig", config_date), - BONOBO_UI_VERB_END - }; - -@@ -190,11 +210,6 @@ intlclock_ui_is_12hr (IntlClockUI *this) - static gboolean - panel_button_press_cb (GtkWidget *button, GdkEventButton *event, gpointer data) - { -- IntlClockUI *this = INTLCLOCK_UI (data); -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (button); -- - if (event->button != 1) - g_signal_stop_emission_by_name (button, "button_press_event"); - -@@ -206,7 +221,9 @@ intlclock_ui_reset_timeout (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); - -- if (GTK_WIDGET_VISIBLE (priv->events_window) || priv->format_show_seconds) { -+ if (GTK_WIDGET_VISIBLE (priv->events_window) || -+ (priv->set_time_window && GTK_WIDGET_VISIBLE (priv->set_time_window)) || -+ priv->format_show_seconds) { - intlclock_set_tick_timeout (INTLCLOCK (priv->clock), 1); - } else { - intlclock_set_tick_timeout (INTLCLOCK (priv->clock), 60); -@@ -244,20 +261,6 @@ panel_button_clicked_cb (GtkButton *button, gpointer data) - intlclock_ui_reset_timeout (this); - } - --static gboolean --panel_events_button_press_cb (GtkWidget *button, GdkEventButton *event, gpointer data) --{ -- IntlClockUI *this = INTLCLOCK_UI (data); -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (button); -- -- if (event->button != 1) -- g_signal_stop_emission_by_name (button, "button_press_event"); -- -- return FALSE; --} -- - static void - position_popup_window (IntlClockUI *this, - GtkWindow *window, -@@ -375,147 +378,6 @@ intlclock_events_window_size_allocate_cb (GtkWidget *widget, GtkAllocation *allo - intlclock_reposition_events_window (this); - } - --static gboolean --intlclock_window_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) --{ -- IntlClockUIPrivate *priv = PRIVATE (user_data); -- -- cairo_t *cr; -- -- cr = gdk_cairo_create (widget->window); -- -- cairo_rectangle ( -- cr, -- event->area.x, event->area.y, -- event->area.width, event->area.height); -- -- cairo_clip (cr); -- --/* draw window background */ -- -- cairo_rectangle ( -- cr, -- widget->allocation.x + 0.5, widget->allocation.y + 0.5, -- widget->allocation.width - 1, widget->allocation.height - 1); -- -- cairo_set_source_rgb ( -- cr, -- widget->style->bg [GTK_STATE_ACTIVE].red / 65535.0, -- widget->style->bg [GTK_STATE_ACTIVE].green / 65535.0, -- widget->style->bg [GTK_STATE_ACTIVE].blue / 65535.0); -- -- cairo_fill_preserve (cr); -- --/* draw window outline */ -- -- cairo_set_source_rgb ( -- cr, -- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); -- -- cairo_set_line_width (cr, 1.0); -- cairo_stroke (cr); -- --/* draw main pane background */ -- -- cairo_rectangle ( -- cr, -- priv->main_section->allocation.x + 0.5, priv->main_section->allocation --.y + 0.5, -- priv->main_section->allocation.width - 1, priv->main_section->allocation.height - 1); -- -- cairo_set_source_rgb ( -- cr, -- widget->style->bg [GTK_STATE_NORMAL].red / 65535.0, -- widget->style->bg [GTK_STATE_NORMAL].green / 65535.0, -- widget->style->bg [GTK_STATE_NORMAL].blue / 65535.0); -- -- cairo_fill (cr); -- --/* draw map pane background */ -- -- if (priv->show_map) { -- cairo_rectangle ( -- cr, -- priv->map_section->allocation.x + 0.5, -- priv->map_section->allocation.y + 0.5, -- priv->map_section->allocation.width - 1, -- priv->map_section->allocation.height - 1); -- -- cairo_set_source_rgb ( -- cr, -- widget->style->bg [GTK_STATE_NORMAL].red / 65535.0, -- widget->style->bg [GTK_STATE_NORMAL].green / 65535.0, -- widget->style->bg [GTK_STATE_NORMAL].blue / 65535.0); -- -- cairo_fill (cr); -- } -- --/* draw internal window outline */ -- -- cairo_rectangle ( -- cr, -- priv->clock_vbox->allocation.x + 0.5, priv->clock_vbox->allocation.y + 0.5, -- priv->clock_vbox->allocation.width - 1, priv->clock_vbox->allocation.height - 1); -- -- cairo_set_source_rgb ( -- cr, -- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); -- -- cairo_stroke (cr); -- --/* draw map/cities pane separator */ -- -- if (priv->show_map) { -- cairo_move_to ( -- cr, -- priv->map_section->allocation.x + 0.5, -- priv->map_section->allocation.y + priv->map_section->allocation.height - 0.5); -- -- cairo_line_to ( -- cr, -- priv->map_section->allocation.x + priv->map_section->allocation.width - 0.5, -- priv->map_section->allocation.y + priv->map_section->allocation.height - 0.5); -- -- cairo_set_source_rgb ( -- cr, -- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); -- -- cairo_stroke (cr); -- } -- --/* draw cities/main pane separator */ -- -- if (priv->show_locations) { -- cairo_move_to ( -- cr, -- priv->cities_section->allocation.x + 0.5, -- priv->cities_section->allocation.y + priv->cities_section->allocation.height - 0.5); -- -- cairo_line_to ( -- cr, -- priv->cities_section->allocation.x + priv->cities_section->allocation.width - 0.5, -- priv->cities_section->allocation.y + priv->cities_section->allocation.height - 0.5); -- -- cairo_set_source_rgb ( -- cr, -- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); -- -- cairo_stroke (cr); -- } -- -- cairo_destroy (cr); -- -- return FALSE; --} -- - static void - intlclock_ui_tick (IntlClock *clock, IntlClockUI *this) - { -@@ -529,10 +391,7 @@ intlclock_ui_tick (IntlClock *clock, IntlClockUI *this) - static void - intlclock_ui_locations_changed (IntlClock *clock, IntlClockUI *this) - { -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- create_cities_section (this); -- intlclock_map_refresh (INTLCLOCK_MAP (priv->map_widget)); -+ create_cities_section (this); - } - - static gboolean -@@ -550,12 +409,20 @@ update_panel_label (gpointer this) - time (&now_t); - localtime_r (&now_t, &now); - -+ if (priv->current_time_label && -+ GTK_WIDGET_VISIBLE (priv->current_time_label)) { -+ date = intlclock_format_time (priv->clock, &now, -+ FALSE, FALSE, TRUE, -+ FALSE, FALSE, NULL, TRUE); -+ gtk_label_set_markup (GTK_LABEL (priv->current_time_label), date); -+ g_free (date); -+ } -+ - date = intlclock_format_time (priv->clock, &now, - priv->format_show_date, - priv->format_12hr, - priv->format_show_seconds, - FALSE, priv->format_show_date, NULL, TRUE); -- - gtk_label_set_markup (GTK_LABEL (priv->panel_label), date); - g_free (date); - -@@ -583,6 +450,7 @@ create_panel_buttons (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); - PanelAppletOrient orient; -+ GtkWidget *box; - - orient = panel_applet_get_orient (priv->panel_applet); - -@@ -590,13 +458,18 @@ create_panel_buttons (IntlClockUI *this) - case PANEL_APPLET_ORIENT_UP: - case PANEL_APPLET_ORIENT_DOWN: - priv->panel_box = gtk_hbox_new (FALSE, 0); -+ box = gtk_hbox_new (FALSE, 6); - break; - case PANEL_APPLET_ORIENT_RIGHT: - case PANEL_APPLET_ORIENT_LEFT: - priv->panel_box = gtk_vbox_new (FALSE, 0); -+ box = gtk_vbox_new (FALSE, 6); - break; -+ default: -+ g_assert_not_reached (); - } - priv->panel_label = gtk_label_new (NULL); -+ priv->panel_weather_icon = gtk_image_new (); - priv->panel_button = gtk_toggle_button_new (); - priv->panel_tips = gtk_tooltips_new (); - -@@ -626,8 +499,9 @@ create_panel_buttons (IntlClockUI *this) - gtk_button_set_relief (GTK_BUTTON (priv->panel_button), - GTK_RELIEF_NONE); - -- gtk_container_add (GTK_CONTAINER (priv->panel_button), -- priv->panel_label); -+ gtk_container_add (GTK_CONTAINER (priv->panel_button), box); -+ gtk_container_add (GTK_CONTAINER (box), priv->panel_weather_icon); -+ gtk_container_add (GTK_CONTAINER (box), priv->panel_label); - - g_signal_connect ( - G_OBJECT (priv->panel_button), "clicked", -@@ -655,12 +529,13 @@ create_panel_buttons (IntlClockUI *this) - ); - - gtk_widget_show (priv->panel_label); -+ gtk_widget_show (priv->panel_weather_icon); -+ gtk_widget_show (box); - - gtk_box_pack_start (GTK_BOX (priv->panel_box), priv->panel_button, - FALSE, FALSE, 0); - -- gtk_container_add (GTK_CONTAINER (priv->panel_applet), -- priv->panel_box); -+ gtk_container_add (GTK_CONTAINER (priv->panel_applet), priv->panel_box); - - gtk_widget_show_all (priv->panel_box); - } -@@ -671,10 +546,16 @@ intlclock_ui_change_orient (PanelApplet *applet, - IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); -- -- if (GTK_IS_WIDGET (priv->panel_box)) -- gtk_widget_destroy (priv->panel_box); -+ GdkPixbuf *pixbuf = NULL; -+ -+ if (GTK_IS_WIDGET (priv->panel_box)) { -+ pixbuf = g_object_ref (gtk_image_get_pixbuf (GTK_IMAGE (priv->panel_weather_icon))); -+ gtk_widget_destroy (priv->panel_box); -+ } - create_panel_buttons (this); -+ intlclock_ui_update_weather_icon (this, pixbuf); -+ if (pixbuf) -+ g_object_unref (pixbuf); - } - - static void -@@ -706,6 +587,16 @@ create_panel_button_popup (IntlClockUI *this) - "hidden", "1", - NULL); - } -+ -+ if (!can_set_system_time ()) { -+ popup_component = panel_applet_get_popup_component -+ (PANEL_APPLET (priv->panel_applet)); -+ -+ bonobo_ui_component_set_prop (popup_component, -+ "/commands/IntlClockConfig", -+ "sensitive", "0", -+ NULL); -+ } - } - - static void -@@ -714,7 +605,7 @@ create_events_window (IntlClockUI *this) - IntlClockUIPrivate *priv = PRIVATE (this); - - priv->events_window = -- GTK_WIDGET (intlclock_events_popup_new (priv->clock, priv->panel_applet)); -+ GTK_WIDGET (intlclock_events_popup_new (priv->clock, priv->panel_applet, this)); - - g_signal_connect (G_OBJECT (priv->events_window), "size-allocate", - G_CALLBACK (intlclock_events_window_size_allocate_cb), this); -@@ -723,41 +614,32 @@ create_events_window (IntlClockUI *this) - } - - static void --create_clock_window (IntlClockUI *this) -+add_to_group (GtkWidget *child, gpointer data) - { -- IntlClockUIPrivate *priv = PRIVATE (this); -- GtkSettings *settings; -- GtkStyle *style; -+ GtkSizeGroup *group = data; - -- priv->clock_vbox = intlclock_events_popup_get_clock_container -- (INTLCLOCK_EVENTS_POPUP (priv->events_window)); -- gtk_widget_show (priv->clock_vbox); -+ gtk_size_group_add_widget (group, child); - } - - static void --create_main_section (IntlClockUI *this) -+create_clock_window (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); -- IntlClockLocation *loc; -- GtkWidget *header, *subheader; -- GtkWidget *prefs_button; -- GtkWidget *prefs_button_box; -- -- if (!priv->main_section) { -- priv->main_section = gtk_vbox_new (FALSE, 6); -- gtk_container_set_border_width -- (GTK_CONTAINER (priv->main_section), -- MAIN_SECTION_PADDING); -- gtk_box_pack_end (GTK_BOX (priv->clock_vbox), -- priv->main_section, FALSE, FALSE, 0); -+ GtkWidget *clock_container; - -- } else { -- gtk_container_foreach (GTK_CONTAINER (priv->main_section), -- (GtkCallback)gtk_widget_destroy, -- NULL); -- } -+ clock_container = intlclock_events_popup_get_clock_container -+ (INTLCLOCK_EVENTS_POPUP (priv->events_window)); -+ gtk_widget_show (clock_container); -+ -+ priv->clock_vbox = gtk_vbox_new (FALSE, 6); -+ gtk_container_add (GTK_CONTAINER (clock_container), priv->clock_vbox); - -- gtk_widget_show_all (priv->main_section); -+ priv->clock_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); -+ gtk_size_group_set_ignore_hidden (priv->clock_group, FALSE); -+ -+ gtk_container_foreach (GTK_CONTAINER (clock_container), -+ (GtkCallback)add_to_group, -+ priv->clock_group); - } - - static gint -@@ -824,7 +706,6 @@ create_cities_section (IntlClockUI *this) - IntlClockUIPrivate *priv = PRIVATE (this); - GList *node; - IntlClockLocationTile *city; -- GtkWidget *header, *subheader, *image;; - GList *cities; - - if (priv->cities_section) { -@@ -832,12 +713,8 @@ create_cities_section (IntlClockUI *this) - priv->cities_section = NULL; - } - -- if (!priv->show_locations) { -- return; -- } -- - priv->cities_section = gtk_vbox_new (FALSE, 6); -- gtk_container_set_border_width (GTK_CONTAINER (priv->cities_section), 8); -+ gtk_container_set_border_width (GTK_CONTAINER (priv->cities_section), 0); - - cities = intlclock_get_locations (priv->clock); - if (g_list_length (cities) == 0) { -@@ -884,10 +761,6 @@ create_map_section (IntlClockUI *this) - priv->map_widget = NULL; - } - -- if (!priv->show_map) { -- return; -- } -- - map = intlclock_map_new (priv->clock); - - priv->map_section = gtk_alignment_new (0, 0, 1, 1); -@@ -895,11 +768,10 @@ create_map_section (IntlClockUI *this) - - gtk_container_add (GTK_CONTAINER (priv->map_section), priv->map_widget); - -- gtk_box_pack_start (GTK_BOX (priv->clock_vbox), -- priv->map_section, FALSE, FALSE, 0); -- - gtk_alignment_set_padding (GTK_ALIGNMENT (priv->map_section), - 1, 1, 1, 1); -+ gtk_box_pack_start (GTK_BOX (priv->clock_vbox), -+ priv->map_section, FALSE, FALSE, 0); - - gtk_widget_show (priv->map_widget); - gtk_widget_show (priv->map_section); -@@ -927,7 +799,6 @@ create_cities_store (IntlClockUI *this) - - while (list) { - IntlClockLocation *loc = INTLCLOCK_LOCATION (list->data); -- gfloat latitude, longitude; - - gtk_list_store_append (priv->cities_store, &iter); - gtk_list_store_set (priv->cities_store, &iter, -@@ -953,12 +824,16 @@ intlclock_prefs_hide (GtkWidget *widget, IntlClockUI *this) - IntlClockUIPrivate *priv = PRIVATE (this); - GtkWidget *tree; - -+ intlclock_edit_hide (widget, this); -+ - gtk_widget_hide (priv->prefs_window); - - tree = glade_xml_get_widget (priv->glade_xml, "cities_list"); - - gtk_tree_selection_unselect_all - (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree))); -+ -+ intlclock_ui_reset_timeout (this); - } - - static gboolean -@@ -974,8 +849,6 @@ intlclock_edit_clear (GtkWidget *widget, IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); - -- GtkWidget *edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); -- - GtkWidget *zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); - GtkWidget *name_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-name-entry"); - -@@ -1003,6 +876,8 @@ intlclock_edit_hide (GtkWidget *widget, IntlClockUI *this) - - GtkWidget *edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); - -+ intlclock_find_hide (widget, this); -+ - gtk_widget_hide (edit_window); - - intlclock_edit_clear (widget, this); -@@ -1016,6 +891,23 @@ intlclock_edit_hide_event (GtkWidget *widget, GdkEvent *event, IntlClockUI *this - return TRUE; - } - -+static void -+intlclock_find_hide (GtkWidget *widget, IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ -+ GtkWidget *find_window = glade_xml_get_widget (priv->glade_xml, "find-location-window"); -+ -+ gtk_widget_hide (find_window); -+} -+ -+static gboolean -+intlclock_find_hide_event (GtkWidget *widget, GdkEvent *event, IntlClockUI *this) -+{ -+ intlclock_find_hide (widget, this); -+ -+ return TRUE; -+} - - static void - set_12hr_format_radio_cb (GtkWidget *widget, IntlClockUI *this) -@@ -1057,28 +949,6 @@ set_seconds_check_cb (GtkWidget *widget, IntlClockUI *this) - } - - static void --set_locations_check_cb (GtkWidget *widget, IntlClockUI *this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- panel_applet_gconf_set_bool (PANEL_APPLET (priv->panel_applet), -- KEY_SHOW_LOCATIONS, -- GTK_TOGGLE_BUTTON (widget)->active, -- NULL); --} -- --static void --set_map_check_cb (GtkWidget *widget, IntlClockUI *this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- panel_applet_gconf_set_bool (PANEL_APPLET (priv->panel_applet), -- KEY_SHOW_MAP, -- GTK_TOGGLE_BUTTON (widget)->active, -- NULL); --} -- --static void - fill_prefs_window (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); -@@ -1087,6 +957,9 @@ fill_prefs_window (IntlClockUI *this) - GtkCellRenderer *renderer; - GtkTreeViewColumn *col; - -+ time_t now_t; -+ struct tm now; -+ - /* Set the 12 hour / 24 hour widget */ - widget = glade_xml_get_widget (priv->glade_xml, "12hr_radio"); - g_signal_connect (widget, "toggled", -@@ -1109,18 +982,6 @@ fill_prefs_window (IntlClockUI *this) - g_signal_connect (widget, "toggled", G_CALLBACK (set_seconds_check_cb), - this); - -- /* Set the "Show Locations" checkbox */ -- widget = glade_xml_get_widget (priv->glade_xml, "show_locations_check"); -- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), priv->show_locations); -- g_signal_connect (widget, "toggled", G_CALLBACK (set_locations_check_cb), -- this); -- -- /* Set the "Show Map" checkbox */ -- widget = glade_xml_get_widget (priv->glade_xml, "show_map_check"); -- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), priv->show_map); -- g_signal_connect (widget, "toggled", G_CALLBACK (set_map_check_cb), -- this); -- - /* Fill the Cities list */ - widget = glade_xml_get_widget (priv->glade_xml, "cities_list"); - -@@ -1136,6 +997,15 @@ fill_prefs_window (IntlClockUI *this) - - gtk_tree_view_set_model (GTK_TREE_VIEW (widget), - GTK_TREE_MODEL (priv->cities_store)); -+ -+ /* Fill the time settings */ -+ tzset (); -+ time (&now_t); -+ localtime_r (&now_t, &now); -+ -+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->seconds_spin), now.tm_sec); -+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->minutes_spin), now.tm_min); -+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->hours_spin), now.tm_hour); - } - - static gint -@@ -1150,19 +1020,334 @@ sort_zoneinfo_by_l10n_name (gconstpointer a, gconstpointer b) - return strcmp (name_a, name_b); - } - -+static void -+intlclock_prefs_locations_changed (GtkTreeSelection *selection, -+ IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ gint n; -+ -+ n = gtk_tree_selection_count_selected_rows (selection); -+ gtk_widget_set_sensitive (priv->prefs_location_edit_button, n > 0); -+ gtk_widget_set_sensitive (priv->prefs_location_remove_button, n > 0); -+} -+ - static void --display_prefs_window (IntlClockUI *this) -+location_tree_selection_changed (GtkTreeSelection *selection, -+ IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ GtkTreeModel *model; -+ GtkTreeIter iter; -+ WeatherLocation *loc = NULL; -+ gboolean can_save = FALSE; -+ -+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) { -+ gtk_tree_model_get (model, &iter, GWEATHER_XML_COL_POINTER, &loc, -1); -+ if (loc != NULL) -+ can_save = TRUE; -+ } -+ -+ gtk_widget_set_sensitive (priv->find_location_ok_button, can_save); -+} -+ -+static void -+wrap_cb (GtkSpinButton *spin, -+ IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ 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 *)priv->seconds_spin) -+ gtk_spin_button_spin (GTK_SPIN_BUTTON (priv->minutes_spin), -+ direction, 1.0); -+ else if (spin == (GtkSpinButton *)priv->minutes_spin) -+ gtk_spin_button_spin (GTK_SPIN_BUTTON (priv->hours_spin), -+ direction, 1.0); -+ else { -+ guint year, month, day; -+ GDate *date; -+ -+ gtk_calendar_get_date (GTK_CALENDAR (priv->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 (priv->calendar), -+ month, year); -+ gtk_calendar_select_day (GTK_CALENDAR (priv->calendar), -+ day); -+ -+ g_date_free (date); -+ } -+} -+ -+static void -+update_set_time_button (IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ gint can_set; -+ -+ can_set = can_set_system_time (); -+ -+ if (priv->time_settings_button) -+ gtk_widget_set_sensitive (priv->time_settings_button, can_set != 0); -+ if (priv->set_time_button) -+ gtk_button_set_label (GTK_BUTTON (priv->set_time_button), -+ can_set == 1 ? -+ _("Set System Time...") : -+ _("Set System Time")); -+} -+ -+static void -+set_time_callback (IntlClockUI *this, GError *error) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ GtkWidget *window; -+ GtkWidget *dialog; -+ -+ if (error) { -+ dialog = gtk_message_dialog_new (NULL, -+ 0, -+ GTK_MESSAGE_ERROR, -+ GTK_BUTTONS_OK, -+ _("Failed to set the system time")); -+ -+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), 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 (this); -+ -+ window = glade_xml_get_widget (priv->glade_xml, "set-time-window"); -+ gtk_widget_hide (window); -+} -+ -+static void -+set_time (GtkWidget *widget, IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ struct tm t; -+ gint64 time; -+ guint year, month, day; -+ -+ t.tm_sec = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->seconds_spin)); -+ t.tm_min = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->minutes_spin)); -+ t.tm_hour = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->hours_spin)); -+ gtk_calendar_get_date (GTK_CALENDAR (priv->calendar), &year, &month, &day); -+ t.tm_year = year - 1900; -+ t.tm_mon = month; -+ t.tm_mday = day; -+ -+ time = mktime (&t); -+ -+ set_system_time_async (time, (GFunc)set_time_callback, this, NULL); -+} -+ -+static gboolean -+find_location (GtkTreeModel *model, -+ GtkTreeIter *iter, -+ const gchar *location, -+ gboolean go_parent) -+{ -+ GtkTreeIter iter_child; -+ GtkTreeIter iter_parent; -+ gchar *aux_loc; -+ gboolean valid; -+ int len; -+ -+ len = strlen (location); -+ -+ if (len <= 0) { -+ return FALSE; -+ } -+ -+ do { -+ gtk_tree_model_get (model, iter, GWEATHER_XML_COL_LOC, &aux_loc, -1); -+ -+ if (g_ascii_strncasecmp (aux_loc, location, len) == 0) { -+ g_free (aux_loc); -+ return TRUE; -+ } -+ -+ if (gtk_tree_model_iter_has_child (model, iter)) { -+ gtk_tree_model_iter_nth_child (model, &iter_child, iter, 0); -+ if (find_location (model, &iter_child, location, FALSE)) { -+ /* Manual copying of the iter */ -+ iter->stamp = iter_child.stamp; -+ iter->user_data = iter_child.user_data; -+ iter->user_data2 = iter_child.user_data2; -+ iter->user_data3 = iter_child.user_data3; -+ -+ g_free (aux_loc); -+ -+ return TRUE; -+ } -+ } -+ -+ g_free (aux_loc); -+ -+ valid = gtk_tree_model_iter_next (model, iter); -+ } while (valid); -+ -+ if (go_parent) { -+ iter_parent = *iter; -+ while (gtk_tree_model_iter_parent (model, iter, &iter_parent)) { -+ if (gtk_tree_model_iter_next (model, iter)) -+ return find_location (model, iter, location, TRUE); -+ iter_parent = *iter; -+ } -+ } -+ -+ return FALSE; -+} -+ -+static void -+find_next_location (GtkButton *button, IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ GtkTreeView *tree; -+ GtkTreeModel *model; -+ GtkEntry *entry; -+ GtkTreeSelection *selection; -+ GtkTreeIter iter; -+ GtkTreeIter iter_parent; -+ GtkTreePath *path; -+ const gchar *location; -+ -+ tree = GTK_TREE_VIEW (priv->location_tree); -+ model = gtk_tree_view_get_model (tree); -+ entry = GTK_ENTRY (priv->find_location_entry); -+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree)); -+ -+ if (gtk_tree_selection_count_selected_rows (selection) >= 1) { -+ gtk_tree_selection_get_selected (selection, &model, &iter); -+ /* Select next or select parent */ -+ if (!gtk_tree_model_iter_next (model, &iter)) { -+ iter_parent = iter; -+ if (!gtk_tree_model_iter_parent (model, &iter, &iter_parent) || -+ !gtk_tree_model_iter_next (model, &iter)) -+ gtk_tree_model_get_iter_first (model, &iter); -+ } -+ } -+ else { -+ gtk_tree_model_get_iter_first (model, &iter); -+ } -+ location = gtk_entry_get_text (entry); -+ -+ if (find_location (model, &iter, location, TRUE)) { -+ gtk_widget_set_sensitive (priv->find_next_location_button, TRUE); -+ path = gtk_tree_model_get_path (model, &iter); -+ gtk_tree_view_expand_to_path (tree, path); -+ gtk_tree_selection_select_path (selection, path); -+ gtk_tree_view_scroll_to_cell (tree, path, NULL, TRUE, 0.5, 0); -+ -+ gtk_tree_path_free (path); -+ } -+ else { -+ gtk_widget_set_sensitive (priv->find_next_location_button, FALSE); -+ } -+} -+ -+static void -+find_entry_changed (GtkEditable *entry, IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ GtkTreeView *tree; -+ GtkTreeModel *model; -+ GtkTreeSelection *selection; -+ GtkTreeIter iter; -+ GtkTreePath *path; -+ const gchar *location; -+ -+ tree = GTK_TREE_VIEW (priv->location_tree); -+ model = gtk_tree_view_get_model (tree); -+ -+ selection = gtk_tree_view_get_selection (tree); -+ gtk_tree_model_get_iter_first (model, &iter); -+ -+ location = gtk_entry_get_text (GTK_ENTRY (entry)); -+ if (find_location (model, &iter, location, TRUE)) { -+ gtk_widget_set_sensitive (priv->find_next_location_button, TRUE); -+ path = gtk_tree_model_get_path (model, &iter); -+ gtk_tree_view_expand_to_path (tree, path); -+ gtk_tree_selection_select_iter (selection, &iter); -+ gtk_tree_view_scroll_to_cell (tree, path, NULL, TRUE, 0.5, 0); -+ gtk_tree_path_free (path); -+ } -+ else { -+ gtk_widget_set_sensitive (priv->find_next_location_button, FALSE); -+ } -+} -+ -+static void -+cancel_time_settings (GtkWidget *button, IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ -+ gtk_widget_hide (priv->set_time_window); -+ -+ intlclock_ui_reset_timeout (this); -+} -+ -+static void -+run_time_settings (GtkWidget *button, IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ GtkWidget *cancel_set_time_button; -+ -+ if (!priv->set_time_button) { -+ priv->set_time_button = glade_xml_get_widget (priv->glade_xml, "set-time-button"); -+ g_signal_connect (priv->set_time_button, "clicked", G_CALLBACK (set_time), this); -+ -+ cancel_set_time_button = glade_xml_get_widget (priv->glade_xml, "cancel-set-time-button"); -+ g_signal_connect (cancel_set_time_button, "clicked", G_CALLBACK (cancel_time_settings), this); -+ -+ priv->current_time_label = glade_xml_get_widget (priv->glade_xml, "current_time_label"); -+ } -+ -+ priv->set_time_window = glade_xml_get_widget (priv->glade_xml, "set-time-window"); -+ gtk_window_present (GTK_WINDOW (priv->set_time_window)); -+ -+ intlclock_ui_reset_timeout (this); -+} -+ -+static void -+display_prefs_window (IntlClockUI *this, gboolean locations) - { - IntlClockUIPrivate *priv = PRIVATE (this); - GtkWidget *edit_window; -- GtkWidget *prefs_window; - GtkWidget *prefs_close_button; -- GtkWidget *prefs_settings_button; - GtkWidget *edit_cancel_button; - GtkWidget *edit_ok_button; - GtkWidget *zone_combo; -- -- GtkWidget *tmp_button; -+ GtkWidget *find_window; -+ GtkWidget *find_location_button; -+ GtkWidget *find_location_cancel_button; -+ GtkTreeSelection *selection; - - if (!priv->prefs_window) { - priv->prefs_window = -@@ -1170,43 +1355,42 @@ display_prefs_window (IntlClockUI *this) - - prefs_close_button = - glade_xml_get_widget (priv->glade_xml, "prefs-close-button"); -- -- prefs_settings_button = -- glade_xml_get_widget (priv->glade_xml, "prefs-time-settings-button"); -- - priv->prefs_locations = - GTK_TREE_VIEW (glade_xml_get_widget (priv->glade_xml, "cities_list")); - -+ selection = gtk_tree_view_get_selection (priv->prefs_locations); -+ g_signal_connect (G_OBJECT (selection), "changed", -+ G_CALLBACK (intlclock_prefs_locations_changed), this); -+ - g_signal_connect (G_OBJECT (priv->prefs_window), "delete_event", - G_CALLBACK (intlclock_prefs_hide_event), this); - - g_signal_connect (G_OBJECT (prefs_close_button), "clicked", - G_CALLBACK (intlclock_prefs_hide), this); - -- g_signal_connect (G_OBJECT (prefs_settings_button), "clicked", -- G_CALLBACK (run_time_configuration_cb), this); -- -- tmp_button = -+ priv->prefs_location_remove_button = - glade_xml_get_widget (priv->glade_xml, "prefs-locations-remove-button"); - -- g_signal_connect (G_OBJECT (tmp_button), "clicked", -+ g_signal_connect (G_OBJECT (priv->prefs_location_remove_button), "clicked", - G_CALLBACK (run_prefs_locations_remove), this); -- -- tmp_button = -+ -+ priv->prefs_location_add_button = - glade_xml_get_widget (priv->glade_xml, "prefs-locations-add-button"); - -- g_signal_connect (G_OBJECT (tmp_button), "clicked", -+ g_signal_connect (G_OBJECT (priv->prefs_location_add_button), "clicked", - G_CALLBACK (run_prefs_locations_add), this); - -- tmp_button = -+ priv->prefs_location_edit_button = - glade_xml_get_widget (priv->glade_xml, "prefs-locations-edit-button"); - -- g_signal_connect (G_OBJECT (tmp_button), "clicked", -+ g_signal_connect (G_OBJECT (priv->prefs_location_edit_button), "clicked", - G_CALLBACK (run_prefs_locations_edit), this); - - edit_window = glade_xml_get_widget (priv->glade_xml, - "edit-location-window"); - -+ gtk_window_set_transient_for (GTK_WINDOW (edit_window), -+ GTK_WINDOW (priv->prefs_window)); - - g_signal_connect (G_OBJECT (edit_window), "delete_event", - G_CALLBACK (intlclock_edit_hide_event), this); -@@ -1219,7 +1403,35 @@ display_prefs_window (IntlClockUI *this) - - zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); - -- g_signal_connect (G_OBJECT (zone_combo), "changed", -+ find_window = glade_xml_get_widget (priv->glade_xml, -+ "find-location-window"); -+ -+ gtk_window_set_transient_for (GTK_WINDOW (find_window), -+ GTK_WINDOW (edit_window)); -+ -+ g_signal_connect (G_OBJECT (find_window), "delete_event", -+ G_CALLBACK (intlclock_find_hide_event), this); -+ -+ find_location_button = -+ glade_xml_get_widget (priv->glade_xml, "find-location-button"); -+ -+ priv->find_location_ok_button = -+ glade_xml_get_widget (priv->glade_xml, "find-location-ok-button"); -+ -+ find_location_cancel_button = -+ glade_xml_get_widget (priv->glade_xml, "find-location-cancel-button"); -+ -+ priv->find_next_location_button = -+ glade_xml_get_widget (priv->glade_xml, "find-next-location-button"); -+ -+ priv->find_location_entry = -+ glade_xml_get_widget (priv->glade_xml, "find-location-entry"); -+ -+ priv->location_tree = -+ glade_xml_get_widget (priv->glade_xml, "find-location-tree"); -+ -+ priv->zone_combo_changed = -+ g_signal_connect (G_OBJECT (zone_combo), "changed", - G_CALLBACK (zone_combo_changed), this); - - -@@ -1229,16 +1441,72 @@ display_prefs_window (IntlClockUI *this) - g_signal_connect (G_OBJECT (edit_ok_button), "clicked", - G_CALLBACK (run_prefs_edit_save), this); - -+ g_signal_connect (find_location_button, "clicked", -+ G_CALLBACK (run_find_location), this); -+ -+ g_signal_connect (G_OBJECT (find_location_cancel_button), "clicked", -+ G_CALLBACK (intlclock_find_hide), this); -+ -+ g_signal_connect (G_OBJECT (priv->find_location_ok_button), "clicked", -+ G_CALLBACK (run_find_location_save), this); -+ -+ g_signal_connect (G_OBJECT (priv->find_next_location_button), "clicked", -+ G_CALLBACK (find_next_location), this); -+ -+ g_signal_connect (G_OBJECT (priv->find_location_entry), "changed", -+ G_CALLBACK (find_entry_changed), this); -+ -+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->location_tree)); -+ g_signal_connect (selection, "changed", -+ G_CALLBACK (location_tree_selection_changed), this); -+ - /* We have to put an item in the combo box in the glade file - to get the simpler, string-only store. Here we remove that - item. */ - gtk_combo_box_remove_text (GTK_COMBO_BOX (zone_combo), 0); - -+ /* Set up the time setting section */ -+ -+ priv->time_settings_button = glade_xml_get_widget (priv->glade_xml, "time-settings-button"); -+ g_signal_connect (priv->time_settings_button, "clicked", G_CALLBACK (run_time_settings), this); -+ -+ priv->calendar = glade_xml_get_widget (priv->glade_xml, "calendar"); -+ priv->hours_spin = glade_xml_get_widget (priv->glade_xml, "hours_spin"); -+ priv->minutes_spin = glade_xml_get_widget (priv->glade_xml, "minutes_spin"); -+ priv->seconds_spin = glade_xml_get_widget (priv->glade_xml, "seconds_spin"); -+ -+ gtk_entry_set_width_chars (GTK_ENTRY (priv->hours_spin), 2); -+ gtk_entry_set_width_chars (GTK_ENTRY (priv->minutes_spin), 2); -+ gtk_entry_set_width_chars (GTK_ENTRY (priv->seconds_spin), 2); -+ -+ gtk_entry_set_alignment (GTK_ENTRY (priv->hours_spin), 1.0); -+ gtk_entry_set_alignment (GTK_ENTRY (priv->minutes_spin), 1.0); -+ gtk_entry_set_alignment (GTK_ENTRY (priv->seconds_spin), 1.0); -+ g_signal_connect (priv->seconds_spin, "wrapped", G_CALLBACK (wrap_cb), this); -+ g_signal_connect (priv->minutes_spin, "wrapped", G_CALLBACK (wrap_cb), this); -+ g_signal_connect (priv->hours_spin, "wrapped", G_CALLBACK (wrap_cb), this); -+ - /* fill it with the current preferences */ - fill_prefs_window (this); - } - -+ if (locations) { -+ GtkWidget *notebook = -+ glade_xml_get_widget (priv->glade_xml, "notebook"); -+ gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 1); -+ } -+ -+ update_set_time_button (this); -+ - gtk_window_present (GTK_WINDOW (priv->prefs_window)); -+ -+ intlclock_ui_reset_timeout (this); -+} -+ -+void -+intlclock_ui_edit_locations (IntlClockUI *ui) -+{ -+ display_prefs_window (ui, TRUE); - } - - static void -@@ -1306,16 +1574,11 @@ intlclock_ui_new (IntlClock *clock, PanelApplet *applet) - create_events_window (this); - create_clock_window (this); - create_cities_store (this); -- -- if (priv->show_locations) { -- create_cities_section (this); -- } -- -- if (priv->show_map) { -- create_map_section (this); -- intlclock_map_refresh (INTLCLOCK_MAP (priv->map_widget)); -- } -- -+ create_cities_section (this); -+ create_map_section (this); -+ -+ intlclock_map_refresh (INTLCLOCK_MAP (priv->map_widget)); -+ - intlclock_ui_reset_timeout (this); - - return this; -@@ -1365,9 +1628,6 @@ intlclock_ui_init (IntlClockUI *this) - - priv->cities_store = NULL; - -- priv->show_locations = TRUE; -- priv->show_map = TRUE; -- - priv->prefs_window = NULL; - - priv->format_12hr = TRUE; -@@ -1547,56 +1807,6 @@ gconf_show_week_changed (GConfClient *client, - } - - static void --gconf_show_locations_changed (GConfClient *client, -- guint cnxn_id, -- GConfEntry *entry, -- IntlClockUI *this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- GtkWidget *widget; -- -- gboolean value; -- -- if (!entry->value || entry->value->type != GCONF_VALUE_BOOL) -- return; -- -- value = gconf_value_get_bool (entry->value); -- -- priv->show_locations = (value != 0); -- -- widget = glade_xml_get_widget (priv->glade_xml, "show_locations_check"); -- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), -- priv->show_locations); -- -- create_cities_section (this); --} -- --static void --gconf_show_map_changed (GConfClient *client, -- guint cnxn_id, -- GConfEntry *entry, -- IntlClockUI *this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- GtkWidget *widget; -- -- gboolean value; -- -- if (!entry->value || entry->value->type != GCONF_VALUE_BOOL) -- return; -- -- value = gconf_value_get_bool (entry->value); -- -- priv->show_map = (value != 0); -- -- widget = glade_xml_get_widget (priv->glade_xml, "show_map_check"); -- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), -- priv->show_map); -- -- create_map_section (this); --} -- --static void - location_start_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, -@@ -1614,6 +1824,7 @@ location_start_element (GMarkupParseContext *context, - gchar *timezone = NULL; - gfloat latitude = 0.0; - gfloat longitude = 0.0; -+ gchar *code = NULL; - - int index = 0; - -@@ -1633,6 +1844,8 @@ location_start_element (GMarkupParseContext *context, - 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]; - } - } - -@@ -1642,7 +1855,7 @@ location_start_element (GMarkupParseContext *context, - return; - } - -- loc = intlclock_location_new (name, timezone, latitude, longitude); -+ loc = intlclock_location_new (name, timezone, latitude, longitude, code); - - *(GList **)user_data = g_list_append (ret, loc); - } -@@ -1713,10 +1926,11 @@ gconf_loc_to_string (IntlClockLocation *loc) - prev_locale = setlocale (LC_NUMERIC, "POSIX"); - - ret = g_markup_printf_escaped -- ("", -+ ("", - intlclock_location_get_name (loc), - intlclock_location_get_timezone (loc), -- latitude, longitude); -+ latitude, longitude, -+ intlclock_location_get_weather_code (loc)); - - setlocale (LC_NUMERIC, ""); - -@@ -1727,7 +1941,7 @@ static void - intlclock_ui_save_cities_store (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); -- IntlClockLocation *loc, *cur; -+ IntlClockLocation *loc; - GList *node = intlclock_get_locations (priv->clock); - - GSList *root = NULL; -@@ -1803,24 +2017,6 @@ setup_gconf (IntlClockUI *this) - g_free (key); - - key = panel_applet_gconf_get_full_key -- (PANEL_APPLET (priv->panel_applet), KEY_SHOW_LOCATIONS); -- priv->listeners [index++] = -- gconf_client_notify_add ( -- client, key, -- (GConfClientNotifyFunc) gconf_show_locations_changed, -- this, NULL, NULL); -- g_free (key); -- -- key = panel_applet_gconf_get_full_key -- (PANEL_APPLET (priv->panel_applet), KEY_SHOW_MAP); -- priv->listeners [index++] = -- gconf_client_notify_add ( -- client, key, -- (GConfClientNotifyFunc) gconf_show_map_changed, -- this, NULL, NULL); -- g_free (key); -- -- key = panel_applet_gconf_get_full_key - (PANEL_APPLET (priv->panel_applet), KEY_CITIES); - priv->listeners [index++] = - gconf_client_notify_add ( -@@ -1868,14 +2064,6 @@ load_gconf_settings (IntlClockUI *this) - panel_applet_gconf_get_bool (priv->panel_applet, - KEY_SHOW_WEEK, NULL); - -- priv->show_locations = -- panel_applet_gconf_get_bool (priv->panel_applet, -- KEY_SHOW_LOCATIONS, NULL); -- -- priv->show_map = -- panel_applet_gconf_get_bool (priv->panel_applet, -- KEY_SHOW_MAP, NULL); -- - values = panel_applet_gconf_get_list (priv->panel_applet, KEY_CITIES, - GCONF_VALUE_STRING, NULL); - -@@ -1892,92 +2080,72 @@ static void bonobo_display_properties_dialog (BonoboUIComponent *uic, - IntlClockUI *this, - const gchar *verbname) - { -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- display_prefs_window (this); -+ display_prefs_window (this, FALSE); - } - --static void bonobo_run_time_configuration (BonoboUIComponent *uic, -- IntlClockUI *this, -- const gchar *verbname) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- run_time_configuration (this); --} -- --static void display_prefs_window_cb (GtkButton *button, gpointer this) -+static void -+copy_time (BonoboUIComponent *uic, -+ IntlClockUI *this, -+ const gchar *verbname) - { - IntlClockUIPrivate *priv = PRIVATE (this); -+ gchar *utf8; -+ time_t now_t; -+ struct tm now; - -- display_prefs_window (this); --} -+ tzset (); -+ time (&now_t); -+ localtime_r (&now_t, &now); - --static void --run_time_configuration_cb (GtkButton *button, gpointer this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -+ utf8 = intlclock_format_time (priv->clock, &now, FALSE, -+ priv->format_12hr, -+ priv->format_show_seconds, -+ FALSE, FALSE, NULL, FALSE); -+ -+ gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY), -+ utf8, -1); -+ gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), -+ utf8, -1); - -- run_time_configuration (this); -+ g_free (utf8); - } - - static void --run_time_configuration (IntlClockUI *this) -+copy_date (BonoboUIComponent *uic, -+ IntlClockUI *this, -+ const gchar *verbname) - { -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- GtkWidget *dialog; -- GError *err; -- char **argv; -- char *path; -+ char string[256]; -+ char *utf8, *loc; - -- GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (priv->events_window)); -- gchar *tool = "/opt/gnome/bin/gnomesu /sbin/yast2 timezone"; -- -- if (!tool || tool[0] == '\0') -- return; -- -- if (!g_shell_parse_argv (tool, NULL, &argv, NULL)) -- return; -- -- if (!(path = g_find_program_in_path (argv [0]))) { -- g_strfreev (argv); -- return; -- } -- -- g_free (path); -- -- err = NULL; -- if (gdk_spawn_on_screen (screen, -- NULL, -- argv, -- NULL, -- G_SPAWN_SEARCH_PATH, -- NULL, -- NULL, -- NULL, -- &err)) { -- g_strfreev (argv); -- return; -- } -- -- g_strfreev (argv); -+ time_t now_t; -+ struct tm now; - -- dialog = gtk_message_dialog_new (NULL, -- GTK_DIALOG_DESTROY_WITH_PARENT, -- GTK_MESSAGE_ERROR, -- GTK_BUTTONS_OK, -- _("Failed to launch time configuration tool: %s"), -- err->message); -- g_error_free (err); -+ tzset (); -+ time (&now_t); -+ localtime_r (&now_t, &now); - -- g_signal_connect (dialog, "response", -- G_CALLBACK (gtk_widget_destroy), NULL); -+ loc = g_locale_from_utf8 (_("%A, %B %d %Y"), -1, NULL, NULL, NULL); -+ if (!loc) -+ strcpy (string, "???"); -+ else if (strftime (string, sizeof (string), loc, &now) <= 0) -+ strcpy (string, "???"); -+ g_free (loc); - -- gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); -- gtk_window_set_screen (GTK_WINDOW (dialog), screen); -+ 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); -+} - -- gtk_widget_show_all (dialog); -+static void -+config_date (BonoboUIComponent *uic, -+ IntlClockUI *this, -+ const char *verbname) -+{ -+ run_time_settings (NULL, this); - } - - static void -@@ -2000,6 +2168,46 @@ remove_tree_row (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, - } - - static void -+update_coords (IntlClockUI *this, gboolean valid, gfloat lat, gfloat lon) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -+ GtkWidget *lat_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-latitude-entry"); -+ GtkWidget *lon_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-entry"); -+ GtkWidget *lat_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-latitude-combo"); -+ GtkWidget *lon_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-combo"); -+ gchar *tmp; -+ -+ 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; -+ } -+ -+ 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); -+ } -+} -+ -+static void - zone_combo_changed (GtkComboBox *widget, gpointer this) - { - IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -@@ -2009,17 +2217,12 @@ zone_combo_changed (GtkComboBox *widget, gpointer this) - gchar *city = NULL; - gfloat lat = 0; - gfloat lon = 0; -- gchar *tmp; -+ GtkTreeModel *model; -+ gchar *name; - - GtkWidget *name_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-name-entry"); -- -- GtkWidget *lat_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-latitude-entry"); -- -- GtkWidget *lon_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-entry"); -- -- GtkWidget *lat_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-latitude-combo"); -- -- GtkWidget *lon_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-combo"); -+ GtkWidget *edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); -+ gchar *weather_code; - - IntlClockCountry *country; - IntlClockZoneInfo *info; -@@ -2028,6 +2231,14 @@ zone_combo_changed (GtkComboBox *widget, gpointer this) - return; - } - -+ /* only fill in other field if name is not set yet, to -+ * allow correcting a guessed timezone -+ */ -+ name = gtk_entry_get_text (name_entry); -+ if (name && name[0]) { -+ return; -+ } -+ - info = intlclock_zonetable_get_l10n_zone (zones, timezone); - g_free (timezone); - -@@ -2049,26 +2260,13 @@ zone_combo_changed (GtkComboBox *widget, gpointer this) - g_free (city); - - intlclock_zoneinfo_get_coords (info, &lat, &lon); -+ update_coords (this, TRUE, lat, lon); - -- 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); -- } -+ fill_location_tree (this); -+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->location_tree)); -+ weather_code = find_weather_code (model, city, lat * M_PI/180.0, lon * M_PI/180.0); -+ g_object_set_data_full (G_OBJECT (edit_window), "weather-code", -+ weather_code, g_free); - } - - static void -@@ -2144,12 +2342,8 @@ edit_tree_row (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, - IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); - - IntlClockLocation *loc; -- int i; -- int timezone_idx = -1; - gchar *tmp; - gfloat lat, lon; -- GList *list; -- GList *cur; - - /* fill the dialog with this location's data, show it */ - GtkWidget *edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); -@@ -2205,13 +2399,165 @@ static void - run_prefs_locations_remove (GtkButton *button, gpointer this) - { - IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -- GtkTreeModel *model = gtk_tree_view_get_model (priv->prefs_locations);; - GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->prefs_locations)); - - gtk_tree_selection_selected_foreach (sel, remove_tree_row, this); - } - - static void -+run_find_location (GtkButton *button, gpointer this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -+ -+ GtkWidget *window = glade_xml_get_widget (priv->glade_xml, "find-location-window"); -+ -+ gtk_tree_view_collapse_all (priv->location_tree); -+ gtk_widget_grab_focus (priv->find_location_entry); -+ gtk_window_present (GTK_WINDOW (window)); -+} -+ -+static gdouble -+distance (gdouble lat1, gdouble lon1, -+ gdouble lat2, gdouble lon2) -+{ -+ gdouble radius = 6372.795; -+ -+ return acos (cos (lat1) * cos (lat2) * cos (lon1 - lon2) + sin (lat1) * sin (lat2)) * radius; -+} -+ -+static gchar * -+find_timezone (IntlClockUI *this, -+ const char *name, -+ gfloat lat, -+ gfloat lon) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -+ IntlClockZoneTable *zonetab = intlclock_get_zonetable (priv->clock); -+ GList *zones, *l; -+ double dist, d; -+ gfloat zlat, zlon; -+ IntlClockZoneInfo *best; -+ -+ g_print ("find zone for %s (%f %f)\n", name, lat, lon); -+ dist = 1e6; -+ best = NULL; -+ zones = intlclock_zonetable_get_zones (zonetab); -+ for (l = zones; l; l = l->next) { -+ IntlClockZoneInfo *info = l->data; -+ intlclock_zoneinfo_get_coords (info, &zlat, &zlon); -+ -+ d = distance (lat, lon, zlat*M_PI/180.0, zlon*M_PI/180.0); -+ -+ if (d < dist) { -+ best = info; -+ dist = d; -+ } -+ } -+ -+ intlclock_zoneinfo_get_coords (best, &zlat, &zlon); -+ g_print ("best: %s (%f, %f), distance: %f\n", -+ intlclock_zoneinfo_get_name (best), zlat, zlon, dist); -+ -+ return g_strdup (intlclock_zoneinfo_get_name (best)); -+} -+ -+static void -+update_timezone (IntlClockUI *this, -+ const char *name, -+ gfloat lat, -+ gfloat lon) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -+ GtkWidget *zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); -+ GtkTreeModel *model; -+ gchar *timezone; -+ IntlClockLocation *loc; -+ -+ timezone = find_timezone (this, name, lat, lon); -+ loc = intlclock_location_new (name, timezone, lat*180.0/M_PI, lon*180.0/M_PI, NULL); -+ -+ g_signal_handler_block (zone_combo, priv->zone_combo_changed); -+ -+ fill_timezone_combo_from_location (this, zone_combo, loc); -+ -+ g_signal_handler_unblock (zone_combo, priv->zone_combo_changed); -+ -+ g_object_unref (loc); -+ g_free (timezone); -+} -+ -+static void -+run_find_location_save (GtkButton *button, gpointer this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -+ GtkTreeSelection *selection; -+ GtkTreeModel *model; -+ GtkTreeIter iter; -+ WeatherLocation *loc = NULL; -+ GtkWidget *name_entry; -+ GtkWidget *edit_window; -+ -+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->location_tree)); -+ if (!gtk_tree_selection_get_selected (selection, &model, &iter)) -+ return; -+ -+ gtk_tree_model_get (model, &iter, GWEATHER_XML_COL_POINTER, &loc, -1); -+ -+ if (!loc) -+ return; -+ -+ edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); -+ name_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-name-entry"); -+ gtk_entry_set_text (GTK_ENTRY (name_entry), loc->name); -+ g_object_set_data_full (G_OBJECT (edit_window), "weather-code", -+ g_strdup (loc->code), g_free); -+ -+ update_coords (this, loc->latlon_valid, loc->latitude*180.0/M_PI, loc->longitude*180.0/M_PI); -+ -+ update_timezone (this, loc->name, loc->latitude, loc->longitude); -+ -+ intlclock_find_hide (button, this); -+} -+ -+static void -+location_row_activated (GtkTreeView *tree_view, -+ GtkTreePath *path, -+ GtkTreeViewColumn *column, -+ IntlClockUI *this) -+{ -+ run_find_location_save (tree_view, this); -+} -+ -+static void -+fill_location_tree (IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -+ GtkTreeView *tree; -+ GtkTreeModel *model; -+ GtkTreeViewColumn *column; -+ GtkCellRenderer *cell; -+ -+ tree = (GtkTreeView*)priv->location_tree; -+ -+ if (gtk_tree_view_get_model (tree) != NULL) -+ return; -+ -+ model = (GtkTreeModel*)gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); -+ gtk_tree_view_set_model (tree, model); -+ -+ cell = gtk_cell_renderer_text_new (); -+ column = gtk_tree_view_column_new_with_attributes ("not used", cell, -+ "text", GWEATHER_XML_COL_LOC, NULL); -+ gtk_tree_view_append_column (tree, column); -+ gtk_tree_view_set_expander_column (tree, column); -+ -+ g_signal_connect (tree, "row-activated", -+ G_CALLBACK (location_row_activated), this); -+ -+ gweather_xml_load_locations (tree, NULL); -+} -+ -+static void - run_prefs_locations_add (GtkButton *button, gpointer this) - { - IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -@@ -2220,7 +2566,8 @@ run_prefs_locations_add (GtkButton *button, gpointer this) - GtkWidget *zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); - - fill_timezone_combo_from_location (this, zone_combo, NULL); -- -+ fill_location_tree (this); -+ - g_object_set_data (G_OBJECT (edit_window), "intlclock-location", NULL); - gtk_window_present (GTK_WINDOW (edit_window)); - } -@@ -2230,7 +2577,6 @@ run_prefs_locations_edit (GtkButton *button, gpointer this) - { - IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); - -- GtkTreeModel *model = gtk_tree_view_get_model (priv->prefs_locations);; - GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->prefs_locations)); - - gtk_tree_selection_selected_foreach (sel, edit_tree_row, this); -@@ -2245,7 +2591,6 @@ run_prefs_edit_save (GtkButton *button, gpointer this) - IntlClockZoneTable *zones = intlclock_get_zonetable (priv->clock); - - IntlClockLocation *loc = g_object_get_data (G_OBJECT (edit_window), "intlclock-location"); -- - GtkWidget *zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); - GtkWidget *name_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-name-entry"); - -@@ -2255,6 +2600,8 @@ run_prefs_edit_save (GtkButton *button, gpointer this) - GtkWidget *lon_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-combo"); - - gchar *timezone_l10n = gtk_combo_box_get_active_text (GTK_COMBO_BOX (zone_combo)); -+ gchar *weather_code = g_object_get_data (G_OBJECT (edit_window), "weather-code"); -+ - IntlClockZoneInfo *info = intlclock_zonetable_get_l10n_zone (zones, timezone_l10n); - - if (!info) { -@@ -2281,9 +2628,11 @@ run_prefs_edit_save (GtkButton *button, gpointer this) - intlclock_location_set_timezone (loc, intlclock_zoneinfo_get_name (info)); - intlclock_location_set_name (loc, name); - intlclock_location_set_coords (loc, lat, lon); -+ intlclock_location_set_weather_code (loc, weather_code); - } else { - GList *locs; -- loc = intlclock_location_new (name, intlclock_zoneinfo_get_name (info), lat, lon); -+ -+ loc = intlclock_location_new (name, intlclock_zoneinfo_get_name (info), lat, lon, weather_code); - - locs = g_list_copy (intlclock_get_locations (priv->clock)); - locs = g_list_append (locs, loc); -@@ -2294,3 +2643,11 @@ run_prefs_edit_save (GtkButton *button, gpointer this) - - intlclock_edit_hide (edit_window, this); - } -+ -+void -+intlclock_ui_update_weather_icon (IntlClockUI *ui, GdkPixbuf *pixbuf) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (ui)); -+ -+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->panel_weather_icon), pixbuf); -+} -diff --git a/src/intlclock-ui.h b/src/intlclock-ui.h -index ecbee03..a10099a 100644 ---- a/src/intlclock-ui.h -+++ b/src/intlclock-ui.h -@@ -29,6 +29,8 @@ GType intlclock_ui_get_type (void); - - IntlClockUI *intlclock_ui_new (IntlClock *clock, PanelApplet *applet); - gboolean intlclock_ui_is_12hr (IntlClockUI *ui); -+void intlclock_ui_edit_locations (IntlClockUI *ui); -+void intlclock_ui_update_weather_icon (IntlClockUI *ui, GdkPixbuf *pixbuf); - - G_END_DECLS - #endif /* __INTLCLOCK_UI_H__ */ -diff --git a/src/intlclock-zonetable.c b/src/intlclock-zonetable.c -index a2a0b6f..e6e27cb 100644 ---- a/src/intlclock-zonetable.c -+++ b/src/intlclock-zonetable.c -@@ -27,8 +27,6 @@ typedef struct { - GHashTable *country_table; - } IntlClockZoneTablePrivate; - --#define USE_CRIPPLED_ZONELIST 1 -- - /* Seeded with the list from Nat's Blackberry */ - char *available_zones[] = { - /* Eniwetok (-12) */ -diff --git a/src/intlclock.c b/src/intlclock.c -index 02f5b0a..552c45c 100644 ---- a/src/intlclock.c -+++ b/src/intlclock.c -@@ -32,6 +32,8 @@ typedef struct { - enum { - TICK, - LOCATIONS_CHANGED, -+ BLINK_LOCATION, -+ CURRENT_TIMEZONE_CHANGED, - LAST_SIGNAL - }; - -@@ -87,7 +89,25 @@ intlclock_class_init (IntlClockClass *this_class) - _intlclock_marshal_VOID__VOID, - G_TYPE_NONE, 0); - -- g_type_class_add_private (this_class, sizeof (IntlClockPrivate)); -+ intlclock_signals[BLINK_LOCATION] = g_signal_new -+ ("blink-location", -+ G_OBJECT_CLASS_TYPE (obj_class), -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (IntlClockClass, blink_location), -+ NULL, NULL, -+ _intlclock_marshal_VOID__OBJECT, -+ G_TYPE_NONE, 1, INTLCLOCK_LOCATION_TYPE); -+ -+ intlclock_signals[CURRENT_TIMEZONE_CHANGED] = g_signal_new -+ ("current-timezone-changed", -+ G_OBJECT_CLASS_TYPE (obj_class), -+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, -+ G_STRUCT_OFFSET (IntlClockClass, current_timezone_changed), -+ NULL, NULL, -+ _intlclock_marshal_VOID__VOID, -+ G_TYPE_NONE, 0); -+ -+ g_type_class_add_private (this_class, sizeof (IntlClockPrivate)); - } - - static void -@@ -133,7 +153,7 @@ intlclock_set_locations (IntlClock *this, GList *locations) - - priv->locations = locations; - -- g_signal_emit_by_name (this, "locations-changed"); -+ g_signal_emit (this, intlclock_signals[LOCATIONS_CHANGED], 0); - } - - GList * -@@ -202,7 +222,7 @@ intlclock_emit_tick (gpointer data) - IntlClock *this = INTLCLOCK (data); - IntlClockPrivate *priv = PRIVATE (this); - -- g_signal_emit_by_name (this, "tick"); -+ g_signal_emit (this, intlclock_signals[TICK], 0); - - if (priv->in_partial_timeout) { - intlclock_reset_timeout (this); -@@ -353,3 +373,9 @@ intlclock_free_locations (IntlClock *this) - g_list_free (priv->locations); - priv->locations = NULL; - } -+ -+void -+intlclock_blink_location (IntlClock *this, IntlClockLocation *loc) -+{ -+ g_signal_emit (this, intlclock_signals[BLINK_LOCATION], 0, loc); -+} -diff --git a/src/intlclock.h b/src/intlclock.h -index 3b0012c..20c681d 100644 ---- a/src/intlclock.h -+++ b/src/intlclock.h -@@ -27,6 +27,9 @@ typedef struct - - void (* tick) (IntlClock *clock); - void (* locations_changed) (IntlClock *clock); -+ void (* blink_location) (IntlClock *clock, IntlClockLocation *loc); -+ void (* current_timezone_changed) (IntlClock *clock); -+ - } IntlClockClass; - - GType intlclock_get_type (void); -@@ -35,6 +38,7 @@ IntlClock *intlclock_new (void); - - void intlclock_set_locations (IntlClock *this, GList *list); - GList *intlclock_get_locations (IntlClock *this); -+void intlclock_blink_location (IntlClock *this, IntlClockLocation *loc); - - IntlClockZoneTable *intlclock_get_zonetable (IntlClock *this); - gchar *intlclock_format_time (IntlClock *this, struct tm *now, -diff --git a/src/set-timezone.c b/src/set-timezone.c -new file mode 100644 -index 0000000..5c96149 ---- /dev/null -+++ b/src/set-timezone.c -@@ -0,0 +1,426 @@ -+/* -*- 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 -+#include -+ -+static DBusGConnection * -+get_session_bus (void) -+{ -+ GError *error; -+ static DBusGConnection *bus = NULL; -+ -+ if (bus == NULL) { -+ error = NULL; -+ bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); -+ if (bus == NULL) { -+ g_warning ("Couldn't connect to session bus: %s", -+ error->message); -+ g_error_free (error); -+ } -+ } -+ -+ return bus; -+} -+ -+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; -+} -+ -+static PolKitContext * -+get_pk_context (void) -+{ -+ static PolKitContext *pk_context = NULL; -+ -+ if (pk_context == NULL) { -+ pk_context = polkit_context_new (); -+ if (!polkit_context_init (pk_context, NULL)) { -+ polkit_context_unref (pk_context); -+ pk_context = NULL; -+ } -+ } -+ -+ return pk_context; -+} -+ -+gboolean -+set_system_timezone (const char *filename, GError **err) -+{ -+ DBusGConnection *session_bus; -+ DBusGConnection *system_bus; -+ DBusGProxy *mechanism_proxy; -+ DBusGProxy *polkit_gnome_proxy; -+ gboolean ret = FALSE; -+ -+ session_bus = get_session_bus (); -+ if (session_bus == NULL) -+ goto out; -+ -+ system_bus = get_system_bus (); -+ if (system_bus == NULL) -+ goto out; -+ -+ mechanism_proxy = dbus_g_proxy_new_for_name (system_bus, -+ "org.gnome.ClockApplet.Mechanism", -+ "/", -+ "org.gnome.ClockApplet.Mechanism"); -+ -+ polkit_gnome_proxy = dbus_g_proxy_new_for_name (session_bus, -+ "org.gnome.PolicyKit", -+ "/org/gnome/PolicyKit/Manager", -+ "org.gnome.PolicyKit.Manager"); -+ -+ if (filename != NULL) { -+ GError *error; -+ -+ g_debug ("Trying to set timezone '%s'", filename); -+ try_again: -+ error = NULL; -+ /* first, try to call into the mechanism */ -+ if (!dbus_g_proxy_call_with_timeout (mechanism_proxy, -+ "SetTimezone", -+ INT_MAX, -+ &error, -+ /* parameters: */ -+ G_TYPE_STRING, filename, -+ G_TYPE_INVALID, -+ /* return values: */ -+ G_TYPE_INVALID)) { -+ if (dbus_g_error_has_name (error, "org.gnome.ClockApplet.Mechanism.NotPrivileged")) { -+ char **tokens; -+ char *polkit_result_textual; -+ char *polkit_action; -+ gboolean gained_privilege; -+ -+ tokens = g_strsplit (error->message, " ", 2); -+ g_error_free (error); -+ if (g_strv_length (tokens) != 2) { -+ g_warning ("helper return string malformed"); -+ g_strfreev (tokens); -+ goto out; -+ } -+ polkit_action = tokens[0]; -+ polkit_result_textual = tokens[1]; -+ -+ g_debug ("helper refused; returned polkit_result='%s' and polkit_action='%s'", -+ polkit_result_textual, polkit_action); -+ -+ /* Now ask the user for auth... */ -+ if (!dbus_g_proxy_call_with_timeout (polkit_gnome_proxy, -+ "ShowDialog", -+ INT_MAX, -+ &error, -+ /* parameters: */ -+ G_TYPE_STRING, polkit_action, -+ G_TYPE_UINT, 0, /* X11 window ID; none */ -+ G_TYPE_INVALID, -+ /* return values: */ -+ G_TYPE_BOOLEAN, &gained_privilege, -+ G_TYPE_INVALID)) { -+ g_propagate_error (err, error); -+ g_strfreev (tokens); -+ goto out; -+ } -+ g_strfreev (tokens); -+ -+ if (gained_privilege) { -+ g_debug ("Gained privilege; trying to set timezone again"); -+ goto try_again; -+ } -+ -+ } else { -+ g_propagate_error (err, error); -+ } -+ goto out; -+ } -+ -+ g_debug ("Successfully set time zone to '%s'", filename); -+ } -+ -+ ret = TRUE; -+out: -+ g_object_unref (mechanism_proxy); -+ g_object_unref (polkit_gnome_proxy); -+ -+ return ret; -+} -+ -+static gint -+can_do (const gchar *pk_action_id) -+{ -+ DBusConnection *system_bus; -+ PolKitCaller *pk_caller; -+ PolKitAction *pk_action; -+ PolKitResult pk_result; -+ PolKitContext *pk_context; -+ DBusError dbus_error; -+ gint res = 0; -+ -+ system_bus = dbus_g_connection_get_connection (get_system_bus ()); -+ if (system_bus == NULL) -+ goto out; -+ -+ pk_context = get_pk_context (); -+ if (pk_context == NULL) -+ goto out; -+ -+ pk_caller = NULL; -+ pk_action = NULL; -+ -+ pk_action = polkit_action_new (); -+ polkit_action_set_action_id (pk_action, pk_action_id); -+ -+ dbus_error_init (&dbus_error); -+ pk_caller = polkit_caller_new_from_pid (system_bus, getpid (), &dbus_error); -+ if (pk_caller == NULL) { -+ fprintf (stderr, "cannot get caller from dbus name\n"); -+ goto out; -+ } -+ -+ pk_result = polkit_context_can_caller_do_action (pk_context, pk_action, pk_caller); -+ -+ switch (pk_result) { -+ default: -+ case POLKIT_RESULT_UNKNOWN: -+ case POLKIT_RESULT_NO: -+ res = 0; -+ break; -+ case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH: -+ case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_SESSION: -+ case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_ALWAYS: -+ case POLKIT_RESULT_ONLY_VIA_SELF_AUTH: -+ case POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_SESSION: -+ case POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_ALWAYS: -+ res = 1; -+ break; -+ case POLKIT_RESULT_YES: -+ res = 2; -+ break; -+ } -+ -+out: -+ if (pk_action != NULL) -+ polkit_action_unref (pk_action); -+ if (pk_caller != NULL) -+ polkit_caller_unref (pk_caller); -+ -+ return res; -+} -+ -+gint -+can_set_system_timezone (void) -+{ -+ return can_do ("org.gnome.clockapplet.mechanism.settimezone"); -+} -+ -+gint -+can_set_system_time (void) -+{ -+ return can_do ("org.gnome.clockapplet.mechanism.settime"); -+} -+ -+typedef struct { -+ gint ref_count; -+ gint64 time; -+ 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); -+ } -+} -+ -+static void set_time_async (SetTimeCallbackData *data); -+ -+static void -+auth_notify (DBusGProxy *proxy, -+ DBusGProxyCall *call, -+ void *user_data) -+{ -+ SetTimeCallbackData *data = user_data; -+ GError *error = NULL; -+ gboolean gained_privilege; -+ -+ if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_BOOLEAN, &gained_privilege, G_TYPE_INVALID)) { -+ if (gained_privilege) -+ set_time_async (data); -+ } -+ else { -+ if (data->callback) -+ data->callback (data->data, error); -+ else -+ g_error_free (error); -+ } -+} -+ -+static void -+do_auth_async (const gchar *action, -+ const gchar *result, -+ SetTimeCallbackData *data) -+{ -+ DBusGConnection *bus; -+ DBusGProxy *proxy; -+ -+ g_debug ("helper refused; returned polkit_result='%s' and polkit_action='%s'", -+ result, action); -+ -+ /* Now ask the user for auth... */ -+ bus = get_session_bus (); -+ if (bus == NULL) -+ return; -+ -+ proxy = dbus_g_proxy_new_for_name (bus, -+ "org.gnome.PolicyKit", -+ "/org/gnome/PolicyKit/Manager", -+ "org.gnome.PolicyKit.Manager"); -+ -+ data->ref_count++; -+ dbus_g_proxy_begin_call_with_timeout (proxy, -+ "ShowDialog", -+ auth_notify, -+ data, free_data, -+ INT_MAX, -+ G_TYPE_STRING, action, -+ G_TYPE_UINT, 0, -+ G_TYPE_INVALID); -+} -+ -+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 (dbus_g_error_has_name (error, "org.gnome.ClockApplet.Mechanism.NotPrivileged")) { -+ gchar **tokens; -+ -+ tokens = g_strsplit (error->message, " ", 2); -+ g_error_free (error); -+ if (g_strv_length (tokens) == 2) -+ do_auth_async (tokens[0], tokens[1], data); -+ else -+ g_warning ("helper return string malformed"); -+ g_strfreev (tokens); -+ } -+ 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; -+ DBusGProxyCall *call; -+ -+ bus = get_system_bus (); -+ if (bus == NULL) -+ return; -+ -+ proxy = dbus_g_proxy_new_for_name (bus, -+ "org.gnome.ClockApplet.Mechanism", -+ "/", -+ "org.gnome.ClockApplet.Mechanism"); -+ -+ data->ref_count++; -+ 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); -+} -+ -+void -+set_system_time_async (gint64 time, -+ GFunc callback, -+ gpointer d, -+ GDestroyNotify notify) -+{ -+ SetTimeCallbackData *data; -+ -+ if (time == -1) -+ return; -+ -+ data = g_new (SetTimeCallbackData, 1); -+ data->ref_count = 1; -+ data->time = time; -+ data->callback = callback; -+ data->data = d; -+ data->notify = notify; -+ -+ set_time_async (data); -+ free_data (data); -+} -diff --git a/src/set-timezone.h b/src/set-timezone.h -new file mode 100644 -index 0000000..c71622c ---- /dev/null -+++ b/src/set-timezone.h -@@ -0,0 +1,36 @@ -+/* -*- 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 -+ -+gboolean set_system_timezone (const char *filename, -+ GError **err); -+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); -+ -+#endif diff --git a/intlclock-changes-20071013.patch b/intlclock-changes-20071013.patch deleted file mode 100644 index b414c42..0000000 --- a/intlclock-changes-20071013.patch +++ /dev/null @@ -1,12214 +0,0 @@ -diff --git a/configure.in b/configure.in -index 4e818da..6c75db1 100644 ---- a/configure.in -+++ b/configure.in -@@ -59,7 +59,7 @@ if test -n "$LIBECAL_REQUIREMENT"; then - fi - AM_CONDITIONAL(HAVE_LIBECAL, test -n "$LIBECAL_REQUIREMENT") - --PKG_CHECK_MODULES(INTLCLOCK, [ glib-2.0 gobject-2.0 gtk+-2.0 gdk-2.0 librsvg-2.0 libpanelapplet-2.0 libgnome-2.0 gconf-2.0 $LIBECAL_REQUIREMENT ]) -+PKG_CHECK_MODULES(INTLCLOCK, [ glib-2.0 gobject-2.0 gtk+-2.0 gdk-2.0 librsvg-2.0 libpanelapplet-2.0 libgnome-2.0 gconf-2.0 $LIBECAL_REQUIREMENT dbus-glib-1 gweather libxml-2.0 polkit polkit-dbus ]) - - AC_SUBST(INTLCLOCK_CFLAGS) - AC_SUBST(INTLCLOCK_LIBS) -diff --git a/data/GNOME_IntlClockApplet.xml b/data/GNOME_IntlClockApplet.xml -index dd2e8b8..a88dc3d 100644 ---- a/data/GNOME_IntlClockApplet.xml -+++ b/data/GNOME_IntlClockApplet.xml -@@ -1,9 +1,14 @@ - - - -+ -+ -+ - -+ _label="Ad_just Date & Time" -+ pixtype="stock" pixname="gtk-preferences"/> - - -diff --git a/data/GNOME_IntlClockApplet_Factory.server.in.in b/data/GNOME_IntlClockApplet_Factory.server.in.in -index 1446822..705fb76 100644 ---- a/data/GNOME_IntlClockApplet_Factory.server.in.in -+++ b/data/GNOME_IntlClockApplet_Factory.server.in.in -@@ -20,7 +20,7 @@ - - - -- -+ - - - - -+ 6 - True - False - 0 - - -- -+ - 6 - True - True -@@ -37,194 +38,35 @@ - False - - -- -- 6 -+ -+ 12 - True -- 4 -- 3 - False -- 6 -- 6 -+ 18 - - -- -- True -- Clock options: -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 0 -- 1 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 2 -- 3 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 3 -- 4 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 2 -- 3 -- 3 -- 4 -- fill -- -- -- -- -- -- -- True -- True -- Show s_econds -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- -- -- 1 -- 3 -- 2 -- 3 -- fill -- -- -- -- -- -- -+ - True - False - 6 - - -- -+ - True -- True -- 12 _hour format -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -+ <b>Clock Options</b> -+ False -+ True -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 - - - 0 -@@ -234,138 +76,150 @@ - - - -- -+ - True -- True -- 24 h_our format -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- 12hr_radio -+ False -+ 0 -+ -+ -+ -+ True -+ -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ False -+ 13 -+ -+ -+ -+ True -+ True -+ 12 _hour format -+ True -+ GTK_RELIEF_NORMAL -+ True -+ False -+ False -+ True -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ True -+ 24 h_our format -+ True -+ GTK_RELIEF_NORMAL -+ True -+ False -+ False -+ True -+ 12hr_radio -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ Show the _date -+ True -+ GTK_RELIEF_NORMAL -+ True -+ False -+ False -+ True -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ True -+ Show _seconds -+ True -+ GTK_RELIEF_NORMAL -+ True -+ False -+ False -+ True -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ - - - 0 -- False -- False -+ True -+ True - - - - -- 1 -- 2 -- 0 -- 1 -- fill -- fill -- -- -- -- -- -- True -- True -- Show the _date -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- -- -- 1 -- 2 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 2 -- 3 -- 0 -- 1 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 2 -- 3 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 1 -- 2 -- 3 -- 4 -- fill -- -+ 0 -+ False -+ True - - - -@@ -376,7 +230,7 @@ - - - -- -+ - True - General - False -@@ -399,332 +253,105 @@ - - - -- -- 6 -+ -+ 12 - True -- 8 -- 4 - False -- 6 -- 6 -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 3 -- 4 -- 0 -- 1 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 3 -- 4 -- 1 -- 2 -- fill -- -- -- -+ 18 - - -- -+ - True -- True -- GTK_POLICY_NEVER -- GTK_POLICY_NEVER -- GTK_SHADOW_IN -- GTK_CORNER_TOP_LEFT -+ False -+ 12 - - -- -+ - True - True -- False -- False -- False -- True -- False -- False -- True -+ GTK_POLICY_NEVER -+ GTK_POLICY_NEVER -+ GTK_SHADOW_IN -+ GTK_CORNER_TOP_LEFT -+ -+ -+ -+ True -+ True -+ False -+ False -+ False -+ True -+ False -+ False -+ True -+ -+ - -+ -+ 0 -+ True -+ True -+ - -- -- -- 0 -- 3 -- 2 -- 8 -- fill -- -- -- -- -- -- True -- 0 -- 0.5 -- 0 -- 1 -- 0 -- 0 -- 0 -- 0 - - -- -+ - True -- False -+ GTK_BUTTONBOX_START - 6 - - -- -+ -+ 24 -+ 25 - True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0.5 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -+ True -+ True -+ gtk-add -+ True -+ GTK_RELIEF_NORMAL -+ True - -- -- 0 -- False -- False -- - - - -- -+ -+ 24 -+ 24 - True -- GTK_BUTTONBOX_START -- 6 -- -- -- -- 24 -- 25 -- True -- True -- True -- gtk-add -- True -- GTK_RELIEF_NORMAL -- True -- -- -- -- -- -- 24 -- 24 -- True -- True -- True -- gtk-edit -- True -- GTK_RELIEF_NORMAL -- True -- -- -- -- -- -- True -- True -- True -- gtk-remove -- True -- GTK_RELIEF_NORMAL -- True -- -- -+ True -+ True -+ gtk-edit -+ True -+ GTK_RELIEF_NORMAL -+ True - -- -- 0 -- False -- False -- - - - -- -+ - True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0.5 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -+ True -+ True -+ gtk-remove -+ True -+ GTK_RELIEF_NORMAL -+ True - -- -- 0 -- False -- False -- - - -+ -+ 0 -+ False -+ False -+ - - - -- 3 -- 4 -- 2 -- 8 -- -- fill -- -- -- -- -- -- True -- True -- Show the world _map in the clock -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- -- -- 0 -- 1 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0.5 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 2 -- 3 -- 1 -- 2 -- -- -- -- -- -- -- True -- -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 1 -- 2 -- 1 -- 2 -- fill -- -- -- -- -- -- -- True -- True -- S_how locations in the clock -- True -- GTK_RELIEF_NORMAL -- True -- False -- False -- True -- -- -- 0 -- 3 -- 0 -- 1 -- fill -- -+ 0 -+ True -+ True - - - -@@ -735,7 +362,7 @@ - - - -- -+ - True - Locations - False -@@ -772,95 +399,20 @@ - 0 - - -- -- True -- GTK_BUTTONBOX_DEFAULT_STYLE -- 0 -- -- -- 0 -- False -- False -- -- -- -- -- -+ - True - GTK_BUTTONBOX_END - 6 - - -- -+ - True - True - True -+ Time Settings -+ True - GTK_RELIEF_NORMAL - True -- -- -- -- True -- 0.5 -- 0.5 -- 0 -- 0 -- 0 -- 0 -- 0 -- 0 -- -- -- -- True -- False -- 2 -- -- -- -- True -- gtk-properties -- 4 -- 0.5 -- 0.5 -- 0 -- 0 -- -- -- 0 -- False -- False -- -- -- -- -- -- True -- Time _Settings -- True -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0.5 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- False -- False -- -- -- -- -- -- - - - -@@ -910,13 +462,13 @@ - - - -+ 12 - True - False -- 0 -+ 24 - - - -- 6 - True - 1 - 3 -@@ -926,7 +478,6 @@ - - - -- 6 - True - False - 6 -@@ -974,62 +525,6 @@ - 6 - - -- -- True -- Timezone: -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 0 -- 1 -- fill -- -- -- -- -- -- -- True -- Location Name: -- False -- False -- GTK_JUSTIFY_LEFT -- False -- False -- 0 -- 0.5 -- 0 -- 0 -- PANGO_ELLIPSIZE_NONE -- -1 -- False -- 0 -- -- -- 0 -- 1 -- 1 -- 2 -- fill -- -- -- -- -- - - True - True -@@ -1070,45 +565,6 @@ - - - -- -- True -- Dummy Item -- False -- True -- True -- -- -- 1 -- 4 -- 0 -- 1 -- fill -- fill -- -- -- -- -- -- True -- True -- True -- True -- 0 -- -- True -- -- False -- -- -- 1 -- 4 -- 1 -- 2 -- -- -- -- -- - - True - Longitude: -@@ -1145,7 +601,7 @@ - 0 - - True -- -+ - False - - -@@ -1258,7 +714,7 @@ South - 0 - - True -- -+ - False - - -@@ -1269,6 +725,131 @@ South - - - -+ -+ -+ -+ True -+ Location Name: -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ 1 -+ 0 -+ 1 -+ fill -+ -+ -+ -+ -+ -+ -+ True -+ Timezone: -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ 1 -+ 1 -+ 2 -+ fill -+ -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ True -+ True -+ True -+ 0 -+ -+ True -+ -+ False -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ Find... -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 1 -+ 4 -+ 0 -+ 1 -+ fill -+ fill -+ -+ -+ -+ -+ -+ True -+ Dummy Item -+ False -+ True -+ True -+ -+ -+ 1 -+ 4 -+ 1 -+ 2 -+ fill -+ fill -+ -+ - - - 0 -@@ -1294,60 +875,33 @@ South - - - -- -- 6 -+ - True -- False -- 0 -+ GTK_BUTTONBOX_END -+ 6 - - -- -+ - True -- GTK_BUTTONBOX_DEFAULT_STYLE -- 0 -+ True -+ True -+ gtk-cancel -+ True -+ GTK_RELIEF_NORMAL -+ True - -- -- 0 -- False -- False -- - - - -- -+ - True -- GTK_BUTTONBOX_END -- 6 -- -- -- -- True -- True -- True -- gtk-cancel -- True -- GTK_RELIEF_NORMAL -- True -- -- -- -- -- -- True -- True -- True -- gtk-ok -- True -- GTK_RELIEF_NORMAL -- True -- -- -+ True -+ True -+ gtk-ok -+ True -+ GTK_RELIEF_NORMAL -+ True - -- -- 0 -- True -- True -- - - - -@@ -1723,4 +1277,580 @@ South - - - -+ -+ -+ GTK_WINDOW_TOPLEVEL -+ GTK_WIN_POS_NONE -+ False -+ True -+ False -+ True -+ False -+ False -+ GDK_WINDOW_TYPE_HINT_NORMAL -+ GDK_GRAVITY_NORTH_WEST -+ True -+ False -+ -+ -+ -+ 12 -+ True -+ False -+ 24 -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ True -+ GTK_POLICY_AUTOMATIC -+ GTK_POLICY_AUTOMATIC -+ GTK_SHADOW_IN -+ GTK_CORNER_TOP_LEFT -+ -+ -+ -+ True -+ True -+ False -+ False -+ False -+ False -+ False -+ False -+ False -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ _Find: -+ True -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ find-location-entry -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ True -+ True -+ True -+ 0 -+ -+ True -+ -+ False -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ True -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ 0 -+ 0 -+ 0 -+ 0 -+ -+ -+ -+ True -+ False -+ 2 -+ -+ -+ -+ True -+ gtk-find -+ 4 -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ Find _Next -+ True -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ GTK_BUTTONBOX_END -+ 0 -+ -+ -+ -+ True -+ True -+ True -+ gtk-cancel -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ True -+ gtk-ok -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ -+ -+ 12 -+ Time Settings -+ GTK_WINDOW_TOPLEVEL -+ GTK_WIN_POS_NONE -+ False -+ True -+ False -+ True -+ False -+ False -+ GDK_WINDOW_TYPE_HINT_NORMAL -+ GDK_GRAVITY_NORTH_WEST -+ True -+ False -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ <b>Time Settings</b> -+ False -+ True -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ False -+ 0 -+ -+ -+ -+ True -+ -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0.5 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ False -+ 12 -+ -+ -+ -+ True -+ True -+ GTK_CALENDAR_SHOW_HEADING -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ Current Time: -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ Time: -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ False -+ 6 -+ -+ -+ -+ True -+ 23:59:59 -+ False -+ False -+ GTK_JUSTIFY_LEFT -+ False -+ False -+ 0 -+ 0.5 -+ 0 -+ 0 -+ PANGO_ELLIPSIZE_NONE -+ -1 -+ False -+ 0 -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ False -+ 0 -+ -+ -+ -+ True -+ True -+ 1 -+ 0 -+ True -+ GTK_UPDATE_ALWAYS -+ False -+ True -+ 23 0 23 1 12 12 -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ 1 -+ 0 -+ True -+ GTK_UPDATE_ALWAYS -+ False -+ True -+ 59 0 59 1 30 30 -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ 1 -+ 0 -+ True -+ GTK_UPDATE_ALWAYS -+ False -+ True -+ 59 0 59 1 30 30 -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ 0 -+ False -+ True -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ 0 -+ False -+ False -+ -+ -+ -+ -+ -+ True -+ False -+ 0 -+ -+ -+ -+ True -+ GTK_BUTTONBOX_END -+ 6 -+ -+ -+ -+ True -+ True -+ True -+ gtk-cancel -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ -+ True -+ True -+ Set System Time -+ True -+ GTK_RELIEF_NORMAL -+ True -+ -+ -+ -+ -+ 0 -+ True -+ True -+ -+ -+ -+ -+ 0 -+ False -+ False -+ GTK_PACK_END -+ -+ -+ -+ -+ -+ - -diff --git a/data/intlclock.schemas.in b/data/intlclock.schemas.in -index 2ab6772..00fee4f 100644 ---- a/data/intlclock.schemas.in -+++ b/data/intlclock.schemas.in -@@ -89,41 +89,54 @@ - - - -- /schemas/apps/intlclock_applet/prefs/show_locations -+ /schemas/apps/intlclock_applet/prefs/cities -+ clock-applet -+ list -+ string -+ [] -+ -+ List of cities for the clock. -+ -+ List of cities to display in the international clock. -+ -+ -+ -+ -+ -+ /schemas/apps/intlclock_applet/prefs/expand_locations - clock-applet - bool - true - -- Show other locations in clock -+ Expand the location section in clock - -- If true, show a list of locations in the international clock. -+ If true, expand the list of locations in the international clock. - - - - - -- /schemas/apps/intlclock_applet/prefs/show_map -+ /schemas/apps/intlclock_applet/prefs/expand_tasks - clock-applet - bool - true - -- Show world map in clock -+ Expand the tasks section in clock - -- If true, show the world map in the international clock. -+ If true, expand the list of tasks in the international clock. - - - - - -- /schemas/apps/intlclock_applet/prefs/cities -+ /schemas/apps/intlclock_applet/prefs/expand_appointments - clock-applet -- list -- string -- [] -+ bool -+ true - -- List of cities for the clock. -+ Expand the appointments section in clock - -- List of cities to display in the international clock. -+ If true, expand the list of appointments in the international clock. - - - -diff --git a/intltool-extract.in b/intltool-extract.in -deleted file mode 100755 -index bb6c368..340fc8d ---- a/intltool-extract.in -+++ /dev/null -@@ -1,841 +0,0 @@ --#!@INTLTOOL_PERL@ -w --# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- -- --# --# The Intltool Message Extractor --# --# Copyright (C) 2000-2001, 2003 Free Software Foundation. --# --# Intltool 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. --# --# Intltool 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., 675 Mass Ave, Cambridge, MA 02139, USA. --# --# As a special exception to the GNU General Public License, if you --# distribute this file as part of a program that contains a --# configuration script generated by Autoconf, you may include it under --# the same distribution terms that you use for the rest of that program. --# --# Authors: Kenneth Christiansen --# Darin Adler --# -- --## Release information --my $PROGRAM = "intltool-extract"; --my $PACKAGE = "intltool"; --my $VERSION = "0.35.0"; -- --## Loaded modules --use strict; --use File::Basename; --use Getopt::Long; -- --## Scalars used by the option stuff --my $TYPE_ARG = "0"; --my $LOCAL_ARG = "0"; --my $HELP_ARG = "0"; --my $VERSION_ARG = "0"; --my $UPDATE_ARG = "0"; --my $QUIET_ARG = "0"; --my $SRCDIR_ARG = "."; -- --my $FILE; --my $OUTFILE; -- --my $gettext_type = ""; --my $input; --my %messages = (); --my %loc = (); --my %count = (); --my %comments = (); --my $strcount = 0; -- --my $XMLCOMMENT = ""; -- --## Use this instead of \w for XML files to handle more possible characters. --my $w = "[-A-Za-z0-9._:]"; -- --## Always print first --$| = 1; -- --## Handle options --GetOptions ( -- "type=s" => \$TYPE_ARG, -- "local|l" => \$LOCAL_ARG, -- "help|h" => \$HELP_ARG, -- "version|v" => \$VERSION_ARG, -- "update" => \$UPDATE_ARG, -- "quiet|q" => \$QUIET_ARG, -- "srcdir=s" => \$SRCDIR_ARG, -- ) or &error; -- --&split_on_argument; -- -- --## Check for options. --## This section will check for the different options. -- --sub split_on_argument { -- -- if ($VERSION_ARG) { -- &version; -- -- } elsif ($HELP_ARG) { -- &help; -- -- } elsif ($LOCAL_ARG) { -- &place_local; -- &extract; -- -- } elsif ($UPDATE_ARG) { -- &place_normal; -- &extract; -- -- } elsif (@ARGV > 0) { -- &place_normal; -- &message; -- &extract; -- -- } else { -- &help; -- -- } --} -- --sub place_normal { -- $FILE = $ARGV[0]; -- $OUTFILE = "$FILE.h"; --} -- --sub place_local { -- $FILE = $ARGV[0]; -- $OUTFILE = fileparse($FILE, ()); -- if (!-e "tmp/") { -- system("mkdir tmp/"); -- } -- $OUTFILE = "./tmp/$OUTFILE.h" --} -- --sub determine_type { -- if ($TYPE_ARG =~ /^gettext\/(.*)/) { -- $gettext_type=$1 -- } --} -- --## Sub for printing release information --sub version{ -- print <<_EOF_; --${PROGRAM} (${PACKAGE}) $VERSION --Copyright (C) 2000, 2003 Free Software Foundation, Inc. --Written by Kenneth Christiansen, 2000. -- --This is free software; see the source for copying conditions. There is NO --warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. --_EOF_ -- exit; --} -- --## Sub for printing usage information --sub help { -- print <<_EOF_; --Usage: ${PROGRAM} [OPTION]... [FILENAME] --Generates a header file from an XML source file. -- --It grabs all strings between <_translatable_node> and its end tag in --XML files. Read manpage (man ${PROGRAM}) for more info. -- -- --type=TYPE Specify the file type of FILENAME. Currently supports: -- "gettext/glade", "gettext/ini", "gettext/keys" -- "gettext/rfc822deb", "gettext/schemas", -- "gettext/scheme", "gettext/xml" -- -l, --local Writes output into current working directory -- (conflicts with --update) -- --update Writes output into the same directory the source file -- reside (conflicts with --local) -- --srcdir Root of the source tree -- -v, --version Output version information and exit -- -h, --help Display this help and exit -- -q, --quiet Quiet mode -- --Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE") --or send email to . --_EOF_ -- exit; --} -- --## Sub for printing error messages --sub error{ -- print STDERR "Try `${PROGRAM} --help' for more information.\n"; -- exit; --} -- --sub message { -- print "Generating C format header file for translation.\n" unless $QUIET_ARG; --} -- --sub extract { -- &determine_type; -- -- &convert; -- -- open OUT, ">$OUTFILE"; -- binmode (OUT) if $^O eq 'MSWin32'; -- &msg_write; -- close OUT; -- -- print "Wrote $OUTFILE\n" unless $QUIET_ARG; --} -- --sub convert { -- -- ## Reading the file -- { -- local (*IN); -- local $/; #slurp mode -- open (IN, "<$SRCDIR_ARG/$FILE") || die "can't open $SRCDIR_ARG/$FILE: $!"; -- $input = ; -- } -- -- &type_ini if $gettext_type eq "ini"; -- &type_keys if $gettext_type eq "keys"; -- &type_xml if $gettext_type eq "xml"; -- &type_glade if $gettext_type eq "glade"; -- &type_scheme if $gettext_type eq "scheme"; -- &type_schemas if $gettext_type eq "schemas"; -- &type_rfc822deb if $gettext_type eq "rfc822deb"; --} -- --sub entity_decode_minimal --{ -- local ($_) = @_; -- -- s/'/'/g; # ' -- s/"/"/g; # " -- s/&/&/g; -- -- return $_; --} -- --sub entity_decode --{ -- local ($_) = @_; -- -- s/'/'/g; # ' -- s/"/"/g; # " -- s/&/&/g; -- s/<//g; -- -- return $_; --} -- --sub escape_char --{ -- return '\"' if $_ eq '"'; -- return '\n' if $_ eq "\n"; -- return '\\' if $_ eq '\\'; -- -- return $_; --} -- --sub escape --{ -- my ($string) = @_; -- return join "", map &escape_char, split //, $string; --} -- --sub type_ini { -- ### For generic translatable desktop files ### -- while ($input =~ /^_.*=(.*)$/mg) { -- $messages{$1} = []; -- } --} -- --sub type_keys { -- ### For generic translatable mime/keys files ### -- while ($input =~ /^\s*_\w+=(.*)$/mg) { -- $messages{$1} = []; -- } --} -- --sub type_xml { -- ### For generic translatable XML files ### -- my $tree = readXml($input); -- parseTree(0, $tree); --} -- --sub print_var { -- my $var = shift; -- my $vartype = ref $var; -- -- if ($vartype =~ /ARRAY/) { -- my @arr = @{$var}; -- print "[ "; -- foreach my $el (@arr) { -- print_var($el); -- print ", "; -- } -- print "] "; -- } elsif ($vartype =~ /HASH/) { -- my %hash = %{$var}; -- print "{ "; -- foreach my $key (keys %hash) { -- print "$key => "; -- print_var($hash{$key}); -- print ", "; -- } -- print "} "; -- } else { -- print $var; -- } --} -- --# Same syntax as getAttributeString in intltool-merge.in.in, similar logic (look for ## differences comment) --sub getAttributeString --{ -- my $sub = shift; -- my $do_translate = shift || 1; -- my $language = shift || ""; -- my $translate = shift; -- my $result = ""; -- foreach my $e (reverse(sort(keys %{ $sub }))) { -- my $key = $e; -- my $string = $sub->{$e}; -- my $quote = '"'; -- -- $string =~ s/^[\s]+//; -- $string =~ s/[\s]+$//; -- -- if ($string =~ /^'.*'$/) -- { -- $quote = "'"; -- } -- $string =~ s/^['"]//g; -- $string =~ s/['"]$//g; -- -- ## differences from intltool-merge.in.in -- if ($key =~ /^_/) { -- $comments{entity_decode($string)} = $XMLCOMMENT if $XMLCOMMENT; -- $messages{entity_decode($string)} = []; -- $$translate = 2; -- } -- ## differences end here from intltool-merge.in.in -- $result .= " $key=$quote$string$quote"; -- } -- return $result; --} -- --# Verbatim copy from intltool-merge.in.in --sub getXMLstring --{ -- my $ref = shift; -- my $spacepreserve = shift || 0; -- my @list = @{ $ref }; -- my $result = ""; -- -- my $count = scalar(@list); -- my $attrs = $list[0]; -- my $index = 1; -- -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); -- -- while ($index < $count) { -- my $type = $list[$index]; -- my $content = $list[$index+1]; -- if (! $type ) { -- # We've got CDATA -- if ($content) { -- # lets strip the whitespace here, and *ONLY* here -- $content =~ s/\s+/ /gs if (!$spacepreserve); -- $result .= $content; -- } -- } elsif ( "$type" ne "1" ) { -- # We've got another element -- $result .= "<$type"; -- $result .= getAttributeString(@{$content}[0], 0); # no nested translatable elements -- if ($content) { -- my $subresult = getXMLstring($content, $spacepreserve); -- if ($subresult) { -- $result .= ">".$subresult . ""; -- } else { -- $result .= "/>"; -- } -- } else { -- $result .= "/>"; -- } -- } -- $index += 2; -- } -- return $result; --} -- --# Verbatim copy from intltool-merge.in.in, except for MULTIPLE_OUTPUT handling removed --# Translate list of nodes if necessary --sub translate_subnodes --{ -- my $fh = shift; -- my $content = shift; -- my $language = shift || ""; -- my $singlelang = shift || 0; -- my $spacepreserve = shift || 0; -- -- my @nodes = @{ $content }; -- -- my $count = scalar(@nodes); -- my $index = 0; -- while ($index < $count) { -- my $type = $nodes[$index]; -- my $rest = $nodes[$index+1]; -- traverse($fh, $type, $rest, $language, $spacepreserve); -- $index += 2; -- } --} -- --# Based on traverse() in intltool-merge.in.in --sub traverse --{ -- my $fh = shift; # unused, to allow us to sync code between -merge and -extract -- my $nodename = shift; -- my $content = shift; -- my $language = shift || ""; -- my $spacepreserve = shift || 0; -- -- if ($nodename && "$nodename" eq "1") { -- $XMLCOMMENT = $content; -- } elsif ($nodename) { -- # element -- my @all = @{ $content }; -- my $attrs = shift @all; -- my $translate = 0; -- my $outattr = getAttributeString($attrs, 1, $language, \$translate); -- -- if ($nodename =~ /^_/) { -- $translate = 1; -- $nodename =~ s/^_//; -- } -- my $lookup = ''; -- -- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- -- if ($translate) { -- $lookup = getXMLstring($content, $spacepreserve); -- if (!$spacepreserve) { -- $lookup =~ s/^\s+//s; -- $lookup =~ s/\s+$//s; -- } -- -- if ($lookup && $translate != 2) { -- $comments{$lookup} = $XMLCOMMENT if $XMLCOMMENT; -- $messages{$lookup} = []; -- } elsif ($translate == 2) { -- translate_subnodes($fh, \@all, $language, 1, $spacepreserve); -- } -- } else { -- $XMLCOMMENT = ""; -- my $count = scalar(@all); -- if ($count > 0) { -- my $index = 0; -- while ($index < $count) { -- my $type = $all[$index]; -- my $rest = $all[$index+1]; -- traverse($fh, $type, $rest, $language, $spacepreserve); -- $index += 2; -- } -- } -- } -- $XMLCOMMENT = ""; -- } --} -- -- --# Verbatim copy from intltool-merge.in.in, $fh for compatibility --sub parseTree --{ -- my $fh = shift; -- my $ref = shift; -- my $language = shift || ""; -- -- my $name = shift @{ $ref }; -- my $cont = shift @{ $ref }; -- -- while (!$name || "$name" eq "1") { -- $name = shift @{ $ref }; -- $cont = shift @{ $ref }; -- } -- -- my $spacepreserve = 0; -- my $attrs = @{$cont}[0]; -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- -- traverse($fh, $name, $cont, $language, $spacepreserve); --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_comment --{ -- my $expat = shift; -- my $data = $expat->original_string(); -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- $data =~ s/^$//s; -- push @$clist, 1 => $data; --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_cdatastart --{ -- my $expat = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- push @$clist, 0 => $expat->original_string(); --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_cdataend --{ -- my $expat = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- $clist->[$pos] .= $expat->original_string(); --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_char --{ -- my $expat = shift; -- my $text = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- # Use original_string so that we retain escaped entities -- # in CDATA sections. -- # -- if ($pos > 0 and $clist->[$pos - 1] eq '0') { -- $clist->[$pos] .= $expat->original_string(); -- } else { -- push @$clist, 0 => $expat->original_string(); -- } --} -- --# Verbatim copy from intltool-merge.in.in --sub intltool_tree_start --{ -- my $expat = shift; -- my $tag = shift; -- my @origlist = (); -- -- # Use original_string so that we retain escaped entities -- # in attribute values. We must convert the string to an -- # @origlist array to conform to the structure of the Tree -- # Style. -- # -- my @original_array = split /\x/, $expat->original_string(); -- my $source = $expat->original_string(); -- -- # Remove leading tag. -- # -- $source =~ s|^\s*<\s*(\S+)||s; -- -- # Grab attribute key/value pairs and push onto @origlist array. -- # -- while ($source) -- { -- if ($source =~ /^\s*([\w:-]+)\s*[=]\s*["]/) -- { -- $source =~ s|^\s*([\w:-]+)\s*[=]\s*["]([^"]*)["]||s; -- push @origlist, $1; -- push @origlist, '"' . $2 . '"'; -- } -- elsif ($source =~ /^\s*([\w:-]+)\s*[=]\s*[']/) -- { -- $source =~ s|^\s*([\w:-]+)\s*[=]\s*[']([^']*)[']||s; -- push @origlist, $1; -- push @origlist, "'" . $2 . "'"; -- } -- else -- { -- last; -- } -- } -- -- my $ol = [ { @origlist } ]; -- -- push @{ $expat->{Lists} }, $expat->{Curlist}; -- push @{ $expat->{Curlist} }, $tag => $ol; -- $expat->{Curlist} = $ol; --} -- --# Copied from intltool-merge.in.in and added comment handler. --sub readXml --{ -- my $xmldoc = shift || return; -- my $ret = eval 'require XML::Parser'; -- if(!$ret) { -- die "You must have XML::Parser installed to run $0\n\n"; -- } -- my $xp = new XML::Parser(Style => 'Tree'); -- $xp->setHandlers(Char => \&intltool_tree_char); -- $xp->setHandlers(Start => \&intltool_tree_start); -- $xp->setHandlers(CdataStart => \&intltool_tree_cdatastart); -- $xp->setHandlers(CdataEnd => \&intltool_tree_cdataend); -- -- ## differences from intltool-merge.in.in -- $xp->setHandlers(Comment => \&intltool_tree_comment); -- ## differences end here from intltool-merge.in.in -- -- my $tree = $xp->parse($xmldoc); -- #print_var($tree); -- --# Hello thereHowdydo --# would be: --# [foo, [{}, 1, "comment", head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]], bar, --# [{}, 0, "Howdy", ref, [{}]], 0, "do" ] ] -- -- return $tree; --} -- --sub type_schemas { -- ### For schemas XML files ### -- -- # FIXME: We should handle escaped < (less than) -- while ($input =~ / -- \s* -- (\s*(?:\s*)?(.*?)\s*<\/default>\s*)? -- (\s*(?:\s*)?(.*?)\s*<\/short>\s*)? -- (\s*(?:\s*)?(.*?)\s*<\/long>\s*)? -- <\/locale> -- /sgx) { -- my @totranslate = ($3,$6,$9); -- my @eachcomment = ($2,$5,$8); -- foreach (@totranslate) { -- my $currentcomment = shift @eachcomment; -- next if !$_; -- s/\s+/ /g; -- $messages{entity_decode_minimal($_)} = []; -- $comments{entity_decode_minimal($_)} = $currentcomment if (defined($currentcomment)); -- } -- } --} -- --sub type_rfc822deb { -- ### For rfc822-style Debian configuration files ### -- -- my $lineno = 1; -- my $type = ''; -- while ($input =~ /\G(.*?)(^|\n)(_+)([^:]+):[ \t]*(.*?)(?=\n\S|$)/sg) -- { -- my ($pre, $newline, $underscore, $tag, $text) = ($1, $2, $3, $4, $5); -- while ($pre =~ m/\n/g) -- { -- $lineno ++; -- } -- $lineno += length($newline); -- my @str_list = rfc822deb_split(length($underscore), $text); -- for my $str (@str_list) -- { -- $strcount++; -- $messages{$str} = []; -- $loc{$str} = $lineno; -- $count{$str} = $strcount; -- my $usercomment = ''; -- while($pre =~ s/(^|\n)#([^\n]*)$//s) -- { -- $usercomment = "\n" . $2 . $usercomment; -- } -- $comments{$str} = $tag . $usercomment; -- } -- $lineno += ($text =~ s/\n//g); -- } --} -- --sub rfc822deb_split { -- # Debian defines a special way to deal with rfc822-style files: -- # when a value contain newlines, it consists of -- # 1. a short form (first line) -- # 2. a long description, all lines begin with a space, -- # and paragraphs are separated by a single dot on a line -- # This routine returns an array of all paragraphs, and reformat -- # them. -- # When first argument is 2, the string is a comma separated list of -- # values. -- my $type = shift; -- my $text = shift; -- $text =~ s/^[ \t]//mg; -- return (split(/, */, $text, 0)) if $type ne 1; -- return ($text) if $text !~ /\n/; -- -- $text =~ s/([^\n]*)\n//; -- my @list = ($1); -- my $str = ''; -- for my $line (split (/\n/, $text)) -- { -- chomp $line; -- if ($line =~ /^\.\s*$/) -- { -- # New paragraph -- $str =~ s/\s*$//; -- push(@list, $str); -- $str = ''; -- } -- elsif ($line =~ /^\s/) -- { -- # Line which must not be reformatted -- $str .= "\n" if length ($str) && $str !~ /\n$/; -- $line =~ s/\s+$//; -- $str .= $line."\n"; -- } -- else -- { -- # Continuation line, remove newline -- $str .= " " if length ($str) && $str !~ /\n$/; -- $str .= $line; -- } -- } -- $str =~ s/\s*$//; -- push(@list, $str) if length ($str); -- return @list; --} -- --sub type_glade { -- ### For translatable Glade XML files ### -- -- my $tags = "label|title|text|format|copyright|comments|preview_text|tooltip|message"; -- -- while ($input =~ /<($tags)>([^<]+)<\/($tags)>/sg) { -- # Glade sometimes uses tags that normally mark translatable things for -- # little bits of non-translatable content. We work around this by not -- # translating strings that only includes something like label4 or window1. -- $messages{entity_decode($2)} = [] unless $2 =~ /^(window|label|dialog)[0-9]+$/; -- } -- -- while ($input =~ /(..[^<]*)<\/items>/sg) { -- for my $item (split (/\n/, $1)) { -- $messages{entity_decode($item)} = []; -- } -- } -- -- ## handle new glade files -- while ($input =~ /<(property|atkproperty)\s+[^>]*translatable\s*=\s*"yes"(?:\s+[^>]*comments\s*=\s*"([^"]*)")?[^>]*>([^<]+)<\/\1>/sg) { -- $messages{entity_decode($3)} = [] unless $3 =~ /^(window|label)[0-9]+$/; -- if (defined($2) and !($3 =~ /^(window|label)[0-9]+$/)) { -- $comments{entity_decode($3)} = entity_decode($2) ; -- } -- } -- while ($input =~ /]*)"\s+description="([^>]+)"\/>/sg) { -- $messages{entity_decode_minimal($2)} = []; -- } --} -- --sub type_scheme { -- my ($line, $i, $state, $str, $trcomment, $char); -- for $line (split(/\n/, $input)) { -- $i = 0; -- $state = 0; # 0 - nothing, 1 - string, 2 - translatable string -- while ($i < length($line)) { -- if (substr($line,$i,1) eq "\"") { -- if ($state == 2) { -- $comments{$str} = $trcomment if ($trcomment); -- $messages{$str} = []; -- $str = ''; -- $state = 0; $trcomment = ""; -- } elsif ($state == 1) { -- $str = ''; -- $state = 0; $trcomment = ""; -- } else { -- $state = 1; -- $str = ''; -- if ($i>0 && substr($line,$i-1,1) eq '_') { -- $state = 2; -- } -- } -- } elsif (!$state) { -- if (substr($line,$i,1) eq ";") { -- $trcomment = substr($line,$i+1); -- $trcomment =~ s/^;*\s*//; -- $i = length($line); -- } elsif ($trcomment && substr($line,$i,1) !~ /\s|\(|\)|_/) { -- $trcomment = ""; -- } -- } else { -- if (substr($line,$i,1) eq "\\") { -- $char = substr($line,$i+1,1); -- if ($char ne "\"" && $char ne "\\") { -- $str = $str . "\\"; -- } -- $i++; -- } -- $str = $str . substr($line,$i,1); -- } -- $i++; -- } -- } --} -- --sub msg_write { -- my @msgids; -- if (%count) -- { -- @msgids = sort { $count{$a} <=> $count{$b} } keys %count; -- } -- else -- { -- @msgids = sort keys %messages; -- } -- for my $message (@msgids) -- { -- my $offsetlines = 1; -- $offsetlines++ if $message =~ /%/; -- if (defined ($comments{$message})) -- { -- while ($comments{$message} =~ m/\n/g) -- { -- $offsetlines++; -- } -- } -- print OUT "# ".($loc{$message} - $offsetlines). " \"$FILE\"\n" -- if defined $loc{$message}; -- print OUT "/* ".$comments{$message}." */\n" -- if defined $comments{$message}; -- print OUT "/* xgettext:no-c-format */\n" if $message =~ /%/; -- -- my @lines = split (/\n/, $message, -1); -- for (my $n = 0; $n < @lines; $n++) -- { -- if ($n == 0) -- { -- print OUT "char *s = N_(\""; -- } -- else -- { -- print OUT " \""; -- } -- -- print OUT escape($lines[$n]); -- -- if ($n < @lines - 1) -- { -- print OUT "\\n\"\n"; -- } -- else -- { -- print OUT "\");\n"; -- } -- } -- } --} -- -diff --git a/intltool-extract.in b/intltool-extract.in -new file mode 120000 -index bb6c368..340fc8d ---- /dev/null -+++ b/intltool-extract.in -@@ -0,0 +1 @@ -+/usr/share/intltool/intltool-extract.in -\ No newline at end of file -diff --git a/intltool-merge.in b/intltool-merge.in -deleted file mode 100755 -index d0535ab..2238bbd ---- a/intltool-merge.in -+++ /dev/null -@@ -1,1356 +0,0 @@ --#!@INTLTOOL_PERL@ -w --# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- -- --# --# The Intltool Message Merger --# --# Copyright (C) 2000, 2003 Free Software Foundation. --# Copyright (C) 2000, 2001 Eazel, Inc --# --# Intltool is free software; you can redistribute it and/or --# modify it under the terms of the GNU General Public License --# version 2 published by the Free Software Foundation. --# --# Intltool 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., 675 Mass Ave, Cambridge, MA 02139, USA. --# --# As a special exception to the GNU General Public License, if you --# distribute this file as part of a program that contains a --# configuration script generated by Autoconf, you may include it under --# the same distribution terms that you use for the rest of that program. --# --# Authors: Maciej Stachowiak --# Kenneth Christiansen --# Darin Adler --# --# Proper XML UTF-8'ification written by Cyrille Chepelov --# -- --## Release information --my $PROGRAM = "intltool-merge"; --my $PACKAGE = "intltool"; --my $VERSION = "0.35.0"; -- --## Loaded modules --use strict; --use Getopt::Long; --use Text::Wrap; --use File::Basename; -- --my $must_end_tag = -1; --my $last_depth = -1; --my $translation_depth = -1; --my @tag_stack = (); --my @entered_tag = (); --my @translation_strings = (); --my $leading_space = ""; -- --## Scalars used by the option stuff --my $HELP_ARG = 0; --my $VERSION_ARG = 0; --my $BA_STYLE_ARG = 0; --my $XML_STYLE_ARG = 0; --my $KEYS_STYLE_ARG = 0; --my $DESKTOP_STYLE_ARG = 0; --my $SCHEMAS_STYLE_ARG = 0; --my $RFC822DEB_STYLE_ARG = 0; --my $QUIET_ARG = 0; --my $PASS_THROUGH_ARG = 0; --my $UTF8_ARG = 0; --my $MULTIPLE_OUTPUT = 0; --my $cache_file; -- --## Handle options --GetOptions --( -- "help" => \$HELP_ARG, -- "version" => \$VERSION_ARG, -- "quiet|q" => \$QUIET_ARG, -- "oaf-style|o" => \$BA_STYLE_ARG, ## for compatibility -- "ba-style|b" => \$BA_STYLE_ARG, -- "xml-style|x" => \$XML_STYLE_ARG, -- "keys-style|k" => \$KEYS_STYLE_ARG, -- "desktop-style|d" => \$DESKTOP_STYLE_ARG, -- "schemas-style|s" => \$SCHEMAS_STYLE_ARG, -- "rfc822deb-style|r" => \$RFC822DEB_STYLE_ARG, -- "pass-through|p" => \$PASS_THROUGH_ARG, -- "utf8|u" => \$UTF8_ARG, -- "multiple-output|m" => \$MULTIPLE_OUTPUT, -- "cache|c=s" => \$cache_file -- ) or &error; -- --my $PO_DIR; --my $FILE; --my $OUTFILE; -- --my %po_files_by_lang = (); --my %translations = (); --my $iconv = $ENV{"ICONV"} || $ENV{"INTLTOOL_ICONV"} || "@INTLTOOL_ICONV@"; --my $devnull = ($^O eq 'MSWin32' ? 'NUL:' : '/dev/null'); -- --# Use this instead of \w for XML files to handle more possible characters. --my $w = "[-A-Za-z0-9._:]"; -- --# XML quoted string contents --my $q = "[^\\\"]*"; -- --## Check for options. -- --if ($VERSION_ARG) --{ -- &print_version; --} --elsif ($HELP_ARG) --{ -- &print_help; --} --elsif ($BA_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &ba_merge_translations; -- &finalize; --} --elsif ($XML_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &xml_merge_output; -- &finalize; --} --elsif ($KEYS_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &keys_merge_translations; -- &finalize; --} --elsif ($DESKTOP_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &desktop_merge_translations; -- &finalize; --} --elsif ($SCHEMAS_STYLE_ARG && @ARGV > 2) --{ -- &utf8_sanity_check; -- &preparation; -- &print_message; -- &schemas_merge_translations; -- &finalize; --} --elsif ($RFC822DEB_STYLE_ARG && @ARGV > 2) --{ -- &preparation; -- &print_message; -- &rfc822deb_merge_translations; -- &finalize; --} --else --{ -- &print_help; --} -- --exit; -- --## Sub for printing release information --sub print_version --{ -- print <<_EOF_; --${PROGRAM} (${PACKAGE}) ${VERSION} --Written by Maciej Stachowiak, Darin Adler and Kenneth Christiansen. -- --Copyright (C) 2000-2003 Free Software Foundation, Inc. --Copyright (C) 2000-2001 Eazel, Inc. --This is free software; see the source for copying conditions. There is NO --warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. --_EOF_ -- exit; --} -- --## Sub for printing usage information --sub print_help --{ -- print <<_EOF_; --Usage: ${PROGRAM} [OPTION]... PO_DIRECTORY FILENAME OUTPUT_FILE --Generates an output file that includes some localized attributes from an --untranslated source file. -- --Mandatory options: (exactly one must be specified) -- -b, --ba-style includes translations in the bonobo-activation style -- -d, --desktop-style includes translations in the desktop style -- -k, --keys-style includes translations in the keys style -- -s, --schemas-style includes translations in the schemas style -- -r, --rfc822deb-style includes translations in the RFC822 style -- -x, --xml-style includes translations in the standard xml style -- --Other options: -- -u, --utf8 convert all strings to UTF-8 before merging -- (default for everything except RFC822 style) -- -p, --pass-through deprecated, does nothing and issues a warning -- -m, --multiple-output output one localized file per locale, instead of -- a single file containing all localized elements -- -c, --cache=FILE specify cache file name -- (usually \$top_builddir/po/.intltool-merge-cache) -- -q, --quiet suppress most messages -- --help display this help and exit -- --version output version information and exit -- --Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE") --or send email to . --_EOF_ -- exit; --} -- -- --## Sub for printing error messages --sub print_error --{ -- print STDERR "Try `${PROGRAM} --help' for more information.\n"; -- exit; --} -- -- --sub print_message --{ -- print "Merging translations into $OUTFILE.\n" unless $QUIET_ARG; --} -- -- --sub preparation --{ -- $PO_DIR = $ARGV[0]; -- $FILE = $ARGV[1]; -- $OUTFILE = $ARGV[2]; -- -- &gather_po_files; -- &get_translation_database; --} -- --# General-purpose code for looking up translations in .po files -- --sub po_file2lang --{ -- my ($tmp) = @_; -- $tmp =~ s/^.*\/(.*)\.po$/$1/; -- return $tmp; --} -- --sub gather_po_files --{ -- for my $po_file (glob "$PO_DIR/*.po") { -- $po_files_by_lang{po_file2lang($po_file)} = $po_file; -- } --} -- --sub get_local_charset --{ -- my ($encoding) = @_; -- my $alias_file = $ENV{"G_CHARSET_ALIAS"} || "@INTLTOOL_LIBDIR@/charset.alias"; -- -- # seek character encoding aliases in charset.alias (glib) -- -- if (open CHARSET_ALIAS, $alias_file) -- { -- while () -- { -- next if /^\#/; -- return $1 if (/^\s*([-._a-zA-Z0-9]+)\s+$encoding\b/i) -- } -- -- close CHARSET_ALIAS; -- } -- -- # if not found, return input string -- -- return $encoding; --} -- --sub get_po_encoding --{ -- my ($in_po_file) = @_; -- my $encoding = ""; -- -- open IN_PO_FILE, $in_po_file or die; -- while () -- { -- ## example: "Content-Type: text/plain; charset=ISO-8859-1\n" -- if (/Content-Type\:.*charset=([-a-zA-Z0-9]+)\\n/) -- { -- $encoding = $1; -- last; -- } -- } -- close IN_PO_FILE; -- -- if (!$encoding) -- { -- print STDERR "Warning: no encoding found in $in_po_file. Assuming ISO-8859-1\n" unless $QUIET_ARG; -- $encoding = "ISO-8859-1"; -- } -- -- system ("$iconv -f $encoding -t UTF-8 <$devnull 2>$devnull"); -- if ($?) { -- $encoding = get_local_charset($encoding); -- } -- -- return $encoding --} -- --sub utf8_sanity_check --{ -- print STDERR "Warning: option --pass-through has been removed.\n" if $PASS_THROUGH_ARG; -- $UTF8_ARG = 1; --} -- --sub get_translation_database --{ -- if ($cache_file) { -- &get_cached_translation_database; -- } else { -- &create_translation_database; -- } --} -- --sub get_newest_po_age --{ -- my $newest_age; -- -- foreach my $file (values %po_files_by_lang) -- { -- my $file_age = -M $file; -- $newest_age = $file_age if !$newest_age || $file_age < $newest_age; -- } -- -- $newest_age = 0 if !$newest_age; -- -- return $newest_age; --} -- --sub create_cache --{ -- print "Generating and caching the translation database\n" unless $QUIET_ARG; -- -- &create_translation_database; -- -- open CACHE, ">$cache_file" || die; -- print CACHE join "\x01", %translations; -- close CACHE; --} -- --sub load_cache --{ -- print "Found cached translation database\n" unless $QUIET_ARG; -- -- my $contents; -- open CACHE, "<$cache_file" || die; -- { -- local $/; -- $contents = ; -- } -- close CACHE; -- %translations = split "\x01", $contents; --} -- --sub get_cached_translation_database --{ -- my $cache_file_age = -M $cache_file; -- if (defined $cache_file_age) -- { -- if ($cache_file_age <= &get_newest_po_age) -- { -- &load_cache; -- return; -- } -- print "Found too-old cached translation database\n" unless $QUIET_ARG; -- } -- -- &create_cache; --} -- --sub create_translation_database --{ -- for my $lang (keys %po_files_by_lang) -- { -- my $po_file = $po_files_by_lang{$lang}; -- -- if ($UTF8_ARG) -- { -- my $encoding = get_po_encoding ($po_file); -- -- if (lc $encoding eq "utf-8") -- { -- open PO_FILE, "<$po_file"; -- } -- else -- { -- print "NOTICE: $po_file is not in UTF-8 but $encoding, converting...\n" unless $QUIET_ARG;; -- -- open PO_FILE, "$iconv -f $encoding -t UTF-8 $po_file|"; -- } -- } -- else -- { -- open PO_FILE, "<$po_file"; -- } -- -- my $nextfuzzy = 0; -- my $inmsgid = 0; -- my $inmsgstr = 0; -- my $msgid = ""; -- my $msgstr = ""; -- -- while () -- { -- $nextfuzzy = 1 if /^#, fuzzy/; -- -- if (/^msgid "((\\.|[^\\])*)"/ ) -- { -- $translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr; -- $msgid = ""; -- $msgstr = ""; -- -- if ($nextfuzzy) { -- $inmsgid = 0; -- } else { -- $msgid = unescape_po_string($1); -- $inmsgid = 1; -- } -- $inmsgstr = 0; -- $nextfuzzy = 0; -- } -- -- if (/^msgstr "((\\.|[^\\])*)"/) -- { -- $msgstr = unescape_po_string($1); -- $inmsgstr = 1; -- $inmsgid = 0; -- } -- -- if (/^"((\\.|[^\\])*)"/) -- { -- $msgid .= unescape_po_string($1) if $inmsgid; -- $msgstr .= unescape_po_string($1) if $inmsgstr; -- } -- } -- $translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr; -- } --} -- --sub finalize --{ --} -- --sub unescape_one_sequence --{ -- my ($sequence) = @_; -- -- return "\\" if $sequence eq "\\\\"; -- return "\"" if $sequence eq "\\\""; -- return "\n" if $sequence eq "\\n"; -- return "\r" if $sequence eq "\\r"; -- return "\t" if $sequence eq "\\t"; -- return "\b" if $sequence eq "\\b"; -- return "\f" if $sequence eq "\\f"; -- return "\a" if $sequence eq "\\a"; -- return chr(11) if $sequence eq "\\v"; # vertical tab, see ascii(7) -- -- return chr(hex($1)) if ($sequence =~ /\\x([0-9a-fA-F]{2})/); -- return chr(oct($1)) if ($sequence =~ /\\([0-7]{3})/); -- -- # FIXME: Is \0 supported as well? Kenneth and Rodney don't want it, see bug #48489 -- -- return $sequence; --} -- --sub unescape_po_string --{ -- my ($string) = @_; -- -- $string =~ s/(\\x[0-9a-fA-F]{2}|\\[0-7]{3}|\\.)/unescape_one_sequence($1)/eg; -- -- return $string; --} -- --## NOTE: deal with < - < but not > - > because it seems its ok to have --## > in the entity. For further info please look at #84738. --sub entity_decode --{ -- local ($_) = @_; -- -- s/'/'/g; # ' -- s/"/"/g; # " -- s/&/&/g; -- s/</; -- close INPUT; -- } -- -- open OUTPUT, ">$OUTFILE" or die "can't open $OUTFILE: $!"; -- # Binmode so that selftest works ok if using a native Win32 Perl... -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- while ($source =~ s|^(.*?)([ \t]*<\s*$w+\s+($w+\s*=\s*"$q"\s*)+/?>)([ \t]*\n)?||s) -- { -- print OUTPUT $1; -- -- my $node = $2 . "\n"; -- -- my @strings = (); -- $_ = $node; -- while (s/(\s)_($w+\s*=\s*"($q)")/$1$2/s) { -- push @strings, entity_decode($3); -- } -- print OUTPUT; -- -- my %langs; -- for my $string (@strings) -- { -- for my $lang (keys %po_files_by_lang) -- { -- $langs{$lang} = 1 if $translations{$lang, $string}; -- } -- } -- -- for my $lang (sort keys %langs) -- { -- $_ = $node; -- s/(\sname\s*=\s*)"($q)"/$1"$2-$lang"/s; -- s/(\s)_($w+\s*=\s*")($q)"/$1 . $2 . entity_encoded_translation($lang, $3) . '"'/seg; -- print OUTPUT; -- } -- } -- -- print OUTPUT $source; -- -- close OUTPUT; --} -- -- --## XML (non-bonobo-activation) merge code -- -- --# Process tag attributes --# Only parameter is a HASH containing attributes -> values mapping --sub getAttributeString --{ -- my $sub = shift; -- my $do_translate = shift || 0; -- my $language = shift || ""; -- my $result = ""; -- my $translate = shift; -- foreach my $e (reverse(sort(keys %{ $sub }))) { -- my $key = $e; -- my $string = $sub->{$e}; -- my $quote = '"'; -- -- $string =~ s/^[\s]+//; -- $string =~ s/[\s]+$//; -- -- if ($string =~ /^'.*'$/) -- { -- $quote = "'"; -- } -- $string =~ s/^['"]//g; -- $string =~ s/['"]$//g; -- -- if ($do_translate && $key =~ /^_/) { -- $key =~ s|^_||g; -- if ($language) { -- # Handle translation -- my $decode_string = entity_decode($string); -- my $translation = $translations{$language, $decode_string}; -- if ($translation) { -- $translation = entity_encode($translation); -- $string = $translation; -- } -- $$translate = 2; -- } else { -- $$translate = 2 if ($translate && (!$$translate)); # watch not to "overwrite" $translate -- } -- } -- -- $result .= " $key=$quote$string$quote"; -- } -- return $result; --} -- --# Returns a translatable string from XML node, it works on contents of every node in XML::Parser tree --sub getXMLstring --{ -- my $ref = shift; -- my $spacepreserve = shift || 0; -- my @list = @{ $ref }; -- my $result = ""; -- -- my $count = scalar(@list); -- my $attrs = $list[0]; -- my $index = 1; -- -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); -- -- while ($index < $count) { -- my $type = $list[$index]; -- my $content = $list[$index+1]; -- if (! $type ) { -- # We've got CDATA -- if ($content) { -- # lets strip the whitespace here, and *ONLY* here -- $content =~ s/\s+/ /gs if (!$spacepreserve); -- $result .= $content; -- } -- } elsif ( "$type" ne "1" ) { -- # We've got another element -- $result .= "<$type"; -- $result .= getAttributeString(@{$content}[0], 0); # no nested translatable elements -- if ($content) { -- my $subresult = getXMLstring($content, $spacepreserve); -- if ($subresult) { -- $result .= ">".$subresult . ""; -- } else { -- $result .= "/>"; -- } -- } else { -- $result .= "/>"; -- } -- } -- $index += 2; -- } -- return $result; --} -- --# Translate list of nodes if necessary --sub translate_subnodes --{ -- my $fh = shift; -- my $content = shift; -- my $language = shift || ""; -- my $singlelang = shift || 0; -- my $spacepreserve = shift || 0; -- -- my @nodes = @{ $content }; -- -- my $count = scalar(@nodes); -- my $index = 0; -- while ($index < $count) { -- my $type = $nodes[$index]; -- my $rest = $nodes[$index+1]; -- if ($singlelang) { -- my $oldMO = $MULTIPLE_OUTPUT; -- $MULTIPLE_OUTPUT = 1; -- traverse($fh, $type, $rest, $language, $spacepreserve); -- $MULTIPLE_OUTPUT = $oldMO; -- } else { -- traverse($fh, $type, $rest, $language, $spacepreserve); -- } -- $index += 2; -- } --} -- --sub isWellFormedXmlFragment --{ -- my $ret = eval 'require XML::Parser'; -- if(!$ret) { -- die "You must have XML::Parser installed to run $0\n\n"; -- } -- -- my $fragment = shift; -- return 0 if (!$fragment); -- -- $fragment = "$fragment"; -- my $xp = new XML::Parser(Style => 'Tree'); -- my $tree = 0; -- eval { $tree = $xp->parse($fragment); }; -- return $tree; --} -- --sub traverse --{ -- my $fh = shift; -- my $nodename = shift; -- my $content = shift; -- my $language = shift || ""; -- my $spacepreserve = shift || 0; -- -- if (!$nodename) { -- if ($content =~ /^[\s]*$/) { -- $leading_space .= $content; -- } -- print $fh $content; -- } else { -- # element -- my @all = @{ $content }; -- my $attrs = shift @all; -- my $translate = 0; -- my $outattr = getAttributeString($attrs, 1, $language, \$translate); -- -- if ($nodename =~ /^_/) { -- $translate = 1; -- $nodename =~ s/^_//; -- } -- my $lookup = ''; -- -- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- -- print $fh "<$nodename", $outattr; -- if ($translate) { -- $lookup = getXMLstring($content, $spacepreserve); -- if (!$spacepreserve) { -- $lookup =~ s/^\s+//s; -- $lookup =~ s/\s+$//s; -- } -- -- if ($lookup || $translate == 2) { -- my $translation = $translations{$language, $lookup} if isWellFormedXmlFragment($translations{$language, $lookup}); -- if ($MULTIPLE_OUTPUT && ($translation || $translate == 2)) { -- $translation = $lookup if (!$translation); -- print $fh " xml:lang=\"", $language, "\"" if $language; -- print $fh ">"; -- if ($translate == 2) { -- translate_subnodes($fh, \@all, $language, 1, $spacepreserve); -- } else { -- print $fh $translation; -- } -- print $fh ""; -- -- return; # this means there will be no same translation with xml:lang="$language"... -- # if we want them both, just remove this "return" -- } else { -- print $fh ">"; -- if ($translate == 2) { -- translate_subnodes($fh, \@all, $language, 1, $spacepreserve); -- } else { -- print $fh $lookup; -- } -- print $fh ""; -- } -- } else { -- print $fh "/>"; -- } -- -- for my $lang (sort keys %po_files_by_lang) { -- if ($MULTIPLE_OUTPUT && $lang ne "$language") { -- next; -- } -- if ($lang) { -- # Handle translation -- # -- my $translate = 0; -- my $localattrs = getAttributeString($attrs, 1, $lang, \$translate); -- my $translation = $translations{$lang, $lookup} if isWellFormedXmlFragment($translations{$lang, $lookup}); -- if ($translate && !$translation) { -- $translation = $lookup; -- } -- -- if ($translation || $translate) { -- print $fh "\n"; -- $leading_space =~ s/.*\n//g; -- print $fh $leading_space; -- print $fh "<", $nodename, " xml:lang=\"", $lang, "\"", $localattrs, ">"; -- if ($translate == 2) { -- translate_subnodes($fh, \@all, $lang, 1, $spacepreserve); -- } else { -- print $fh $translation; -- } -- print $fh ""; -- } -- } -- } -- -- } else { -- my $count = scalar(@all); -- if ($count > 0) { -- print $fh ">"; -- my $index = 0; -- while ($index < $count) { -- my $type = $all[$index]; -- my $rest = $all[$index+1]; -- traverse($fh, $type, $rest, $language, $spacepreserve); -- $index += 2; -- } -- print $fh ""; -- } else { -- print $fh "/>"; -- } -- } -- } --} -- --sub intltool_tree_comment --{ -- my $expat = shift; -- my $data = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- push @$clist, 1 => $data; --} -- --sub intltool_tree_cdatastart --{ -- my $expat = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- push @$clist, 0 => $expat->original_string(); --} -- --sub intltool_tree_cdataend --{ -- my $expat = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- $clist->[$pos] .= $expat->original_string(); --} -- --sub intltool_tree_char --{ -- my $expat = shift; -- my $text = shift; -- my $clist = $expat->{Curlist}; -- my $pos = $#$clist; -- -- # Use original_string so that we retain escaped entities -- # in CDATA sections. -- # -- if ($pos > 0 and $clist->[$pos - 1] eq '0') { -- $clist->[$pos] .= $expat->original_string(); -- } else { -- push @$clist, 0 => $expat->original_string(); -- } --} -- --sub intltool_tree_start --{ -- my $expat = shift; -- my $tag = shift; -- my @origlist = (); -- -- # Use original_string so that we retain escaped entities -- # in attribute values. We must convert the string to an -- # @origlist array to conform to the structure of the Tree -- # Style. -- # -- my @original_array = split /\x/, $expat->original_string(); -- my $source = $expat->original_string(); -- -- # Remove leading tag. -- # -- $source =~ s|^\s*<\s*(\S+)||s; -- -- # Grab attribute key/value pairs and push onto @origlist array. -- # -- while ($source) -- { -- if ($source =~ /^\s*([\w:-]+)\s*[=]\s*["]/) -- { -- $source =~ s|^\s*([\w:-]+)\s*[=]\s*["]([^"]*)["]||s; -- push @origlist, $1; -- push @origlist, '"' . $2 . '"'; -- } -- elsif ($source =~ /^\s*([\w:-]+)\s*[=]\s*[']/) -- { -- $source =~ s|^\s*([\w:-]+)\s*[=]\s*[']([^']*)[']||s; -- push @origlist, $1; -- push @origlist, "'" . $2 . "'"; -- } -- else -- { -- last; -- } -- } -- -- my $ol = [ { @origlist } ]; -- -- push @{ $expat->{Lists} }, $expat->{Curlist}; -- push @{ $expat->{Curlist} }, $tag => $ol; -- $expat->{Curlist} = $ol; --} -- --sub readXml --{ -- my $filename = shift || return; -- if(!-f $filename) { -- die "ERROR Cannot find filename: $filename\n"; -- } -- -- my $ret = eval 'require XML::Parser'; -- if(!$ret) { -- die "You must have XML::Parser installed to run $0\n\n"; -- } -- my $xp = new XML::Parser(Style => 'Tree'); -- $xp->setHandlers(Char => \&intltool_tree_char); -- $xp->setHandlers(Start => \&intltool_tree_start); -- $xp->setHandlers(CdataStart => \&intltool_tree_cdatastart); -- $xp->setHandlers(CdataEnd => \&intltool_tree_cdataend); -- my $tree = $xp->parsefile($filename); -- --# Hello thereHowdydo --# would be: --# [foo, [{}, head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]], bar, [{}, --# 0, "Howdy", ref, [{}]], 0, "do" ] ] -- -- return $tree; --} -- --sub print_header --{ -- my $infile = shift; -- my $fh = shift; -- my $source; -- -- if(!-f $infile) { -- die "ERROR Cannot find filename: $infile\n"; -- } -- -- print $fh qq{\n}; -- { -- local $/; -- open DOCINPUT, "<${FILE}" or die; -- $source = ; -- close DOCINPUT; -- } -- if ($source =~ /()/s) -- { -- print $fh "$1\n"; -- } -- elsif ($source =~ /(]*>)/s) -- { -- print $fh "$1\n"; -- } --} -- --sub parseTree --{ -- my $fh = shift; -- my $ref = shift; -- my $language = shift || ""; -- -- my $name = shift @{ $ref }; -- my $cont = shift @{ $ref }; -- -- while (!$name || "$name" eq "1") { -- $name = shift @{ $ref }; -- $cont = shift @{ $ref }; -- } -- -- my $spacepreserve = 0; -- my $attrs = @{$cont}[0]; -- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); -- -- traverse($fh, $name, $cont, $language, $spacepreserve); --} -- --sub xml_merge_output --{ -- my $source; -- -- if ($MULTIPLE_OUTPUT) { -- for my $lang (sort keys %po_files_by_lang) { -- if ( ! -e $lang ) { -- mkdir $lang or die "Cannot create subdirectory $lang: $!\n"; -- } -- open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n"; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- my $tree = readXml($FILE); -- print_header($FILE, \*OUTPUT); -- parseTree(\*OUTPUT, $tree, $lang); -- close OUTPUT; -- print "CREATED $lang/$OUTFILE\n" unless $QUIET_ARG; -- } -- } -- open OUTPUT, ">$OUTFILE" or die "Cannot open $OUTFILE: $!\n"; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- my $tree = readXml($FILE); -- print_header($FILE, \*OUTPUT); -- parseTree(\*OUTPUT, $tree); -- close OUTPUT; -- print "CREATED $OUTFILE\n" unless $QUIET_ARG; --} -- --sub keys_merge_translations --{ -- open INPUT, "<${FILE}" or die; -- open OUTPUT, ">${OUTFILE}" or die; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- while () -- { -- if (s/^(\s*)_(\w+=(.*))/$1$2/) -- { -- my $string = $3; -- -- print OUTPUT; -- -- my $non_translated_line = $_; -- -- for my $lang (sort keys %po_files_by_lang) -- { -- my $translation = $translations{$lang, $string}; -- next if !$translation; -- -- $_ = $non_translated_line; -- s/(\w+)=.*/[$lang]$1=$translation/; -- print OUTPUT; -- } -- } -- else -- { -- print OUTPUT; -- } -- } -- -- close OUTPUT; -- close INPUT; --} -- --sub desktop_merge_translations --{ -- open INPUT, "<${FILE}" or die; -- open OUTPUT, ">${OUTFILE}" or die; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- while () -- { -- if (s/^(\s*)_(\w+=(.*))/$1$2/) -- { -- my $string = $3; -- -- print OUTPUT; -- -- my $non_translated_line = $_; -- -- for my $lang (sort keys %po_files_by_lang) -- { -- my $translation = $translations{$lang, $string}; -- next if !$translation; -- -- $_ = $non_translated_line; -- s/(\w+)=.*/${1}[$lang]=$translation/; -- print OUTPUT; -- } -- } -- else -- { -- print OUTPUT; -- } -- } -- -- close OUTPUT; -- close INPUT; --} -- --sub schemas_merge_translations --{ -- my $source; -- -- { -- local $/; # slurp mode -- open INPUT, "<$FILE" or die "can't open $FILE: $!"; -- $source = ; -- close INPUT; -- } -- -- open OUTPUT, ">$OUTFILE" or die; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- # FIXME: support attribute translations -- -- # Empty nodes never need translation, so unmark all of them. -- # For example, <_foo/> is just replaced by . -- $source =~ s|<\s*_($w+)\s*/>|<$1/>|g; -- -- while ($source =~ s/ -- (.*?) -- (\s+)((\s*) -- (\s*(?:\s*)?(.*?)\s*<\/default>)?(\s*) -- (\s*(?:\s*)?(.*?)\s*<\/short>)?(\s*) -- (\s*(?:\s*)?(.*?)\s*<\/long>)?(\s*) -- <\/locale>) -- //sx) -- { -- print OUTPUT $1; -- -- my $locale_start_spaces = $2 ? $2 : ''; -- my $default_spaces = $4 ? $4 : ''; -- my $short_spaces = $7 ? $7 : ''; -- my $long_spaces = $10 ? $10 : ''; -- my $locale_end_spaces = $13 ? $13 : ''; -- my $c_default_block = $3 ? $3 : ''; -- my $default_string = $6 ? $6 : ''; -- my $short_string = $9 ? $9 : ''; -- my $long_string = $12 ? $12 : ''; -- -- print OUTPUT "$locale_start_spaces$c_default_block"; -- -- $default_string =~ s/\s+/ /g; -- $default_string = entity_decode($default_string); -- $short_string =~ s/\s+/ /g; -- $short_string = entity_decode($short_string); -- $long_string =~ s/\s+/ /g; -- $long_string = entity_decode($long_string); -- -- for my $lang (sort keys %po_files_by_lang) -- { -- my $default_translation = $translations{$lang, $default_string}; -- my $short_translation = $translations{$lang, $short_string}; -- my $long_translation = $translations{$lang, $long_string}; -- -- next if (!$default_translation && !$short_translation && -- !$long_translation); -- -- print OUTPUT "\n$locale_start_spaces"; -- -- print OUTPUT "$default_spaces"; -- -- if ($default_translation) -- { -- $default_translation = entity_encode($default_translation); -- print OUTPUT "$default_translation"; -- } -- -- print OUTPUT "$short_spaces"; -- -- if ($short_translation) -- { -- $short_translation = entity_encode($short_translation); -- print OUTPUT "$short_translation"; -- } -- -- print OUTPUT "$long_spaces"; -- -- if ($long_translation) -- { -- $long_translation = entity_encode($long_translation); -- print OUTPUT "$long_translation"; -- } -- -- print OUTPUT "$locale_end_spaces"; -- } -- } -- -- print OUTPUT $source; -- -- close OUTPUT; --} -- --sub rfc822deb_merge_translations --{ -- my %encodings = (); -- for my $lang (keys %po_files_by_lang) { -- $encodings{$lang} = ($UTF8_ARG ? 'UTF-8' : get_po_encoding($po_files_by_lang{$lang})); -- } -- -- my $source; -- -- $Text::Wrap::huge = 'overflow'; -- $Text::Wrap::break = qr/\n|\s(?=\S)/; -- -- { -- local $/; # slurp mode -- open INPUT, "<$FILE" or die "can't open $FILE: $!"; -- $source = ; -- close INPUT; -- } -- -- open OUTPUT, ">${OUTFILE}" or die; -- binmode (OUTPUT) if $^O eq 'MSWin32'; -- -- while ($source =~ /(^|\n+)(_*)([^:\s]+)(:[ \t]*)(.*?)(?=\n[\S\n]|$)/sg) -- { -- my $sep = $1; -- my $non_translated_line = $3.$4; -- my $string = $5; -- my $underscore = length($2); -- next if $underscore eq 0 && $non_translated_line =~ /^#/; -- # Remove [] dummy strings -- my $stripped = $string; -- $stripped =~ s/\[\s[^\[\]]*\],/,/g if $underscore eq 2; -- $stripped =~ s/\[\s[^\[\]]*\]$//; -- $non_translated_line .= $stripped; -- -- print OUTPUT $sep.$non_translated_line; -- -- if ($underscore) -- { -- my @str_list = rfc822deb_split($underscore, $string); -- -- for my $lang (sort keys %po_files_by_lang) -- { -- my $is_translated = 1; -- my $str_translated = ''; -- my $first = 1; -- -- for my $str (@str_list) -- { -- my $translation = $translations{$lang, $str}; -- -- if (!$translation) -- { -- $is_translated = 0; -- last; -- } -- -- # $translation may also contain [] dummy -- # strings, mostly to indicate an empty string -- $translation =~ s/\[\s[^\[\]]*\]$//; -- -- if ($first) -- { -- if ($underscore eq 2) -- { -- $str_translated .= $translation; -- } -- else -- { -- $str_translated .= -- Text::Tabs::expand($translation) . -- "\n"; -- } -- } -- else -- { -- if ($underscore eq 2) -- { -- $str_translated .= ', ' . $translation; -- } -- else -- { -- $str_translated .= Text::Tabs::expand( -- Text::Wrap::wrap(' ', ' ', $translation)) . -- "\n .\n"; -- } -- } -- $first = 0; -- -- # To fix some problems with Text::Wrap::wrap -- $str_translated =~ s/(\n )+\n/\n .\n/g; -- } -- next unless $is_translated; -- -- $str_translated =~ s/\n \.\n$//; -- $str_translated =~ s/\s+$//; -- -- $_ = $non_translated_line; -- s/^(\w+):\s*.*/$sep${1}-$lang.$encodings{$lang}: $str_translated/s; -- print OUTPUT; -- } -- } -- } -- print OUTPUT "\n"; -- -- close OUTPUT; -- close INPUT; --} -- --sub rfc822deb_split --{ -- # Debian defines a special way to deal with rfc822-style files: -- # when a value contain newlines, it consists of -- # 1. a short form (first line) -- # 2. a long description, all lines begin with a space, -- # and paragraphs are separated by a single dot on a line -- # This routine returns an array of all paragraphs, and reformat -- # them. -- # When first argument is 2, the string is a comma separated list of -- # values. -- my $type = shift; -- my $text = shift; -- $text =~ s/^[ \t]//mg; -- return (split(/, */, $text, 0)) if $type ne 1; -- return ($text) if $text !~ /\n/; -- -- $text =~ s/([^\n]*)\n//; -- my @list = ($1); -- my $str = ''; -- -- for my $line (split (/\n/, $text)) -- { -- chomp $line; -- if ($line =~ /^\.\s*$/) -- { -- # New paragraph -- $str =~ s/\s*$//; -- push(@list, $str); -- $str = ''; -- } -- elsif ($line =~ /^\s/) -- { -- # Line which must not be reformatted -- $str .= "\n" if length ($str) && $str !~ /\n$/; -- $line =~ s/\s+$//; -- $str .= $line."\n"; -- } -- else -- { -- # Continuation line, remove newline -- $str .= " " if length ($str) && $str !~ /\n$/; -- $str .= $line; -- } -- } -- -- $str =~ s/\s*$//; -- push(@list, $str) if length ($str); -- -- return @list; --} -- -diff --git a/intltool-merge.in b/intltool-merge.in -new file mode 120000 -index d0535ab..2238bbd ---- /dev/null -+++ b/intltool-merge.in -@@ -0,0 +1 @@ -+/usr/share/intltool/intltool-merge.in -\ No newline at end of file -diff --git a/intltool-update.in b/intltool-update.in -deleted file mode 100755 -index 661d8fe..0b1800f ---- a/intltool-update.in -+++ /dev/null -@@ -1,1089 +0,0 @@ --#!@INTLTOOL_PERL@ -w --# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- -- --# --# The Intltool Message Updater --# --# Copyright (C) 2000-2003 Free Software Foundation. --# --# Intltool is free software; you can redistribute it and/or --# modify it under the terms of the GNU General Public License --# version 2 published by the Free Software Foundation. --# --# Intltool 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., 675 Mass Ave, Cambridge, MA 02139, USA. --# --# As a special exception to the GNU General Public License, if you --# distribute this file as part of a program that contains a --# configuration script generated by Autoconf, you may include it under --# the same distribution terms that you use for the rest of that program. --# --# Authors: Kenneth Christiansen --# Maciej Stachowiak --# Darin Adler -- --## Release information --my $PROGRAM = "intltool-update"; --my $VERSION = "0.35.0"; --my $PACKAGE = "intltool"; -- --## Loaded modules --use strict; --use Getopt::Long; --use Cwd; --use File::Copy; --use File::Find; -- --## Scalars used by the option stuff --my $HELP_ARG = 0; --my $VERSION_ARG = 0; --my $DIST_ARG = 0; --my $POT_ARG = 0; --my $HEADERS_ARG = 0; --my $MAINTAIN_ARG = 0; --my $REPORT_ARG = 0; --my $VERBOSE = 0; --my $GETTEXT_PACKAGE = ""; --my $OUTPUT_FILE = ""; -- --my @languages; --my %varhash = (); --my %po_files_by_lang = (); -- --# Regular expressions to categorize file types. --# FIXME: Please check if the following is correct -- --my $xml_support = --"xml(?:\\.in)*|". # http://www.w3.org/XML/ (Note: .in is not required) --"ui|". # Bonobo specific - User Interface desc. files --"lang|". # ? --"glade2?(?:\\.in)*|". # Glade specific - User Interface desc. files (Note: .in is not required) --"scm(?:\\.in)*|". # ? (Note: .in is not required) --"oaf(?:\\.in)+|". # DEPRECATED: Replaces by Bonobo .server files --"etspec|". # ? --"server(?:\\.in)+|". # Bonobo specific --"sheet(?:\\.in)+|". # ? --"schemas(?:\\.in)+|". # GConf specific --"pong(?:\\.in)+|". # DEPRECATED: PONG is not used [by GNOME] any longer. --"kbd(?:\\.in)+"; # GOK specific. -- --my $ini_support = --"icon(?:\\.in)+|". # http://www.freedesktop.org/Standards/icon-theme-spec --"desktop(?:\\.in)+|". # http://www.freedesktop.org/Standards/menu-spec --"caves(?:\\.in)+|". # GNOME Games specific --"directory(?:\\.in)+|". # http://www.freedesktop.org/Standards/menu-spec --"soundlist(?:\\.in)+|". # GNOME specific --"keys(?:\\.in)+|". # GNOME Mime database specific --"theme(?:\\.in)+|". # http://www.freedesktop.org/Standards/icon-theme-spec --"service(?:\\.in)+"; # DBus specific -- --my $buildin_gettext_support = --"c|y|cs|cc|cpp|c\\+\\+|h|hh|gob|py"; -- --## Always flush buffer when printing --$| = 1; -- --## Sometimes the source tree will be rooted somewhere else. --my $SRCDIR = "."; --my $POTFILES_in; -- --$SRCDIR = $ENV{"srcdir"} if $ENV{"srcdir"}; --$POTFILES_in = "<$SRCDIR/POTFILES.in"; -- --my $devnull = ($^O eq 'MSWin32' ? 'NUL:' : '/dev/null'); -- --## Handle options --GetOptions --( -- "help" => \$HELP_ARG, -- "version" => \$VERSION_ARG, -- "dist|d" => \$DIST_ARG, -- "pot|p" => \$POT_ARG, -- "headers|s" => \$HEADERS_ARG, -- "maintain|m" => \$MAINTAIN_ARG, -- "report|r" => \$REPORT_ARG, -- "verbose|x" => \$VERBOSE, -- "gettext-package|g=s" => \$GETTEXT_PACKAGE, -- "output-file|o=s" => \$OUTPUT_FILE, -- ) or &Console_WriteError_InvalidOption; -- --&Console_Write_IntltoolHelp if $HELP_ARG; --&Console_Write_IntltoolVersion if $VERSION_ARG; -- --my $arg_count = ($DIST_ARG > 0) -- + ($POT_ARG > 0) -- + ($HEADERS_ARG > 0) -- + ($MAINTAIN_ARG > 0) -- + ($REPORT_ARG > 0); -- --&Console_Write_IntltoolHelp if $arg_count > 1; -- --# --version and --help don't require a module name --my $MODULE = $GETTEXT_PACKAGE || &FindPackageName || "unknown"; -- --if ($POT_ARG) --{ -- &GenerateHeaders; -- &GeneratePOTemplate; --} --elsif ($HEADERS_ARG) --{ -- &GenerateHeaders; --} --elsif ($MAINTAIN_ARG) --{ -- &FindLeftoutFiles; --} --elsif ($REPORT_ARG) --{ -- &GenerateHeaders; -- &GeneratePOTemplate; -- &Console_Write_CoverageReport; --} --elsif ((defined $ARGV[0]) && $ARGV[0] =~ /^[a-z]/) --{ -- my $lang = $ARGV[0]; -- -- ## Report error if the language file supplied -- ## to the command line is non-existent -- &Console_WriteError_NotExisting("$SRCDIR/$lang.po") -- if ! -s "$SRCDIR/$lang.po"; -- -- if (!$DIST_ARG) -- { -- print "Working, please wait..." if $VERBOSE; -- &GenerateHeaders; -- &GeneratePOTemplate; -- } -- &POFile_Update ($lang, $OUTPUT_FILE); -- &Console_Write_TranslationStatus ($lang, $OUTPUT_FILE); --} --else --{ -- &Console_Write_IntltoolHelp; --} -- --exit; -- --######### -- --sub Console_Write_IntltoolVersion --{ -- print <<_EOF_; --${PROGRAM} (${PACKAGE}) $VERSION --Written by Kenneth Christiansen, Maciej Stachowiak, and Darin Adler. -- --Copyright (C) 2000-2003 Free Software Foundation, Inc. --This is free software; see the source for copying conditions. There is NO --warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. --_EOF_ -- exit; --} -- --sub Console_Write_IntltoolHelp --{ -- print <<_EOF_; --Usage: ${PROGRAM} [OPTION]... LANGCODE --Updates PO template files and merge them with the translations. -- --Mode of operation (only one is allowed): -- -p, --pot generate the PO template only -- -s, --headers generate the header files in POTFILES.in -- -m, --maintain search for left out files from POTFILES.in -- -r, --report display a status report for the module -- -d, --dist merge LANGCODE.po with existing PO template -- --Extra options: -- -g, --gettext-package=NAME override PO template name, useful with --pot -- -o, --output-file=FILE write merged translation to FILE -- -x, --verbose display lots of feedback -- --help display this help and exit -- --version output version information and exit -- --Examples of use: --${PROGRAM} --pot just create a new PO template --${PROGRAM} xy create new PO template and merge xy.po with it -- --Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE") --or send email to . --_EOF_ -- exit; --} -- --sub echo_n --{ -- my $str = shift; -- my $ret = `echo "$str"`; -- -- $ret =~ s/\n$//; # do we need the "s" flag? -- -- return $ret; --} -- --sub POFile_DetermineType ($) --{ -- my $type = $_; -- my $gettext_type; -- -- my $xml_regex = "(?:" . $xml_support . ")"; -- my $ini_regex = "(?:" . $ini_support . ")"; -- my $buildin_regex = "(?:" . $buildin_gettext_support . ")"; -- -- if ($type =~ /\[type: gettext\/([^\]].*)]/) -- { -- $gettext_type=$1; -- } -- elsif ($type =~ /schemas(\.in)+$/) -- { -- $gettext_type="schemas"; -- } -- elsif ($type =~ /glade2?(\.in)*$/) -- { -- $gettext_type="glade"; -- } -- elsif ($type =~ /scm(\.in)*$/) -- { -- $gettext_type="scheme"; -- } -- elsif ($type =~ /keys(\.in)+$/) -- { -- $gettext_type="keys"; -- } -- -- # bucket types -- -- elsif ($type =~ /$xml_regex$/) -- { -- $gettext_type="xml"; -- } -- elsif ($type =~ /$ini_regex$/) -- { -- $gettext_type="ini"; -- } -- elsif ($type =~ /$buildin_regex$/) -- { -- $gettext_type="buildin"; -- } -- else -- { -- $gettext_type="unknown"; -- } -- -- return "gettext\/$gettext_type"; --} -- --sub TextFile_DetermineEncoding ($) --{ -- my $gettext_code="ASCII"; # All files are ASCII by default -- my $filetype=`file $_ | cut -d ' ' -f 2`; -- -- if ($? eq "0") -- { -- if ($filetype =~ /^(ISO|UTF)/) -- { -- chomp ($gettext_code = $filetype); -- } -- elsif ($filetype =~ /^XML/) -- { -- $gettext_code="UTF-8"; # We asume that .glade and other .xml files are UTF-8 -- } -- } -- -- return $gettext_code; --} -- --sub isNotValidMissing --{ -- my ($file) = @_; -- -- return if $file =~ /^\{arch\}\/.*$/; -- return if $file =~ /^$varhash{"PACKAGE"}-$varhash{"VERSION"}\/.*$/; --} -- --sub FindLeftoutFiles --{ -- my (@buf_i18n_plain, -- @buf_i18n_xml, -- @buf_i18n_xml_unmarked, -- @buf_i18n_ini, -- @buf_potfiles, -- @buf_potfiles_ignore, -- @buf_allfiles, -- @buf_allfiles_sorted, -- @buf_potfiles_sorted -- ); -- -- ## Search and find all translatable files -- find sub { -- push @buf_i18n_plain, "$File::Find::name" if /\.($buildin_gettext_support)$/; -- push @buf_i18n_xml, "$File::Find::name" if /\.($xml_support)$/; -- push @buf_i18n_ini, "$File::Find::name" if /\.($ini_support)$/; -- push @buf_i18n_xml_unmarked, "$File::Find::name" if /\.(schemas(\.in)+)$/; -- }, ".."; -- -- -- open POTFILES, $POTFILES_in or die "$PROGRAM: there's no POTFILES.in!\n"; -- @buf_potfiles = grep !/^(#|\s*$)/, ; -- close POTFILES; -- -- foreach (@buf_potfiles) { -- s/^\[.*]\s*//; -- } -- -- print "Searching for missing translatable files...\n" if $VERBOSE; -- -- ## Check if we should ignore some found files, when -- ## comparing with POTFILES.in -- foreach my $ignore ("POTFILES.skip", "POTFILES.ignore") -- { -- (-s $ignore) or next; -- -- if ("$ignore" eq "POTFILES.ignore") -- { -- print "The usage of POTFILES.ignore is deprecated. Please consider moving the\n". -- "content of this file to POTFILES.skip.\n"; -- } -- -- print "Found $ignore: Ignoring files...\n" if $VERBOSE; -- open FILE, "<$ignore" or die "ERROR: Failed to open $ignore!\n"; -- -- while () -- { -- push @buf_potfiles_ignore, $_ unless /^(#|\s*$)/; -- } -- close FILE; -- -- @buf_potfiles = (@buf_potfiles_ignore, @buf_potfiles); -- } -- -- foreach my $file (@buf_i18n_plain) -- { -- my $in_comment = 0; -- my $in_macro = 0; -- -- open FILE, "<$file"; -- while () -- { -- # Handle continued multi-line comment. -- if ($in_comment) -- { -- next unless s-.*\*/--; -- $in_comment = 0; -- } -- -- # Handle continued macro. -- if ($in_macro) -- { -- $in_macro = 0 unless /\\$/; -- next; -- } -- -- # Handle start of macro (or any preprocessor directive). -- if (/^\s*\#/) -- { -- $in_macro = 1 if /^([^\\]|\\.)*\\$/; -- next; -- } -- -- # Handle comments and quoted text. -- while (m-(/\*|//|\'|\")-) # \' and \" keep emacs perl mode happy -- { -- my $match = $1; -- if ($match eq "/*") -- { -- if (!s-/\*.*?\*/--) -- { -- s-/\*.*--; -- $in_comment = 1; -- } -- } -- elsif ($match eq "//") -- { -- s-//.*--; -- } -- else # ' or " -- { -- if (!s-$match([^\\]|\\.)*?$match-QUOTEDTEXT-) -- { -- warn "mismatched quotes at line $. in $file\n"; -- s-$match.*--; -- } -- } -- } -- -- if (/\.GetString ?\(QUOTEDTEXT/) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- ## Remove the first 3 chars and add newline -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- last; -- } -- -- if (/_\(QUOTEDTEXT/) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- ## Remove the first 3 chars and add newline -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- last; -- } -- } -- close FILE; -- } -- -- foreach my $file (@buf_i18n_xml) -- { -- open FILE, "<$file"; -- -- while () -- { -- # FIXME: share the pattern matching code with intltool-extract -- if (/\s_[-A-Za-z0-9._:]+\s*=\s*\"([^"]+)\"/ || /<_[^>]+>/ || /translatable=\"yes\"/) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- last; -- } -- } -- close FILE; -- } -- -- foreach my $file (@buf_i18n_ini) -- { -- open FILE, "<$file"; -- while () -- { -- if (/_(.*)=/) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- last; -- } -- } -- close FILE; -- } -- -- foreach my $file (@buf_i18n_xml_unmarked) -- { -- if (defined isNotValidMissing (unpack("x3 A*", $file))) { -- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; -- } -- } -- -- -- @buf_allfiles_sorted = sort (@buf_allfiles); -- @buf_potfiles_sorted = sort (@buf_potfiles); -- -- my %in2; -- foreach (@buf_potfiles_sorted) -- { -- $in2{$_} = 1; -- } -- -- my @result; -- -- foreach (@buf_allfiles_sorted) -- { -- if (!exists($in2{$_})) -- { -- push @result, $_ -- } -- } -- -- my @buf_potfiles_notexist; -- -- foreach (@buf_potfiles_sorted) -- { -- chomp (my $dummy = $_); -- if ("$dummy" ne "" and ! -f "../$dummy") -- { -- push @buf_potfiles_notexist, $_; -- } -- } -- -- ## Save file with information about the files missing -- ## if any, and give information about this procedure. -- if (@result + @buf_potfiles_notexist > 0) -- { -- if (@result) -- { -- print "\n" if $VERBOSE; -- unlink "missing"; -- open OUT, ">missing"; -- print OUT @result; -- close OUT; -- warn "\e[1mThe following files contain translations and are currently not in use. Please\e[0m\n". -- "\e[1mconsider adding these to the POTFILES.in file, located in the po/ directory.\e[0m\n\n"; -- print STDERR @result, "\n"; -- warn "If some of these files are left out on purpose then please add them to\n". -- "POTFILES.skip instead of POTFILES.in. A file \e[1m'missing'\e[0m containing this list\n". -- "of left out files has been written in the current directory.\n"; -- } -- if (@buf_potfiles_notexist) -- { -- unlink "notexist"; -- open OUT, ">notexist"; -- print OUT @buf_potfiles_notexist; -- close OUT; -- warn "\n" if ($VERBOSE or @result); -- warn "\e[1mThe following files do not exist anymore:\e[0m\n\n"; -- warn @buf_potfiles_notexist, "\n"; -- warn "Please remove them from POTFILES.in or POTFILES.skip. A file \e[1m'notexist'\e[0m\n". -- "containing this list of absent files has been written in the current directory.\n"; -- } -- } -- -- ## If there is nothing to complain about, notify the user -- else { -- print "\nAll files containing translations are present in POTFILES.in.\n" if $VERBOSE; -- } --} -- --sub Console_WriteError_InvalidOption --{ -- ## Handle invalid arguments -- print STDERR "Try `${PROGRAM} --help' for more information.\n"; -- exit 1; --} -- --sub GenerateHeaders --{ -- my $EXTRACT = "@INTLTOOL_EXTRACT@"; -- chomp $EXTRACT; -- -- $EXTRACT = $ENV{"INTLTOOL_EXTRACT"} if $ENV{"INTLTOOL_EXTRACT"}; -- -- ## Generate the .h header files, so we can allow glade and -- ## xml translation support -- if (! -x "$EXTRACT") -- { -- print STDERR "\n *** The intltool-extract script wasn't found!" -- ."\n *** Without it, intltool-update can not generate files.\n"; -- exit; -- } -- else -- { -- open (FILE, $POTFILES_in) or die "$PROGRAM: POTFILES.in not found.\n"; -- -- while () -- { -- chomp; -- next if /^\[\s*encoding/; -- -- ## Find xml files in POTFILES.in and generate the -- ## files with help from the extract script -- -- my $gettext_type= &POFile_DetermineType ($1); -- -- if (/\.($xml_support|$ini_support)$/ || /^\[/) -- { -- s/^\[[^\[].*]\s*//; -- -- my $filename = "../$_"; -- -- if ($VERBOSE) -- { -- system ($EXTRACT, "--update", "--srcdir=$SRCDIR", -- "--type=$gettext_type", $filename); -- } -- else -- { -- system ($EXTRACT, "--update", "--type=$gettext_type", -- "--srcdir=$SRCDIR", "--quiet", $filename); -- } -- } -- } -- close FILE; -- } --} -- --# --# Generate .pot file from POTFILES.in --# --sub GeneratePOTemplate --{ -- my $XGETTEXT = $ENV{"XGETTEXT"} || "@INTLTOOL_XGETTEXT@"; -- my $XGETTEXT_ARGS = $ENV{"XGETTEXT_ARGS"} || ''; -- chomp $XGETTEXT; -- -- if (! -x $XGETTEXT) -- { -- print STDERR " *** xgettext is not found on this system!\n". -- " *** Without it, intltool-update can not extract strings.\n"; -- exit; -- } -- -- print "Building $MODULE.pot...\n" if $VERBOSE; -- -- open INFILE, $POTFILES_in; -- unlink "POTFILES.in.temp"; -- open OUTFILE, ">POTFILES.in.temp" or die("Cannot open POTFILES.in.temp for writing"); -- -- my $gettext_support_nonascii = 0; -- -- # checks for GNU gettext >= 0.12 -- my $dummy = `$XGETTEXT --version --from-code=UTF-8 >$devnull 2>$devnull`; -- if ($? == 0) -- { -- $gettext_support_nonascii = 1; -- } -- else -- { -- # urge everybody to upgrade gettext -- print STDERR "WARNING: This version of gettext does not support extracting non-ASCII\n". -- " strings. That means you should install a version of gettext\n". -- " that supports non-ASCII strings (such as GNU gettext >= 0.12),\n". -- " or have to let non-ASCII strings untranslated. (If there is any)\n"; -- } -- -- my $encoding = "ASCII"; -- my $forced_gettext_code; -- my @temp_headers; -- my $encoding_problem_is_reported = 0; -- -- while () -- { -- next if (/^#/ or /^\s*$/); -- -- chomp; -- -- my $gettext_code; -- -- if (/^\[\s*encoding:\s*(.*)\s*\]/) -- { -- $forced_gettext_code=$1; -- } -- elsif (/\.($xml_support|$ini_support)$/ || /^\[/) -- { -- s/^\[.*]\s*//; -- print OUTFILE "../$_.h\n"; -- push @temp_headers, "../$_.h"; -- $gettext_code = &TextFile_DetermineEncoding ("../$_.h") if ($gettext_support_nonascii and not defined $forced_gettext_code); -- } -- else -- { -- if ($SRCDIR eq ".") { -- print OUTFILE "../$_\n"; -- } else { -- print OUTFILE "$SRCDIR/../$_\n"; -- } -- $gettext_code = &TextFile_DetermineEncoding ("../$_") if ($gettext_support_nonascii and not defined $forced_gettext_code); -- } -- -- next if (! $gettext_support_nonascii); -- -- if (defined $forced_gettext_code) -- { -- $encoding=$forced_gettext_code; -- } -- elsif (defined $gettext_code and "$encoding" ne "$gettext_code") -- { -- if ($encoding eq "ASCII") -- { -- $encoding=$gettext_code; -- } -- elsif ($gettext_code ne "ASCII") -- { -- # Only report once because the message is quite long -- if (! $encoding_problem_is_reported) -- { -- print STDERR "WARNING: You should use the same file encoding for all your project files,\n". -- " but $PROGRAM thinks that most of the source files are in\n". -- " $encoding encoding, while \"$_\" is (likely) in\n". -- " $gettext_code encoding. If you are sure that all translatable strings\n". -- " are in same encoding (say UTF-8), please \e[1m*prepend*\e[0m the following\n". -- " line to POTFILES.in:\n\n". -- " [encoding: UTF-8]\n\n". -- " and make sure that configure.in/ac checks for $PACKAGE >= 0.27 .\n". -- "(such warning message will only be reported once.)\n"; -- $encoding_problem_is_reported = 1; -- } -- } -- } -- } -- -- close OUTFILE; -- close INFILE; -- -- unlink "$MODULE.pot"; -- my @xgettext_argument=("$XGETTEXT", -- "--add-comments", -- "--directory\=\.", -- "--output\=$MODULE\.pot", -- "--files-from\=\.\/POTFILES\.in\.temp"); -- my $XGETTEXT_KEYWORDS = &FindPOTKeywords; -- push @xgettext_argument, $XGETTEXT_KEYWORDS; -- my $MSGID_BUGS_ADDRESS = &FindMakevarsBugAddress; -- push @xgettext_argument, "--msgid-bugs-address\=$MSGID_BUGS_ADDRESS" if $MSGID_BUGS_ADDRESS; -- push @xgettext_argument, "--from-code\=$encoding" if ($gettext_support_nonascii); -- push @xgettext_argument, $XGETTEXT_ARGS if $XGETTEXT_ARGS; -- my $xgettext_command = join ' ', @xgettext_argument; -- -- # intercept xgettext error message -- print "Running $xgettext_command\n" if $VERBOSE; -- my $xgettext_error_msg = `$xgettext_command 2>\&1`; -- my $command_failed = $?; -- -- unlink "POTFILES.in.temp"; -- -- print "Removing generated header (.h) files..." if $VERBOSE; -- unlink foreach (@temp_headers); -- print "done.\n" if $VERBOSE; -- -- if (! $command_failed) -- { -- if (! -e "$MODULE.pot") -- { -- print "None of the files in POTFILES.in contain strings marked for translation.\n" if $VERBOSE; -- } -- else -- { -- print "Wrote $MODULE.pot\n" if $VERBOSE; -- } -- } -- else -- { -- if ($xgettext_error_msg =~ /--from-code/) -- { -- # replace non-ASCII error message with a more useful one. -- print STDERR "ERROR: xgettext failed to generate PO template file because there is non-ASCII\n". -- " string marked for translation. Please make sure that all strings marked\n". -- " for translation are in uniform encoding (say UTF-8), then \e[1m*prepend*\e[0m the\n". -- " following line to POTFILES.in and rerun $PROGRAM:\n\n". -- " [encoding: UTF-8]\n\n"; -- } -- else -- { -- print STDERR "$xgettext_error_msg"; -- if (-e "$MODULE.pot") -- { -- # is this possible? -- print STDERR "ERROR: xgettext failed but still managed to generate PO template file.\n". -- " Please consult error message above if there is any.\n"; -- } -- else -- { -- print STDERR "ERROR: xgettext failed to generate PO template file. Please consult\n". -- " error message above if there is any.\n"; -- } -- } -- exit (1); -- } --} -- --sub POFile_Update --{ -- -f "$MODULE.pot" or die "$PROGRAM: $MODULE.pot does not exist.\n"; -- -- my $MSGMERGE = $ENV{"MSGMERGE"} || "@INTLTOOL_MSGMERGE@"; -- my ($lang, $outfile) = @_; -- -- print "Merging $SRCDIR/$lang.po with $MODULE.pot..." if $VERBOSE; -- -- my $infile = "$SRCDIR/$lang.po"; -- $outfile = "$SRCDIR/$lang.po" if ($outfile eq ""); -- -- # I think msgmerge won't overwrite old file if merge is not successful -- system ("$MSGMERGE", "-o", $outfile, $infile, "$MODULE.pot"); --} -- --sub Console_WriteError_NotExisting --{ -- my ($file) = @_; -- -- ## Report error if supplied language file is non-existing -- print STDERR "$PROGRAM: $file does not exist!\n"; -- print STDERR "Try '$PROGRAM --help' for more information.\n"; -- exit; --} -- --sub GatherPOFiles --{ -- my @po_files = glob ("./*.po"); -- -- @languages = map (&POFile_GetLanguage, @po_files); -- -- foreach my $lang (@languages) -- { -- $po_files_by_lang{$lang} = shift (@po_files); -- } --} -- --sub POFile_GetLanguage ($) --{ -- s/^(.*\/)?(.+)\.po$/$2/; -- return $_; --} -- --sub Console_Write_TranslationStatus --{ -- my ($lang, $output_file) = @_; -- my $MSGFMT = $ENV{"MSGFMT"} || "@INTLTOOL_MSGFMT@"; -- -- $output_file = "$SRCDIR/$lang.po" if ($output_file eq ""); -- -- system ("$MSGFMT", "-o", "$devnull", "--verbose", $output_file); --} -- --sub Console_Write_CoverageReport --{ -- my $MSGFMT = $ENV{"MSGFMT"} || "@INTLTOOL_MSGFMT@"; -- -- &GatherPOFiles; -- -- foreach my $lang (@languages) -- { -- print "$lang: "; -- &POFile_Update ($lang, ""); -- } -- -- print "\n\n * Current translation support in $MODULE \n\n"; -- -- foreach my $lang (@languages) -- { -- print "$lang: "; -- system ("$MSGFMT", "-o", "$devnull", "--verbose", "$SRCDIR/$lang.po"); -- } --} -- --sub SubstituteVariable --{ -- my ($str) = @_; -- -- # always need to rewind file whenever it has been accessed -- seek (CONF, 0, 0); -- -- # cache each variable. varhash is global to we can add -- # variables elsewhere. -- while () -- { -- if (/^(\w+)=(.*)$/) -- { -- ($varhash{$1} = $2) =~ s/^["'](.*)["']$/$1/; -- } -- } -- -- if ($str =~ /^(.*)\${?([A-Z_]+)}?(.*)$/) -- { -- my $rest = $3; -- my $untouched = $1; -- my $sub = ""; -- # Ignore recursive definitions of variables -- $sub = $varhash{$2} if defined $varhash{$2} and $varhash{$2} !~ /\${?$2}?/; -- -- return SubstituteVariable ("$untouched$sub$rest"); -- } -- -- # We're using Perl backticks ` and "echo -n" here in order to -- # expand any shell escapes (such as backticks themselves) in every variable -- return echo_n ($str); --} -- --sub CONF_Handle_Open --{ -- my $base_dirname = getcwd(); -- $base_dirname =~ s@.*/@@; -- -- my ($conf_in, $src_dir); -- -- if ($base_dirname =~ /^po(-.+)?$/) -- { -- if (-f "Makevars") -- { -- my $makefile_source; -- -- local (*IN); -- open (IN, ") -- { -- if (/^top_builddir[ \t]*=/) -- { -- $src_dir = $_; -- $src_dir =~ s/^top_builddir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/; -- -- chomp $src_dir; -- if (-f "$src_dir" . "/configure.ac") { -- $conf_in = "$src_dir" . "/configure.ac" . "\n"; -- } else { -- $conf_in = "$src_dir" . "/configure.in" . "\n"; -- } -- last; -- } -- } -- close IN; -- -- $conf_in || die "Cannot find top_builddir in Makevars."; -- } -- elsif (-f "../configure.ac") -- { -- $conf_in = "../configure.ac"; -- } -- elsif (-f "../configure.in") -- { -- $conf_in = "../configure.in"; -- } -- else -- { -- my $makefile_source; -- -- local (*IN); -- open (IN, ") -- { -- if (/^top_srcdir[ \t]*=/) -- { -- $src_dir = $_; -- $src_dir =~ s/^top_srcdir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/; -- -- chomp $src_dir; -- $conf_in = "$src_dir" . "/configure.in" . "\n"; -- -- last; -- } -- } -- close IN; -- -- $conf_in || die "Cannot find top_srcdir in Makefile."; -- } -- -- open (CONF, "<$conf_in"); -- } -- else -- { -- print STDERR "$PROGRAM: Unable to proceed.\n" . -- "Make sure to run this script inside the po directory.\n"; -- exit; -- } --} -- --sub FindPackageName --{ -- my $version; -- my $domain = &FindMakevarsDomain; -- my $name = $domain || "untitled"; -- -- &CONF_Handle_Open; -- -- my $conf_source; { -- local (*IN); -- open (IN, "<&CONF") || return $name; -- seek (IN, 0, 0); -- local $/; # slurp mode -- $conf_source = ; -- close IN; -- } -- -- # priority for getting package name: -- # 1. GETTEXT_PACKAGE -- # 2. first argument of AC_INIT (with >= 2 arguments) -- # 3. first argument of AM_INIT_AUTOMAKE (with >= 2 argument) -- -- # /^AM_INIT_AUTOMAKE\([\s\[]*([^,\)\s\]]+)/m -- # the \s makes this not work, why? -- if ($conf_source =~ /^AM_INIT_AUTOMAKE\(([^,\)]+),([^,\)]+)/m) -- { -- ($name, $version) = ($1, $2); -- $name =~ s/[\[\]\s]//g; -- $version =~ s/[\[\]\s]//g; -- $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/); -- $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/); -- $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/); -- $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/); -- } -- -- if ($conf_source =~ /^AC_INIT\(([^,\)]+),([^,\)]+)/m) -- { -- ($name, $version) = ($1, $2); -- $name =~ s/[\[\]\s]//g; -- $version =~ s/[\[\]\s]//g; -- $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/); -- $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/); -- $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/); -- $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/); -- } -- -- # \s makes this not work, why? -- $name = $1 if $conf_source =~ /^GETTEXT_PACKAGE=\[?([^\n\]]+)/m; -- -- # m4 macros AC_PACKAGE_NAME, AC_PACKAGE_VERSION etc. have same value -- # as corresponding $PACKAGE_NAME, $PACKAGE_VERSION etc. shell variables. -- $name =~ s/\bAC_PACKAGE_/\$PACKAGE_/g; -- -- $name = $domain if $domain; -- -- $name = SubstituteVariable ($name); -- $name =~ s/^["'](.*)["']$/$1/; -- -- return $name if $name; --} -- -- --sub FindPOTKeywords --{ -- -- my $keywords = "--keyword\=\_ --keyword\=N\_ --keyword\=U\_ --keyword\=Q\_"; -- my $varname = "XGETTEXT_OPTIONS"; -- my $make_source; { -- local (*IN); -- open (IN, "; -- close IN; -- } -- -- $keywords = $1 if $make_source =~ /^$varname[ ]*=\[?([^\n\]]+)/m; -- -- return $keywords; --} -- --sub FindMakevarsDomain --{ -- -- my $domain = ""; -- my $makevars_source; { -- local (*IN); -- open (IN, "; -- close IN; -- } -- -- $domain = $1 if $makevars_source =~ /^DOMAIN[ ]*=\[?([^\n\]\$]+)/m; -- $domain =~ s/^\s+//; -- $domain =~ s/\s+$//; -- -- return $domain; --} -- --sub FindMakevarsBugAddress --{ -- -- my $address = ""; -- my $makevars_source; { -- local (*IN); -- open (IN, "; -- close IN; -- } -- -- $address = $1 if $makevars_source =~ /^MSGID_BUGS_ADDRESS[ ]*=\[?([^\n\]\$]+)/m; -- $address =~ s/^\s+//; -- $address =~ s/\s+$//; -- -- return $address; --} -diff --git a/intltool-update.in b/intltool-update.in -new file mode 120000 -index 661d8fe..0b1800f ---- /dev/null -+++ b/intltool-update.in -@@ -0,0 +1 @@ -+/usr/share/intltool/intltool-update.in -\ No newline at end of file -diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am -index f5dd164..27aec65 100644 ---- a/pixmaps/Makefile.am -+++ b/pixmaps/Makefile.am -@@ -3,8 +3,14 @@ icon_DATA = \ - intlclock-calendar-icon.png \ - intlclock-face-large.svg \ - intlclock-face-small.svg \ -+ intlclock-face-small-morning.svg \ -+ intlclock-face-small-day.svg \ -+ intlclock-face-small-evening.svg \ -+ intlclock-face-small-night.svg \ - intlclock-map.svg \ -- intlclock-map-location-marker.svg -+ intlclock-map-location-marker.svg \ -+ intlclock-map-location-current.svg \ -+ intlclock-map-location-hilight.svg - - EXTRA_DIST = $(icon_DATA) - -diff --git a/pixmaps/intlclock-face-small-day.svg b/pixmaps/intlclock-face-small-day.svg -new file mode 100644 -index 0000000..bd4b5b2 ---- /dev/null -+++ b/pixmaps/intlclock-face-small-day.svg -@@ -0,0 +1,290 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ image/svg+xml -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/pixmaps/intlclock-face-small-evening.svg b/pixmaps/intlclock-face-small-evening.svg -new file mode 100644 -index 0000000..17a9840 ---- /dev/null -+++ b/pixmaps/intlclock-face-small-evening.svg -@@ -0,0 +1,290 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ image/svg+xml -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/pixmaps/intlclock-face-small-morning.svg b/pixmaps/intlclock-face-small-morning.svg -new file mode 100644 -index 0000000..17a9840 ---- /dev/null -+++ b/pixmaps/intlclock-face-small-morning.svg -@@ -0,0 +1,290 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ image/svg+xml -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/pixmaps/intlclock-face-small-night.svg b/pixmaps/intlclock-face-small-night.svg -new file mode 100644 -index 0000000..d5a7d8e ---- /dev/null -+++ b/pixmaps/intlclock-face-small-night.svg -@@ -0,0 +1,291 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ image/svg+xml -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/pixmaps/intlclock-map-location-current.png b/pixmaps/intlclock-map-location-current.png -new file mode 100644 -index 0000000..5c505d1 -Binary files /dev/null and b/pixmaps/intlclock-map-location-current.png differ -diff --git a/pixmaps/intlclock-map-location-current.svg b/pixmaps/intlclock-map-location-current.svg -new file mode 100644 -index 0000000..93b5188 ---- /dev/null -+++ b/pixmaps/intlclock-map-location-current.svg -@@ -0,0 +1,76 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ image/svg+xml -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/pixmaps/intlclock-map-location-hilight.png b/pixmaps/intlclock-map-location-hilight.png -new file mode 100644 -index 0000000..d7de5b7 -Binary files /dev/null and b/pixmaps/intlclock-map-location-hilight.png differ -diff --git a/pixmaps/intlclock-map-location-hilight.svg b/pixmaps/intlclock-map-location-hilight.svg -new file mode 100644 -index 0000000..4a245e0 ---- /dev/null -+++ b/pixmaps/intlclock-map-location-hilight.svg -@@ -0,0 +1,90 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ image/svg+xml -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/pixmaps/intlclock-map-location-marker.png b/pixmaps/intlclock-map-location-marker.png -new file mode 100644 -index 0000000..48d2184 -Binary files /dev/null and b/pixmaps/intlclock-map-location-marker.png differ -diff --git a/po/Makefile.in.in b/po/Makefile.in.in -deleted file mode 100755 -index d2d4e4c..e4713cf ---- a/po/Makefile.in.in -+++ /dev/null -@@ -1,221 +0,0 @@ --# Makefile for program source directory in GNU NLS utilities package. --# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper --# --# This file file be copied and used freely without restrictions. It can --# be used in projects which are not available under the GNU Public License --# but which still want to provide support for the GNU gettext functionality. --# Please note that the actual code is *not* freely available. --# --# - Modified by Owen Taylor to use GETTEXT_PACKAGE --# instead of PACKAGE and to look for po2tbl in ./ not in intl/ --# --# - Modified by jacob berkman to install --# Makefile.in.in and po2tbl.sed.in for use with glib-gettextize --# --# - Modified by Rodney Dawes for use with intltool --# --# We have the following line for use by intltoolize: --# INTLTOOL_MAKEFILE -- --GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ --PACKAGE = @PACKAGE@ --VERSION = @VERSION@ -- --SHELL = /bin/sh -- --srcdir = @srcdir@ --top_srcdir = @top_srcdir@ --top_builddir = .. --VPATH = @srcdir@ -- --prefix = @prefix@ --exec_prefix = @exec_prefix@ --datadir = @datadir@ --datarootdir = @datarootdir@ --libdir = @libdir@ --DATADIRNAME = @DATADIRNAME@ --itlocaledir = $(prefix)/$(DATADIRNAME)/locale --subdir = po --install_sh = @install_sh@ --# Automake >= 1.8 provides @mkdir_p@. --# Until it can be supposed, use the safe fallback: --mkdir_p = $(install_sh) -d -- --INSTALL = @INSTALL@ --INSTALL_DATA = @INSTALL_DATA@ -- --GMSGFMT = @GMSGFMT@ --MSGFMT = @MSGFMT@ --XGETTEXT = @XGETTEXT@ --INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ --INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ --MSGMERGE = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist --GENPOT = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot -- --ALL_LINGUAS = @ALL_LINGUAS@ -- --PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; fi) -- --POFILES=$(shell if test -n "$(PO_LINGUAS)"; then LINGUAS="$(PO_LINGUAS)"; else LINGUAS="$(ALL_LINGUAS)"; fi; for lang in $$LINGUAS; do printf "$$lang.po "; done) -- --DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(POFILES) --EXTRA_DISTFILES = POTFILES.skip Makevars LINGUAS -- --POTFILES = \ --#This Gets Replace for some reason -- --CATALOGS=$(shell if test -n "$(PO_LINGUAS)"; then LINGUAS="$(PO_LINGUAS)"; else LINGUAS="$(ALL_LINGUAS)"; fi; for lang in $$LINGUAS; do printf "$$lang.gmo "; done) -- --.SUFFIXES: --.SUFFIXES: .po .pox .gmo .mo .msg .cat -- --.po.pox: -- $(MAKE) $(GETTEXT_PACKAGE).pot -- $(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox -- --.po.mo: -- $(MSGFMT) -o $@ $< -- --.po.gmo: -- file=`echo $* | sed 's,.*/,,'`.gmo \ -- && rm -f $$file && $(GMSGFMT) -o $$file $< -- --.po.cat: -- sed -f ../intl/po2msg.sed < $< > $*.msg \ -- && rm -f $@ && gencat $@ $*.msg -- -- --all: all-@USE_NLS@ -- --all-yes: $(CATALOGS) --all-no: -- --$(GETTEXT_PACKAGE).pot: $(POTFILES) -- $(GENPOT) -- --install: install-data --install-data: install-data-@USE_NLS@ --install-data-no: all --install-data-yes: all -- $(mkdir_p) $(DESTDIR)$(itlocaledir) -- if test -n "$(PO_LINGUAS)"; then \ -- linguas="$(PO_LINGUAS)"; \ -- else \ -- linguas="$(ALL_LINGUAS)"; \ -- fi; \ -- for lang in $$linguas; do \ -- dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \ -- $(mkdir_p) $$dir; \ -- if test -r $$lang.gmo; then \ -- $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ -- echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \ -- else \ -- $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ -- echo "installing $(srcdir)/$$lang.gmo as" \ -- "$$dir/$(GETTEXT_PACKAGE).mo"; \ -- fi; \ -- if test -r $$lang.gmo.m; then \ -- $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ -- echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ -- else \ -- if test -r $(srcdir)/$$lang.gmo.m ; then \ -- $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \ -- $$dir/$(GETTEXT_PACKAGE).mo.m; \ -- echo "installing $(srcdir)/$$lang.gmo.m as" \ -- "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ -- else \ -- true; \ -- fi; \ -- fi; \ -- done -- --# Empty stubs to satisfy archaic automake needs --dvi info tags TAGS ID: -- --# Define this as empty until I found a useful application. --installcheck: -- --uninstall: -- if test -n "$(PO_LINGUAS)"; then \ -- linguas="$(PO_LINGUAS)"; \ -- else \ -- linguas="$(ALL_LINGUAS)"; \ -- fi; \ -- for lang in $$linguas; do \ -- rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ -- rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ -- done -- --check: all $(GETTEXT_PACKAGE).pot -- --mostlyclean: -- rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp -- rm -f .intltool-merge-cache -- --clean: mostlyclean -- --distclean: clean -- rm -f Makefile Makefile.in POTFILES stamp-it -- rm -f *.mo *.msg *.cat *.cat.m *.gmo -- --maintainer-clean: distclean -- @echo "This command is intended for maintainers to use;" -- @echo "it deletes files that may require special tools to rebuild." -- rm -f Makefile.in.in -- --distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) --dist distdir: $(DISTFILES) -- dists="$(DISTFILES)"; \ -- extra_dists="$(EXTRA_DISTFILES)"; \ -- for file in $$extra_dists; do \ -- test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ -- done; \ -- for file in $$dists; do \ -- test -f $$file || file="$(srcdir)/$$file"; \ -- ln $$file $(distdir) 2> /dev/null \ -- || cp -p $$file $(distdir); \ -- done -- --update-po: Makefile -- $(MAKE) $(GETTEXT_PACKAGE).pot -- tmpdir=`pwd`; \ -- if test -n "$(PO_LINGUAS)"; then \ -- linguas="$(PO_LINGUAS)"; \ -- else \ -- linguas="$(ALL_LINGUAS)"; \ -- fi; \ -- for lang in $$linguas; do \ -- echo "$$lang:"; \ -- result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \ -- if $$result; then \ -- if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ -- rm -f $$tmpdir/$$lang.new.po; \ -- else \ -- if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ -- :; \ -- else \ -- echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ -- rm -f $$tmpdir/$$lang.new.po; \ -- exit 1; \ -- fi; \ -- fi; \ -- else \ -- echo "msgmerge for $$lang.gmo failed!"; \ -- rm -f $$tmpdir/$$lang.new.po; \ -- fi; \ -- done -- --Makefile POTFILES: stamp-it -- @if test ! -f $@; then \ -- rm -f stamp-it; \ -- $(MAKE) stamp-it; \ -- fi -- --stamp-it: Makefile.in.in ../config.status POTFILES.in -- cd .. \ -- && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ -- $(SHELL) ./config.status -- --# Tell versions [3.59,3.63) of GNU make not to export all variables. --# Otherwise a system limit (for SysV at least) may be exceeded. --.NOEXPORT: -diff --git a/po/Makefile.in.in b/po/Makefile.in.in -new file mode 120000 -index d2d4e4c..e4713cf ---- /dev/null -+++ b/po/Makefile.in.in -@@ -0,0 +1 @@ -+/usr/share/intltool/Makefile.in.in -\ No newline at end of file -diff --git a/src/Makefile.am b/src/Makefile.am -index 80d1419..d681d39 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -3,7 +3,7 @@ - INCLUDES = \ - $(INTLCLOCK_CFLAGS) \ - -DGNOMELOCALEDIR=\"$(prefix)/$(DATADIRNAME)/locale\" \ -- -DEVOLUTION_TEXTDOMAIN=\"evolution-2.6\" \ -+ -DEVOLUTION_TEXTDOMAIN=\"evolution-2.12\" \ - -DINTLCLOCK_TEXTDOMAIN=\"gnome-panel-2.0\" \ - -DINTLCLOCK_ICONDIR=\"$(pkgdatadir)\" \ - -DINTLCLOCK_DATADIR=\"$(pkgdatadir)\" \ -@@ -60,7 +60,11 @@ COMMON_SOURCES = \ - intlclock-zoneinfo.c \ - intlclock-zoneinfo.h \ - intlclock-zonetable.c \ -- intlclock-zonetable.h -+ intlclock-zonetable.h \ -+ set-timezone.c \ -+ set-timezone.h \ -+ gweather-xml.c \ -+ gweather-xml.h - - - intlclock_applet_SOURCES = \ -diff --git a/src/gweather-xml.c b/src/gweather-xml.c -new file mode 100644 -index 0000000..94b275d ---- /dev/null -+++ b/src/gweather-xml.c -@@ -0,0 +1,490 @@ -+/* gweather-xml.c - Locations.xml parsing code -+ * -+ * Copyright (C) 2005 Ryan Lortie, 2004 Gareth Owen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+ -+/* There is very little error checking in the parsing code below, it relies -+ * heavily on the locations file being in the correct format. If you have -+ * elements within a parent element, they must come first and be -+ * grouped together. -+ * The format is as follows: -+ * -+ * -+ * -+ * Name of the region -+ * Translated Name -+ * Another Translated Name -+ * -+ * Name of the country -+ * -+ * Name of the location -+ * IWIN code -+ * Forecast code (North America, Australia, UK only) -+ * Weather.com radar map code (North America only) -+ * Latitude and longitude as DD-MM[-SS][H] pair -+ * -+ * -+ * -+ * .... -+ * -+ * -+ * Name of city with multiple locations -+ * Forecast code -+ * Radar Map code -+ * -+ * ... -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * The thing to note is that each country can either contain different locations -+ * or be split into "states" which in turn contain a list of locations. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "gweather-xml.h" -+ -+static gint -+gweather_xml_location_sort_func( GtkTreeModel *model, GtkTreeIter *a, -+ GtkTreeIter *b, gpointer user_data ) -+{ -+ gint res; -+ gchar *name_a, *name_b; -+ gchar *fold_a, *fold_b; -+ -+ gtk_tree_model_get (model, a, GWEATHER_XML_COL_LOC, &name_a, -1); -+ gtk_tree_model_get (model, b, GWEATHER_XML_COL_LOC, &name_b, -1); -+ -+ fold_a = g_utf8_casefold(name_a, -1); -+ fold_b = g_utf8_casefold(name_b, -1); -+ -+ res = g_utf8_collate(fold_a, fold_b); -+ -+ g_free(name_a); -+ g_free(name_b); -+ g_free(fold_a); -+ g_free(fold_b); -+ -+ return res; -+} -+ -+static char* -+gweather_xml_get_value( xmlTextReaderPtr xml ) -+{ -+ char* value; -+ -+ /* check for null node */ -+ if ( xmlTextReaderIsEmptyElement( xml ) ) -+ return NULL; -+ -+ /* the next "node" is the text node containing the value we want to get */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ return NULL; -+ -+ value = (char *) xmlTextReaderValue( xml ); -+ -+ /* move on to the end of this node */ -+ while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_END_ELEMENT ) -+ if( xmlTextReaderRead( xml ) != 1 ) -+ { -+ xmlFree( value ); -+ return NULL; -+ } -+ -+ /* consume the end element too */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ { -+ xmlFree( value ); -+ return NULL; -+ } -+ -+ return value; -+} -+ -+static char * -+gweather_xml_parse_name( xmlTextReaderPtr xml ) -+{ -+ const char * const *locales; -+ const char *this_language; -+ int best_match = INT_MAX; -+ char *lang, *tagname; -+ gboolean keep_going; -+ char *name = NULL; -+ int i; -+ -+ locales = g_get_language_names(); -+ -+ do -+ { -+ /* First let's get the language */ -+ lang = (char *) xmlTextReaderXmlLang( xml ); -+ -+ if( lang == NULL ) -+ this_language = "C"; -+ else -+ this_language = lang; -+ -+ /* the next "node" is text node containing the actual name */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ { -+ xmlFree( lang ); -+ return NULL; -+ } -+ -+ for( i = 0; locales[i] && i < best_match; i++ ) -+ if( !strcmp( locales[i], this_language ) ) -+ { -+ /* if we've already encounted a less accurate -+ translation, then free it */ -+ xmlFree( name ); -+ -+ name = (char *) xmlTextReaderValue( xml ); -+ best_match = i; -+ -+ break; -+ } -+ -+ xmlFree( lang ); -+ -+ while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_ELEMENT ) -+ if( xmlTextReaderRead( xml ) != 1 ) -+ { -+ xmlFree( name ); -+ return NULL; -+ } -+ -+ /* if the next tag is another then keep going */ -+ tagname = (char *) xmlTextReaderName( xml ); -+ keep_going = !strcmp( tagname, "name" ); -+ xmlFree( tagname ); -+ -+ } while( keep_going ); -+ -+ return name; -+} -+ -+static int -+gweather_xml_parse_node (GtkTreeView *view, GtkTreeIter *parent, -+ xmlTextReaderPtr xml, WeatherLocation *current, -+ const char *dflt_radar, const char *dflt_zone, -+ const char *cityname) -+{ -+ GtkTreeStore *store = GTK_TREE_STORE( gtk_tree_view_get_model( view ) ); -+ char *name, *code, *zone, *radar, *coordinates; -+ char **city, *nocity = NULL; -+ GtkTreeIter iter, *self; -+ gboolean is_location; -+ char *tagname; -+ int ret = -1; -+ int tagtype; -+ -+ if( (tagname = (char *) xmlTextReaderName( xml )) == NULL ) -+ return -1; -+ -+ if( !strcmp( tagname, "city" ) ) -+ city = &name; -+ else -+ city = &nocity; -+ -+ is_location = !strcmp( tagname, "location" ); -+ -+ /* if we're processing the top-level, then don't create a new iter */ -+ if( !strcmp( tagname, "gweather" ) ) -+ self = NULL; -+ else -+ { -+ self = &iter; -+ /* insert this node into the tree */ -+ gtk_tree_store_append( store, self, parent ); -+ } -+ -+ xmlFree( tagname ); -+ -+ coordinates = NULL; -+ radar = NULL; -+ zone = NULL; -+ code = NULL; -+ name = NULL; -+ -+ /* absorb the start tag */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ goto error_out; -+ -+ /* start parsing the actual contents of the node */ -+ while( (tagtype = xmlTextReaderNodeType( xml )) != -+ XML_READER_TYPE_END_ELEMENT ) -+ { -+ -+ /* skip non-element types */ -+ if( tagtype != XML_READER_TYPE_ELEMENT ) -+ { -+ if( xmlTextReaderRead( xml ) != 1 ) -+ goto error_out; -+ -+ continue; -+ } -+ -+ tagname = (char *) xmlTextReaderName( xml ); -+ -+ if( !strcmp( tagname, "region" ) || !strcmp( tagname, "country" ) || -+ !strcmp( tagname, "state" ) || !strcmp( tagname, "city" ) || -+ !strcmp( tagname, "location" ) ) -+ { -+ /* recursively handle sub-sections */ -+ if( gweather_xml_parse_node( view, self, xml, current, -+ radar, zone, *city ) ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "name" ) ) -+ { -+ xmlFree( name ); -+ if( (name = gweather_xml_parse_name( xml )) == NULL ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "code" ) ) -+ { -+ xmlFree( code ); -+ if( (code = gweather_xml_get_value( xml )) == NULL ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "zone" ) ) -+ { -+ xmlFree( zone ); -+ if( (zone = gweather_xml_get_value( xml )) == NULL ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "radar" ) ) -+ { -+ xmlFree( radar ); -+ if( (radar = gweather_xml_get_value( xml )) == NULL ) -+ goto error_out; -+ } -+ else if ( !strcmp( tagname, "coordinates" ) ) -+ { -+ xmlFree( coordinates ); -+ if( (coordinates = gweather_xml_get_value( xml )) == NULL ) -+ goto error_out; -+ } -+ else /* some strange tag */ -+ { -+ /* skip past it */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ goto error_out; -+ } -+ -+ xmlFree( tagname ); -+ } -+ -+ if( self ) -+ gtk_tree_store_set( store, self, GWEATHER_XML_COL_LOC, name, -1 ); -+ -+ /* absorb the end tag. in the case of processing a then 'self' -+ is NULL. In this case, we let this fail since we might be at EOF */ -+ if( xmlTextReaderRead( xml ) != 1 && self ) -+ goto error_out; -+ -+ /* if this is an actual location, setup the WeatherLocation for it */ -+ if( is_location ) -+ { -+ WeatherLocation *new_loc; -+ -+ if( cityname == NULL ) -+ cityname = name; -+ -+ if( radar != NULL ) -+ dflt_radar = radar; -+ -+ if( zone != NULL ) -+ dflt_zone = zone; -+ -+ new_loc = weather_location_new( cityname, code, dflt_zone, -+ dflt_radar, coordinates ); -+ -+ gtk_tree_store_set( store, &iter, GWEATHER_XML_COL_POINTER, new_loc, -1 ); -+ -+ /* If this location is actually the currently selected one, select it */ -+ if( current && weather_location_equal( new_loc, current ) ) -+ { -+ GtkTreePath *path; -+ -+ path = gtk_tree_model_get_path( GTK_TREE_MODEL (store), &iter ); -+ gtk_tree_view_expand_to_path( view, path ); -+ gtk_tree_view_set_cursor( view, path, NULL, FALSE ); -+ gtk_tree_view_scroll_to_cell( view, path, NULL, TRUE, 0.5, 0.5 ); -+ gtk_tree_path_free( path ); -+ } -+ } -+ -+ ret = 0; -+ -+error_out: -+ xmlFree( name ); -+ xmlFree( code ); -+ xmlFree( zone ); -+ xmlFree( radar ); -+ xmlFree( coordinates ); -+ -+ return ret; -+} -+ -+/***************************************************************************** -+ * Func: gweather_xml_load_locations() -+ * Desc: Main entry point for loading the locations from the XML file -+ * Parm: -+ * *tree: tree to view locations -+ * *current: currently selected location -+ */ -+int -+gweather_xml_load_locations( GtkTreeView *tree, WeatherLocation *current ) -+{ -+ char *tagname, *format; -+ GtkTreeSortable *sortable; -+ xmlTextReaderPtr xml; -+ int keep_going; -+ int ret = -1; -+ -+ /* Open the xml file containing the different locations */ -+#ifdef GWEATHER_XML_LOCATION -+ xml = xmlNewTextReaderFilename (GWEATHER_XML_LOCATION "Locations.xml"); -+#else -+ xml = xmlNewTextReaderFilename ("/usr/share/gnome-applets/gweather/Locations.xml"); -+#endif -+ if( xml == NULL ) -+ goto error_out; -+ -+ /* fast forward to the first element */ -+ do -+ { -+ /* if we encounter a problem here, exit right away */ -+ if( xmlTextReaderRead( xml ) != 1 ) -+ goto error_out; -+ } while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_ELEMENT ); -+ -+ /* check the name and format */ -+ tagname = (char *) xmlTextReaderName( xml ); -+ keep_going = tagname && !strcmp( tagname, "gweather" ); -+ xmlFree( tagname ); -+ -+ if( !keep_going ) -+ goto error_out; -+ -+ format = (char *) xmlTextReaderGetAttribute( xml, (xmlChar *) "format" ); -+ keep_going = format && !strcmp( format, "1.0" ); -+ xmlFree( format ); -+ -+ if( !keep_going ) -+ goto error_out; -+ -+ ret = gweather_xml_parse_node( tree, NULL, xml, current, NULL, NULL, NULL ); -+ -+ if( ret ) -+ goto error_out; -+ -+ /* Sort the tree */ -+ sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model( tree )); -+ gtk_tree_sortable_set_default_sort_func( sortable, -+ &gweather_xml_location_sort_func, -+ NULL, NULL); -+ gtk_tree_sortable_set_sort_column_id( sortable, -+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, -+ GTK_SORT_ASCENDING ); -+error_out: -+ xmlFreeTextReader( xml ); -+ -+ return ret; -+} -+ -+typedef struct { -+ const gchar *name; -+ gdouble latitude; -+ gdouble longitude; -+ gdouble distance; -+ WeatherLocation *location; -+} SearchData; -+ -+ -+static gdouble -+distance (gdouble lat1, gdouble lon1, -+ gdouble lat2, gdouble lon2) -+{ -+ gdouble radius = 6372.795; -+ -+ return acos (cos (lat1) * cos (lat2) * cos (lon1 - lon2) + sin (lat1) * sin (lat2)) * radius; -+} -+ -+gboolean -+compare_location (GtkTreeModel *model, -+ GtkTreePath *path, -+ GtkTreeIter *iter, -+ gpointer user_data) -+{ -+ SearchData *data = user_data; -+ WeatherLocation *loc; -+ gdouble d; -+ -+ gtk_tree_model_get (model, iter, GWEATHER_XML_COL_POINTER, &loc, -1); -+ -+ if (!loc) -+ return FALSE; -+ -+ d = distance (data->latitude, data->longitude, loc->latitude, loc->longitude); -+ -+ if (d < data->distance) { -+ data->distance = d; -+ data->location = loc; -+ } -+ -+ return FALSE; -+} -+ -+gchar * -+find_weather_code (GtkTreeModel *model, -+ const gchar *name, -+ gdouble lat, -+ gdouble lon) -+{ -+ SearchData data; -+ gchar *code; -+ -+ data.name = name; -+ data.latitude = lat; -+ data.longitude = lon; -+ data.distance = 1e6; -+ data.location = NULL; -+ -+ gtk_tree_model_foreach (GTK_TREE_MODEL (model), compare_location, &data); -+ -+ if (data.distance < 50) -+ code = g_strdup (data.location->code); -+ else -+ code = g_strdup ("-"); -+ -+ g_debug ("distance: %f\nin: %s\nlat, lon: %f, %f\nout: %s\nDMS: %s\ncode: %s\n", -+ data.distance, name, lat, lon, data.location->name, data.location->coordinates, code); -+ -+ return code; -+} -diff --git a/src/gweather-xml.h b/src/gweather-xml.h -new file mode 100644 -index 0000000..d65b651 ---- /dev/null -+++ b/src/gweather-xml.h -@@ -0,0 +1,37 @@ -+/* gweather-xml.h -+ * -+ * Copyright (C) 2004 Gareth Owen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#ifndef __GWEATHER_XML_H__ -+#define __GWEATHER_XML_H__ -+ -+#include -+#include -+ -+enum -+{ -+ GWEATHER_XML_COL_LOC = 0, -+ GWEATHER_XML_COL_POINTER, -+ GWEATHER_XML_NUM_COLUMNS -+}; -+ -+int gweather_xml_load_locations( GtkTreeView *tree, WeatherLocation *current ); -+gchar *find_weather_code (GtkTreeModel *model, const gchar *name, gdouble lat, gdouble lon); -+ -+ -+#endif /* __GWEATHER_XML_H__ */ -diff --git a/src/intlclock-events-popup.c b/src/intlclock-events-popup.c -index 4276f81..a54f6e3 100644 ---- a/src/intlclock-events-popup.c -+++ b/src/intlclock-events-popup.c -@@ -1,6 +1,8 @@ - #include - #include - #include -+#include -+#include - - #ifdef HAVE_CONFIG_H - #include "config.h" -@@ -11,12 +13,18 @@ - #endif - - #include "intlclock-events-popup.h" -+#include "intlclock-ui.h" -+ -+#define KEY_EXPAND_LOCATIONS "expand_locations" -+#define KEY_EXPAND_TASKS "expand_tasks" -+#define KEY_EXPAND_APPOINTMENTS "expand_appointments" - - G_DEFINE_TYPE (IntlClockEventsPopup, intlclock_events_popup, GTK_TYPE_WINDOW) - - typedef struct { - IntlClock *clock; - PanelApplet *panel_applet; -+ IntlClockUI *ui; - - GtkWidget *calendar; - GtkWidget *main_section; -@@ -126,7 +134,7 @@ intlclock_events_popup_size_allocate_cb (GtkWidget *widget, GtkAllocation *alloc - } - - IntlClockEventsPopup * --intlclock_events_popup_new (IntlClock *clock, PanelApplet *panel_applet) -+intlclock_events_popup_new (IntlClock *clock, PanelApplet *panel_applet, IntlClockUI *ui) - { - IntlClockEventsPopup *this; - IntlClockEventsPopupPrivate *priv; -@@ -138,6 +146,7 @@ intlclock_events_popup_new (IntlClock *clock, PanelApplet *panel_applet) - - priv->clock = g_object_ref (clock); - priv->panel_applet = panel_applet; -+ priv->ui = ui; - - gtk_widget_set_name (GTK_WIDGET (this), "intlclock-events-window"); - gtk_container_set_border_width (GTK_CONTAINER (this), 0); -@@ -275,6 +284,21 @@ intlclock_events_popup_tick (IntlClock *clock, IntlClockEventsPopup *this) - gmtime (&priv->current_time); - } - -+static GtkWidget * create_hig_frame (IntlClockEventsPopup *this, -+ const char *title, -+ const char *button_label, -+ const char *key, -+ GCallback callback); -+ -+ -+static void -+edit_locations (IntlClockEventsPopup *this) -+{ -+ IntlClockEventsPopupPrivate *priv = PRIVATE (this); -+ -+ intlclock_ui_edit_locations (priv->ui); -+} -+ - static void - intlclock_events_popup_fill (IntlClockEventsPopup *this) - { -@@ -296,7 +320,10 @@ intlclock_events_popup_fill (IntlClockEventsPopup *this) - - orient = panel_applet_get_orient (priv->panel_applet); - -- priv->clock_container = gtk_vbox_new (FALSE, 0); -+ priv->clock_container = create_hig_frame (this, -+ _("Locations"), _("Edit"), -+ KEY_EXPAND_LOCATIONS, -+ G_CALLBACK (edit_locations)); - - switch (orient) { - case PANEL_APPLET_ORIENT_UP: -@@ -642,28 +669,167 @@ modify_task_text_attributes (GtkTreeModel *model, - g_value_take_boxed (value, attr_list); - } - -+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 -+expander_activated (GtkExpander *expander, -+ gpointer data) -+{ -+ IntlClockEventsPopup *this = data; -+ IntlClockEventsPopupPrivate *priv = PRIVATE (this); -+ const gchar *key; -+ gboolean expanded; -+ -+ key = (const gchar*)g_object_get_data (G_OBJECT (expander), "gconf-key"); -+ expanded = gtk_expander_get_expanded (expander); -+ -+ panel_applet_gconf_set_bool (priv->panel_applet, key, expanded, NULL); -+} -+ -+static void -+expanded_changed (GConfClient *client, -+ guint cnxn_id, -+ GConfEntry *entry, -+ GtkExpander *expander) -+{ -+ if (!entry->value || entry->value->type != GCONF_VALUE_BOOL) -+ return; -+ -+ gtk_expander_set_expanded (expander, -+ gconf_value_get_bool (entry->value)); -+} -+ -+static void -+remove_listener (gpointer data) -+{ -+ GConfClient *client; -+ -+ client = gconf_client_get_default (); -+ gconf_client_notify_remove (client, GPOINTER_TO_UINT (data)); -+ g_object_unref (client); -+} -+ -+static void -+connect_expander_with_gconf (IntlClockEventsPopup *this, -+ GtkWidget *expander, -+ const gchar *key) -+{ -+ IntlClockEventsPopupPrivate *priv = PRIVATE (this); -+ GConfClient *client; -+ gboolean expanded; -+ guint listener; -+ gchar *full_key; -+ -+ g_object_set_data (G_OBJECT (expander), "gconf-key", (gpointer)key); -+ -+ expanded = panel_applet_gconf_get_bool (priv->panel_applet, key, NULL); -+ gtk_expander_set_expanded (GTK_EXPANDER (expander), expanded); -+ -+ g_signal_connect_after (expander, "activate", -+ G_CALLBACK (expander_activated), -+ this); -+ -+ client = gconf_client_get_default (); -+ full_key = panel_applet_gconf_get_full_key (priv->panel_applet, key); -+ listener = gconf_client_notify_add (client, full_key, -+ (GConfClientNotifyFunc)expanded_changed, -+ expander, NULL, NULL); -+ g_object_set_data_full (G_OBJECT (expander), "listener-id", -+ GUINT_TO_POINTER (listener), remove_listener); -+ g_object_unref (client); -+} -+ -+static void add_child (GtkContainer *container, -+ GtkWidget *child, -+ GtkExpander *expander) -+{ -+ gboolean expanded; -+ -+ expanded = gtk_expander_get_expanded (expander); -+ g_object_set (child, "visible", expanded, NULL); -+} -+ - static GtkWidget * --create_hig_frame (const char *title) -+create_hig_frame (IntlClockEventsPopup *this, -+ 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); -- -- alignment = gtk_alignment_new (0, 0.5, 0, 0); -- gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0); -- gtk_widget_show (alignment); -- -- label = gtk_label_new (bold_title); -- gtk_label_set_use_markup (GTK_LABEL (label), TRUE); -- gtk_container_add (GTK_CONTAINER (alignment), label); -- gtk_widget_show (label); -- -+ expander = gtk_expander_new (""); -+ gtk_expander_set_label (GTK_EXPANDER (expander), 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, this); -+ } -+ -+ connect_expander_with_gconf (this, expander, key); - - return vbox; - } -@@ -791,6 +957,12 @@ compare_tasks (GtkTreeModel *model, - } - } - -+static void -+edit_tasks (IntlClockEventsPopup *this) -+{ -+ clock_launch_evolution (this, "--component=tasks"); -+} -+ - static GtkWidget * - create_task_list (IntlClockEventsPopup *this, - GtkWidget **tree_view, -@@ -804,7 +976,9 @@ create_task_list (IntlClockEventsPopup *this, - GtkCellRenderer *cell; - GtkTreeViewColumn *column; - -- vbox = create_hig_frame (_("Tasks")); -+ vbox = create_hig_frame (this, _("Tasks"), _("Edit"), -+ KEY_EXPAND_TASKS, -+ G_CALLBACK (edit_tasks)); - - *scrolled_window = scrolled = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), -@@ -812,8 +986,8 @@ create_task_list (IntlClockEventsPopup *this, - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), - GTK_POLICY_NEVER, - GTK_POLICY_AUTOMATIC); -- gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0); - gtk_widget_show (scrolled); -+ gtk_container_add (GTK_CONTAINER (vbox), scrolled); - - if (!priv->tasks_model) { - GType column_types [N_TASK_COLUMNS] = { -@@ -984,6 +1158,12 @@ handle_appointments_changed (IntlClockEventsPopup *this) - update_frame_visibility (priv->appointment_list, GTK_TREE_MODEL (priv->appointments_model)); - } - -+static void -+edit_appointments (IntlClockEventsPopup *this) -+{ -+ clock_launch_evolution (this, "--component=calendar"); -+} -+ - static GtkWidget * - create_appointment_list (IntlClockEventsPopup *this, - GtkWidget **tree_view, -@@ -997,7 +1177,9 @@ create_appointment_list (IntlClockEventsPopup *this, - GtkCellRenderer *cell; - GtkTreeViewColumn *column; - -- vbox = create_hig_frame ( _("Appointments")); -+ vbox = create_hig_frame (this, _("Appointments"), _("Edit"), -+ KEY_EXPAND_APPOINTMENTS, -+ G_CALLBACK (edit_appointments)); - - *scrolled_window = scrolled = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), -@@ -1005,8 +1187,8 @@ create_appointment_list (IntlClockEventsPopup *this, - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), - GTK_POLICY_NEVER, - GTK_POLICY_AUTOMATIC); -- gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0); - gtk_widget_show (scrolled); -+ gtk_container_add (GTK_CONTAINER (vbox), scrolled); - - if (!priv->appointments_model) { - priv->appointments_model = -diff --git a/src/intlclock-events-popup.h b/src/intlclock-events-popup.h -index 84a5183..b88e4c7 100644 ---- a/src/intlclock-events-popup.h -+++ b/src/intlclock-events-popup.h -@@ -2,6 +2,7 @@ - #define __INTLCLOCK_EVENTS_POPUP_H__ - - #include "intlclock.h" -+#include "intlclock-ui.h" - - #include - #include -@@ -29,7 +30,8 @@ typedef struct - GType intlclock_events_popup_get_type (void); - - IntlClockEventsPopup *intlclock_events_popup_new (IntlClock *clock, -- PanelApplet *panel_applet); -+ PanelApplet *panel_applet, -+ IntlClockUI *ui); - void intlclock_events_popup_set_date (IntlClockEventsPopup *this, - guint year, guint month, guint mday); - GtkWidget *intlclock_events_popup_get_clock_container (IntlClockEventsPopup *this); -diff --git a/src/intlclock-face.c b/src/intlclock-face.c -index 537e8e7..b2e1eb0 100644 ---- a/src/intlclock-face.c -+++ b/src/intlclock-face.c -@@ -33,6 +33,13 @@ static void intlclock_face_load_face (IntlClockFace *this, - gint width, gint height); - typedef struct _IntlClockFacePrivate IntlClockFacePrivate; - -+typedef enum { -+ INTLCLOCK_FACE_MORNING, -+ INTLCLOCK_FACE_DAY, -+ INTLCLOCK_FACE_EVENING, -+ INTLCLOCK_FACE_NIGHT -+} IntlClockFaceTimeOfDay; -+ - struct _IntlClockFacePrivate - { - struct tm time; /* the time on the clock face */ -@@ -40,8 +47,8 @@ struct _IntlClockFacePrivate - - gboolean running; - IntlClockFaceSize size; -+ IntlClockFaceTimeOfDay timeofday; - IntlClockLocation *location; -- RsvgHandle *face; - GdkPixbuf *face_pixbuf; - GtkWidget *size_widget; - }; -@@ -80,6 +87,7 @@ intlclock_face_init (IntlClockFace *this) - IntlClockFacePrivate *priv = INTLCLOCK_FACE_GET_PRIVATE (this); - - priv->size = INTLCLOCK_FACE_SMALL; -+ priv->timeofday = INTLCLOCK_FACE_DAY; - priv->location = NULL; - priv->size_widget = NULL; - -@@ -281,6 +289,48 @@ static void intlclock_face_size_request (GtkWidget *this, - requisition->height = h; - } - -+static void -+update_timeofday (IntlClockFace *this) -+{ -+ IntlClockFacePrivate *priv; -+ IntlClockFaceTimeOfDay timeofday; -+ -+ priv = INTLCLOCK_FACE_GET_PRIVATE (this); -+ -+ /* FIXME this should be a gconf setting -+ * currently we hardcode -+ * morning 7-9 -+ * day 9-17 -+ * evening 17-22 -+ * night 22-7 -+ */ -+ if (priv->time.tm_hour < 7) -+ timeofday = INTLCLOCK_FACE_NIGHT; -+ else if (priv->time.tm_hour < 9) -+ timeofday = INTLCLOCK_FACE_MORNING; -+ else if (priv->time.tm_hour < 17) -+ timeofday = INTLCLOCK_FACE_DAY; -+ else if (priv->time.tm_hour < 22) -+ timeofday = INTLCLOCK_FACE_EVENING; -+ else -+ timeofday = INTLCLOCK_FACE_NIGHT; -+ -+ if (priv->timeofday != timeofday) { -+ priv->timeofday = timeofday; -+ gint width, height; -+ -+ width = GTK_WIDGET (this)->requisition.width; -+ height = GTK_WIDGET (this)->requisition.height; -+ -+ if (width == 0) -+ width = -1; -+ if (height == 0) -+ height = -1; -+ -+ intlclock_face_load_face (this, width, height); -+ } -+} -+ - gboolean - intlclock_face_refresh (IntlClockFace *this) - { -@@ -301,6 +351,8 @@ intlclock_face_refresh (IntlClockFace *this) - localtime_r (&timet, &priv->time); - } - -+ update_timeofday (this); -+ - intlclock_face_redraw_canvas (this); - - return TRUE; /* keep running this event */ -@@ -343,11 +395,6 @@ intlclock_face_finalize (GObject *obj) - priv->location = NULL; - } - -- if (priv->face) { -- rsvg_handle_close (priv->face, NULL); -- priv->face = NULL; -- } -- - if (priv->face_pixbuf) { - gdk_pixbuf_unref (priv->face_pixbuf); - priv->face_pixbuf = NULL; -@@ -375,16 +422,24 @@ static void - intlclock_face_load_face (IntlClockFace *this, gint width, gint height) - { - IntlClockFacePrivate *priv = INTLCLOCK_FACE_GET_PRIVATE (this); -+ const gchar *size_string[2] = { "small", "large" }; -+ const gchar *daytime_string[4] = { "morning", "day", "evening", "night" }; -+ gchar *name; - - if (priv->face_pixbuf != NULL) { - gdk_pixbuf_unref (priv->face_pixbuf); - priv->face_pixbuf = NULL; - } - -- if (priv->size == INTLCLOCK_FACE_SMALL) { -- priv->face_pixbuf = rsvg_pixbuf_from_file_at_size (INTLCLOCK_ICONDIR "/intlclock-face-small.svg", width, height, NULL); -- } else { -- priv->face_pixbuf = rsvg_pixbuf_from_file_at_size (INTLCLOCK_ICONDIR "/intlclock-face-large.svg", width, height, NULL); -- } -+ name = g_strconcat (INTLCLOCK_ICONDIR, "/intlclock-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) -+ return; - -+ name = g_strconcat (INTLCLOCK_ICONDIR, "/intlclock-face-", size_string[priv->size], ".svg", NULL); -+ priv->face_pixbuf = rsvg_pixbuf_from_file_at_size (name, width, height, NULL); -+ g_free (name); - } -diff --git a/src/intlclock-location-tile.c b/src/intlclock-location-tile.c -index 40d96e3..3535d8d 100644 ---- a/src/intlclock-location-tile.c -+++ b/src/intlclock-location-tile.c -@@ -23,9 +23,18 @@ typedef struct { - - IntlClockFaceSize size; - -+ GtkWidget *box; - GtkWidget *clock_face; - GtkWidget *city_label; - GtkWidget *time_label; -+ -+ GtkWidget *current_button; -+ GtkWidget *current_label; -+ GtkWidget *current_marker; -+ GtkSizeGroup *button_group; -+ -+ GtkWidget *weather_icon; -+ - } IntlClockLocationTilePrivate; - - static void intlclock_location_tile_finalize (GObject *); -@@ -36,6 +45,12 @@ static void intlclock_location_tile_refresh (IntlClockLocationTile *this); - #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INTLCLOCK_LOCATION_TILE_TYPE, IntlClockLocationTilePrivate)) - - static void intlclock_location_tile_fill (IntlClockLocationTile *this); -+static void update_weather_icon (IntlClockLocation *loc, WeatherInfo *info, gpointer data); -+static gboolean weather_tooltip (GtkWidget *widget, -+ gint x, gint y, -+ gboolean keyboard_mode, -+ GtkTooltip *tooltip, -+ gpointer data); - - IntlClockLocationTile * - intlclock_location_tile_new (IntlClock *clock, IntlClockUI *ui, -@@ -56,13 +71,17 @@ intlclock_location_tile_new (IntlClock *clock, IntlClockUI *ui, - priv->location = g_object_ref (loc); - priv->size = size; - -- gtk_alignment_set (GTK_ALIGNMENT (this), 0.0, 0.0, 0.0, 0.0); -- gtk_alignment_set_padding (GTK_ALIGNMENT (this), 3, 3, 3, 3); -- - intlclock_location_tile_fill (this); - -- g_signal_connect (G_OBJECT (priv->clock), "tick", -- G_CALLBACK (intlclock_location_tile_tick), this); -+ update_weather_icon (loc, intlclock_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); -+ g_signal_connect (G_OBJECT (loc), "weather-updated", -+ G_CALLBACK (update_weather_icon), this); -+ g_signal_connect (G_OBJECT (priv->clock), "tick", -+ G_CALLBACK (intlclock_location_tile_tick), this); - - return this; - } -@@ -133,13 +152,99 @@ intlclock_location_tile_finalize (GObject *g_obj) - priv->location = NULL; - } - -+ if (priv->button_group) { -+ g_object_unref (priv->button_group); -+ priv->button_group = NULL; -+ } -+ - G_OBJECT_CLASS (intlclock_location_tile_parent_class)->finalize (g_obj); - } - -+static gboolean -+press_on_tile (GtkWidget *widget, -+ GdkEventButton *event, -+ IntlClockLocationTile *tile) -+{ -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ -+ intlclock_blink_location (priv->clock, priv->location); -+ -+ return TRUE; -+} -+ -+static void -+make_current (GtkWidget *widget, IntlClockLocationTile *tile) -+{ -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ GError *error = NULL; -+ GtkWidget *dialog; -+ -+ if (intlclock_location_make_current (priv->location, &error)) { -+ g_signal_emit_by_name (priv->clock, "current-timezone-changed", 0); -+ } -+ else if (error) { -+ dialog = gtk_message_dialog_new (NULL, -+ 0, -+ GTK_MESSAGE_ERROR, -+ GTK_BUTTONS_OK, -+ _("Failed to set the system timezone")); -+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), error->message); -+ g_signal_connect (dialog, "response", -+ G_CALLBACK (gtk_widget_destroy), NULL); -+ gtk_window_present (GTK_WINDOW (dialog)); -+ -+ g_error_free (error); -+ } -+} -+ -+static gboolean -+enter_or_leave_tile (GtkWidget *widget, -+ GdkEventCrossing *event, -+ IntlClockLocationTile *tile) -+{ -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ -+ if (event->type == GDK_ENTER_NOTIFY) { -+ gint can_set; -+ -+ can_set = can_set_system_timezone (); -+ if (!intlclock_location_is_current (priv->location) && -+ can_set != 0) { -+ gtk_label_set_markup (GTK_LABEL (priv->current_label), -+ can_set == 1 ? -+ _("Set...") : -+ _("Set")); -+ gtk_widget_show (priv->current_button); -+ } -+ } -+ else { -+ if (event->detail != GDK_NOTIFY_INFERIOR) -+ gtk_widget_hide (priv->current_button); -+ } -+ -+ return TRUE; -+} -+ - static void - intlclock_location_tile_fill (IntlClockLocationTile *this) - { - IntlClockLocationTilePrivate *priv = PRIVATE (this); -+ GtkWidget *align; -+ GtkWidget *strut; -+ GtkWidget *box; -+ -+ 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); -+ -+ GtkWidget *alignment = gtk_alignment_new (0, 0, 1, 0); -+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 3, 3, 3, 0); - - GtkWidget *tile = gtk_hbox_new (FALSE, 6); - GtkWidget *head_section = gtk_vbox_new (FALSE, 0); -@@ -147,21 +252,55 @@ intlclock_location_tile_fill (IntlClockLocationTile *this) - 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); - -- gtk_box_pack_start (GTK_BOX (head_section), priv->city_label, -- FALSE, FALSE, 0); -- gtk_box_pack_start (GTK_BOX (head_section), priv->time_label, -- FALSE, FALSE, 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 (); -+ 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 as current timezone for this computer")); -+ -+ priv->current_marker = gtk_image_new_from_icon_name ("go-home", GTK_ICON_SIZE_BUTTON); -+ gtk_widget_set_no_show_all (priv->current_marker, TRUE); -+ -+ align = gtk_alignment_new (1, 1, 0, 0); -+ 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); -+ 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); -+ -+ g_signal_connect (priv->current_button, "clicked", -+ G_CALLBACK (make_current), this); - - priv->clock_face = intlclock_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, FALSE, FALSE, 0); -+ gtk_box_pack_start (GTK_BOX (tile), head_section, TRUE, TRUE, 0); - -- gtk_container_add (GTK_CONTAINER (this), tile); -+ gtk_container_add (GTK_CONTAINER (alignment), tile); -+ gtk_container_add (GTK_CONTAINER (priv->box), alignment); -+ gtk_container_add (GTK_CONTAINER (this), priv->box); - - intlclock_location_tile_refresh (this); - } -@@ -226,10 +365,25 @@ static void - intlclock_location_tile_refresh (IntlClockLocationTile *this) - { - IntlClockLocationTilePrivate *priv = PRIVATE (this); -- -- gchar *tmp, *tzname; -+ gchar *tmp, *tmp2, *tzname; - char buf[256]; - struct tm now; -+ long offset, hours, minutes; -+ -+ if (intlclock_location_is_current (priv->location)) { -+ if (!GTK_WIDGET_VISIBLE (priv->current_marker)) { -+ GdkPixbuf *pixbuf; -+ -+ pixbuf = gtk_image_get_pixbuf (GTK_IMAGE (priv->weather_icon)); -+ intlclock_ui_update_weather_icon (priv->ui, pixbuf); -+ } -+ -+ gtk_widget_hide (priv->current_button); -+ gtk_widget_show (priv->current_marker); -+ } -+ else { -+ gtk_widget_hide (priv->current_marker); -+ } - - if (intlclock_needs_face_refresh (this)) { - intlclock_face_refresh (INTLCLOCK_FACE (priv->clock_face)); -@@ -259,8 +413,22 @@ intlclock_location_tile_refresh (IntlClockLocationTile *this) - FALSE, TRUE, TRUE, tzname, TRUE); - } - -- gtk_label_set_markup (GTK_LABEL (priv->time_label), tmp); -+ offset = - intlclock_location_get_offset (priv->location); -+ hours = offset / 3600; -+ minutes = (offset % 3600) / 60; -+ -+ if (hours != 0 && minutes != 0) -+ tmp2 = g_strdup_printf ("%s %+d:%d", tmp, hours, minutes); -+ else if (hours != 0) -+ tmp2 = g_strdup_printf ("%s %+d", tmp, hours); -+ else { -+ tmp2 = tmp; -+ tmp = NULL; -+ } -+ -+ gtk_label_set_markup (GTK_LABEL (priv->time_label), tmp2); - g_free (tmp); -+ g_free (tmp2); - } - - static void -@@ -271,3 +439,87 @@ intlclock_location_tile_tick (IntlClock *clock, - - intlclock_location_tile_refresh (this); - } -+ -+static gboolean -+weather_tooltip (GtkWidget *widget, -+ gint x, -+ gint y, -+ gboolean keyboard_mode, -+ GtkTooltip *tooltip, -+ gpointer data) -+{ -+ IntlClockLocationTile *tile = data; -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ WeatherInfo *info; -+ GdkPixbuf *pixbuf = NULL; -+ gchar *conditions, *temp, *apparent, *wind; -+ gchar *line1, *line2, *line3, *line4, *tip; -+ -+ info = intlclock_location_get_weather_info (priv->location); -+ -+ if (!info || !weather_info_is_valid (info)) -+ return FALSE; -+ -+ weather_info_get_pixbuf (info, &pixbuf); -+ 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)); -+ -+ temp = weather_info_get_temp (info); -+ apparent = weather_info_get_apparent (info); -+ if (strcmp (apparent, temp) != 0 && -+ /* FIXME libgweather needs some real api */ -+ strcmp (apparent, dgettext ("gnome-applets-2.0", "Unknown")) != 0) -+ line2 = g_strdup_printf (_("%s, feels like %s"), temp, apparent); -+ else -+ line2 = g_strdup (temp); -+ -+ wind = weather_info_get_wind (info); -+ if (strcmp (apparent, dgettext ("gnome-applets-2.0", "Unknown")) != 0) -+ line3 = g_strdup_printf ("%s\n", wind); -+ else -+ line3 = g_strdup (""); -+ -+ line4 = g_strdup_printf (_("Sunrise: %s / Sunset: %s"), -+ weather_info_get_sunrise (info), -+ weather_info_get_sunset (info)); -+ -+ 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); -+ -+ return TRUE; -+} -+ -+ -+static void -+update_weather_icon (IntlClockLocation *loc, WeatherInfo *info, gpointer data) -+{ -+ IntlClockLocationTile *tile = data; -+ IntlClockLocationTilePrivate *priv = PRIVATE (tile); -+ GdkPixbuf *pixbuf = NULL; -+ -+ if (!info || !weather_info_is_valid (info)) -+ return; -+ -+ weather_info_get_pixbuf_mini (info, &pixbuf); -+ -+ 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); -+ if (intlclock_location_is_current (loc)) -+ intlclock_ui_update_weather_icon (priv->ui, pixbuf); -+ } -+} -+ -diff --git a/src/intlclock-location.c b/src/intlclock-location.c -index 384b2aa..30154e4 100644 ---- a/src/intlclock-location.c -+++ b/src/intlclock-location.c -@@ -1,4 +1,3 @@ --#include "intlclock-location.h" - - #ifdef HAVE_CONFIG_H - #include -@@ -13,9 +12,16 @@ - #include - #include - #include -+#include - - #include - #include -+#include -+ -+#include "intlclock-location.h" -+#include "intlclock-marshallers.h" -+#include "set-timezone.h" -+#include "gweather-xml.h" - - G_DEFINE_TYPE (IntlClockLocation, intlclock_location, G_TYPE_OBJECT) - -@@ -29,17 +35,31 @@ typedef struct { - - gfloat latitude; - gfloat longitude; -+ -+ gchar *weather_code; -+ WeatherInfo *weather_info; -+ guint weather_timeout; -+ - } IntlClockLocationPrivate; - -+enum { -+ WEATHER_UPDATED, -+ LAST_SIGNAL -+}; -+ -+static guint location_signals[LAST_SIGNAL] = { 0 }; -+ - static void intlclock_location_finalize (GObject *); - static void intlclock_location_set_tz (IntlClockLocation *this); - static void intlclock_location_unset_tz (IntlClockLocation *this); -+static void setup_weather_updates (IntlClockLocation *loc); - - #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INTLCLOCK_LOCATION_TYPE, IntlClockLocationPrivate)) - - IntlClockLocation * - intlclock_location_new (const gchar *name, const gchar *timezone, -- gfloat latitude, gfloat longitude) -+ gfloat latitude, gfloat longitude, -+ const gchar *code) - { - IntlClockLocation *this; - IntlClockLocationPrivate *priv; -@@ -62,6 +82,9 @@ intlclock_location_new (const gchar *name, const gchar *timezone, - priv->latitude = latitude; - priv->longitude = longitude; - -+ priv->weather_code = g_strdup (code); -+ setup_weather_updates (this); -+ - return this; - } - -@@ -193,6 +216,77 @@ guess_zone_from_tree (const gchar *localtime, IntlClockZoneTable *zones) - return ret; - } - -+static const gchar *current_zone = NULL; -+static GnomeVFSMonitorHandle *monitor = NULL; -+ -+static void -+parse_etc_sysconfig_clock (void) -+{ -+ gchar *data; -+ gsize len; -+ gchar **lines; -+ gchar *res; -+ gint i; -+ gchar *p, *q; -+ -+ lines = NULL; -+ res = NULL; -+ if (g_file_test ("/etc/sysconfig/clock", -+ G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { -+ if (!g_file_get_contents ("/etc/sysconfig/clock", -+ &data, &len, NULL)) -+ goto out; -+ -+ lines = g_strsplit (data, "\n", 0); -+ g_free (data); -+ -+ for (i = 0; lines[i] && !res; i++) { -+ if (g_str_has_prefix (lines[i], "ZONE=")) { -+ p = lines[i] + strlen ("ZONE="); -+ if (p[0] != '\"') -+ goto out; -+ p++; -+ q = strchr (p, '\"'); -+ q[0] = '\0'; -+ res = g_strdup (p); -+ } -+ } -+ } -+ -+out: -+ if (lines) -+ g_strfreev (lines); -+ -+ g_free (current_zone); -+ current_zone = res; -+} -+ -+static void -+monitor_etc_sysconfig_clock (GnomeVFSMonitorHandle *handle, -+ const gchar *monitor_uri, -+ const gchar *info_uri, -+ GnomeVFSMonitorEventType event_type, -+ gpointer user_data) -+{ -+ parse_etc_sysconfig_clock (); -+} -+ -+static const gchar * -+zone_from_etc_sysconfig_clock (void) -+{ -+ if (monitor == NULL) { -+ parse_etc_sysconfig_clock (); -+ -+ gnome_vfs_monitor_add (&monitor, -+ "/etc/sysconfig/clock", -+ GNOME_VFS_MONITOR_FILE, -+ monitor_etc_sysconfig_clock, -+ NULL); -+ } -+ -+ return current_zone; -+} -+ - static gchar * - intlclock_location_guess_zone (IntlClockZoneTable *zones) - { -@@ -200,6 +294,12 @@ intlclock_location_guess_zone (IntlClockZoneTable *zones) - const char *localtime = "/etc/localtime"; - gchar *linkfile = NULL; - GError *err = NULL; -+ gchar *zone; -+ -+ /* look for /etc/sysconfig/clock */ -+ if ((zone = zone_from_etc_sysconfig_clock ())) { -+ return g_strdup (zone); -+ } - - /* guess the current time zone by readlink() on /etc/localtime */ - linkfile = g_file_read_link (localtime, &err); -@@ -235,14 +335,14 @@ intlclock_location_new_from_env (IntlClockZoneTable *zones) - - if (zone == NULL) { - /* make a fake location with a null TZ */ -- return intlclock_location_new (_("Unknown Location"), NULL, 0.0, 0.0); -+ return intlclock_location_new (_("Unknown Location"), NULL, 0.0, 0.0, NULL); - } - - info = intlclock_zonetable_get_zone (zones, zone); - - if (info == NULL) { - /* make a fake location with the current TZ */ -- return intlclock_location_new (_("Unknown Location"), zone, 0.0, 0.0); -+ return intlclock_location_new (_("Unknown Location"), zone, 0.0, 0.0, NULL); - } - - g_free (zone); -@@ -260,7 +360,7 @@ intlclock_location_new_from_env (IntlClockZoneTable *zones) - } - - ret = intlclock_location_new (name, intlclock_zoneinfo_get_name (info), -- lat, lon); -+ lat, lon, NULL); - - g_free (name); - -@@ -274,6 +374,15 @@ intlclock_location_class_init (IntlClockLocationClass *this_class) - - g_obj_class->finalize = intlclock_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 (IntlClockLocationClass, weather_updated), -+ NULL, NULL, -+ _intlclock_marshal_VOID__POINTER, -+ G_TYPE_NONE, 1, G_TYPE_POINTER); -+ - g_type_class_add_private (this_class, sizeof (IntlClockLocationPrivate)); - } - -@@ -318,6 +427,21 @@ intlclock_location_finalize (GObject *g_obj) - 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 (intlclock_location_parent_class)->finalize (g_obj); - } - -@@ -467,3 +591,188 @@ intlclock_location_localtime (IntlClockLocation *loc, struct tm *tm) - - intlclock_location_unset_tz (loc); - } -+ -+gboolean -+intlclock_location_is_current (IntlClockLocation *loc) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ const char *zone; -+ -+ if ((zone = zone_from_etc_sysconfig_clock ())) -+ return strcmp (zone, priv->timezone) == 0; -+ -+ return intlclock_location_get_offset (loc) == 0; -+} -+ -+ -+glong -+intlclock_location_get_offset (IntlClockLocation *loc) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ glong sys_timezone; -+ glong offset; -+ -+ unsetenv ("TZ"); -+ tzset (); -+ sys_timezone = timezone; -+ -+ setenv ("TZ", priv->timezone, 1); -+ tzset(); -+ -+ offset = timezone - sys_timezone; -+ -+ if (priv->sys_timezone) { -+ setenv ("TZ", priv->sys_timezone, 1); -+ } else { -+ unsetenv ("TZ"); -+ } -+ tzset(); -+ -+ return offset; -+} -+ -+gboolean -+intlclock_location_make_current (IntlClockLocation *loc, GError **error) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ gchar *filename; -+ gboolean ret; -+ -+ filename = g_build_filename (SYSTEM_ZONEINFODIR, priv->timezone, NULL); -+ ret = set_system_timezone (filename, error); -+ g_free (filename); -+ -+ if (ret) { -+ /* FIXME this ugly shortcut is necessary until we move the -+ * current timezone tracking to intlclock.c and emit the -+ * signal from there -+ */ -+ g_free (current_zone); -+ current_zone = g_strdup (priv->timezone); -+ } -+ -+ return ret; -+} -+ -+const gchar * -+intlclock_location_get_weather_code (IntlClockLocation *loc) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ -+ return priv->weather_code; -+} -+ -+void -+intlclock_location_set_weather_code (IntlClockLocation *loc, const gchar *code) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ -+ g_free (priv->weather_code); -+ priv->weather_code = g_strdup (code); -+ -+ setup_weather_updates (loc); -+} -+ -+WeatherInfo * -+intlclock_location_get_weather_info (IntlClockLocation *loc) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ -+ return priv->weather_info; -+} -+ -+static void -+weather_info_updated (WeatherInfo *info, gpointer data) -+{ -+ IntlClockLocation *loc = data; -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ -+ g_signal_emit (loc, location_signals[WEATHER_UPDATED], -+ 0, priv->weather_info); -+} -+ -+static gboolean -+update_weather_info (gpointer data) -+{ -+ IntlClockLocation *loc = data; -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ WeatherPrefs prefs = { -+ FORECAST_STATE, -+ FALSE, -+ NULL, -+ TEMP_UNIT_CENTIGRADE, -+ SPEED_UNIT_MS, -+ PRESSURE_UNIT_MB, -+ DISTANCE_UNIT_KM -+ }; -+ -+ 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 void -+setup_weather_updates (IntlClockLocation *loc) -+{ -+ IntlClockLocationPrivate *priv = PRIVATE (loc); -+ const gchar *code; -+ WeatherLocation *wl; -+ WeatherPrefs prefs = { -+ FORECAST_STATE, -+ FALSE, -+ NULL, -+ TEMP_UNIT_CENTIGRADE, -+ SPEED_UNIT_MS, -+ PRESSURE_UNIT_MB, -+ DISTANCE_UNIT_KM -+ }; -+ gfloat lat, lon; -+ gchar *dms; -+ -+ 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, "-") == 0) -+ return; -+ -+ dms = rad2dms (priv->latitude, priv->longitude); -+ wl = weather_location_new (priv->name, priv->weather_code, -+ NULL, NULL, dms); -+ -+ priv->weather_info = -+ weather_info_new (wl, &prefs, weather_info_updated, loc); -+ -+ priv->weather_timeout = -+ g_timeout_add_seconds (1800, update_weather_info, loc); -+ -+ weather_location_free (wl); -+ g_free (dms); -+} -+ -diff --git a/src/intlclock-location.h b/src/intlclock-location.h -index 824ee3c..a711ac5 100644 ---- a/src/intlclock-location.h -+++ b/src/intlclock-location.h -@@ -4,6 +4,7 @@ - #include - #include - #include -+#include - - #include "intlclock-zonetable.h" - -@@ -24,12 +25,16 @@ typedef struct - typedef struct - { - GObjectClass g_object_class; -+ -+ void (* weather_updated) (IntlClockLocation *location, WeatherInfo *info); -+ - } IntlClockLocationClass; - - GType intlclock_location_get_type (void); - - IntlClockLocation *intlclock_location_new (const gchar *name, const gchar *timezone, -- gfloat latitude, gfloat longitude); -+ gfloat latitude, gfloat longitude, -+ const gchar *code); - - IntlClockLocation *intlclock_location_new_from_env (IntlClockZoneTable *zones); - -@@ -46,5 +51,14 @@ void intlclock_location_set_coords (IntlClockLocation *loc, gfloat latitude, gfl - - void intlclock_location_localtime (IntlClockLocation *loc, struct tm *tm); - -+gboolean intlclock_location_is_current (IntlClockLocation *loc); -+gboolean intlclock_location_make_current (IntlClockLocation *loc, GError **error); -+ -+const gchar *intlclock_location_get_weather_code (IntlClockLocation *loc); -+void intlclock_location_set_weather_code (IntlClockLocation *loc, const gchar *code); -+WeatherInfo *intlclock_location_get_weather_info (IntlClockLocation *loc); -+ -+glong intlclock_location_get_offset (IntlClockLocation *loc); -+ - G_END_DECLS - #endif /* __INTLCLOCK_LOCATION_H__ */ -diff --git a/src/intlclock-map.c b/src/intlclock-map.c -index 2d72975..9ded127 100644 ---- a/src/intlclock-map.c -+++ b/src/intlclock-map.c -@@ -25,7 +25,7 @@ typedef struct { - gint height; - - GdkPixbuf *stock_map_pixbuf; -- GdkPixbuf *location_marker_pixbuf; -+ GdkPixbuf *location_marker_pixbuf[3]; - - GdkPixbuf *location_map_pixbuf; - -@@ -54,6 +54,7 @@ static void intlclock_map_display (IntlClockMap *this); - - - static void intlclock_map_locations_changed (IntlClock *clock, IntlClockMap *this); -+static void intlclock_map_blink_location (IntlClock *clock, IntlClockLocation *loc, IntlClockMap *this); - static void intlclock_map_tick (IntlClock *clock, IntlClockMap *this); - - #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INTLCLOCK_MAP_TYPE, IntlClockMapPrivate)) -@@ -69,8 +70,12 @@ intlclock_map_new (IntlClock *clock) - - priv->clock = g_object_ref (clock); - -- priv->location_marker_pixbuf = rsvg_pixbuf_from_file -- (INTLCLOCK_ICONDIR "/intlclock-map-location-marker.svg", NULL); -+ priv->location_marker_pixbuf[0] = gdk_pixbuf_new_from_file -+ (INTLCLOCK_ICONDIR "/intlclock-map-location-marker.png", NULL); -+ priv->location_marker_pixbuf[1] = gdk_pixbuf_new_from_file -+ (INTLCLOCK_ICONDIR "/intlclock-map-location-hilight.png", NULL); -+ priv->location_marker_pixbuf[2] = gdk_pixbuf_new_from_file -+ (INTLCLOCK_ICONDIR "/intlclock-map-location-current.png", NULL); - - g_signal_connect (G_OBJECT (priv->clock), "tick", - G_CALLBACK (intlclock_map_tick), this); -@@ -78,6 +83,12 @@ intlclock_map_new (IntlClock *clock) - g_signal_connect (G_OBJECT (priv->clock), "locations_changed", - G_CALLBACK (intlclock_map_locations_changed), this); - -+ g_signal_connect (G_OBJECT (priv->clock), "current_timezone_changed", -+ G_CALLBACK (intlclock_map_locations_changed), this); -+ -+ g_signal_connect (G_OBJECT (priv->clock), "blink_location", -+ G_CALLBACK (intlclock_map_blink_location), this); -+ - intlclock_map_refresh (this); - - return this; -@@ -109,13 +120,16 @@ intlclock_map_init (IntlClockMap *this) - priv->clock = NULL; - - priv->stock_map_pixbuf = NULL; -- priv->location_marker_pixbuf = NULL; -+ priv->location_marker_pixbuf[0] = NULL; -+ priv->location_marker_pixbuf[1] = NULL; -+ priv->location_marker_pixbuf[2] = NULL; - } - - static void - intlclock_map_finalize (GObject *g_obj) - { - IntlClockMapPrivate *priv = PRIVATE (g_obj); -+ int i; - - g_signal_handlers_disconnect_by_func - (priv->clock, G_CALLBACK (intlclock_map_tick), g_obj); -@@ -130,10 +144,12 @@ intlclock_map_finalize (GObject *g_obj) - priv->stock_map_pixbuf = NULL; - } - -- if (priv->location_marker_pixbuf) { -- gdk_pixbuf_unref (priv->location_marker_pixbuf); -- priv->location_marker_pixbuf = NULL; -- } -+ for (i = 0; i < 3; i++) { -+ if (priv->location_marker_pixbuf[i]) { -+ gdk_pixbuf_unref (priv->location_marker_pixbuf[i]); -+ priv->location_marker_pixbuf[i] = NULL; -+ } -+ } - - if (priv->location_map_pixbuf) { - gdk_pixbuf_unref (priv->location_map_pixbuf); -@@ -164,12 +180,13 @@ intlclock_map_refresh (IntlClockMap *this) - IntlClockMapPrivate *priv = PRIVATE (this); - GtkWidget *widget = GTK_WIDGET (this); - GtkWidget *parent = gtk_widget_get_parent (widget); -+ GtkRequisition req; - gint width; - gint height; - -- gtk_widget_size_request (widget, &(widget->requisition)); -- width = widget->requisition.width; -- height = widget->requisition.height; -+ gtk_widget_size_request (widget, &req); -+ width = req.width; -+ height = req.height; - - if (parent) { - if (widget->allocation.width != 1) { -@@ -276,10 +293,10 @@ intlclock_map_size_allocate (GtkWidget *this, GtkAllocation *allocation) - } - - static void --intlclock_map_mark (IntlClockMap *this, gfloat latitude, gfloat longitude) -+intlclock_map_mark (IntlClockMap *this, gfloat latitude, gfloat longitude, gint mark) - { - IntlClockMapPrivate *priv = PRIVATE (this); -- GdkPixbuf *marker = priv->location_marker_pixbuf; -+ GdkPixbuf *marker = priv->location_marker_pixbuf[mark]; - GdkPixbuf *partial = NULL; - - int x, y; -@@ -395,14 +412,22 @@ intlclock_map_mark (IntlClockMap *this, gfloat latitude, gfloat longitude) - } - - static void --intlclock_map_place_location (IntlClockMap *this, IntlClockLocation *loc) -+intlclock_map_place_location (IntlClockMap *this, IntlClockLocation *loc, gboolean hilight) - { - IntlClockMapPrivate *priv = PRIVATE (this); - gfloat latitude, longitude; -+ gint marker; - - intlclock_location_get_coords (loc, &latitude, &longitude); - -- intlclock_map_mark (this, latitude, longitude); -+ if (hilight) -+ marker = 1; -+ else if (intlclock_location_is_current (loc)) -+ marker = 2; -+ else -+ marker = 0; -+ -+ intlclock_map_mark (this, latitude, longitude, marker); - } - - static void -@@ -428,7 +453,7 @@ intlclock_map_place_locations (IntlClockMap *this) - while (locs) { - loc = INTLCLOCK_LOCATION (locs->data); - -- intlclock_map_place_location (this, loc); -+ intlclock_map_place_location (this, loc, FALSE); - - locs = locs->next; - } -@@ -633,16 +658,12 @@ intlclock_map_rotate (IntlClockMap *this) - static void - intlclock_map_display (IntlClockMap *this) - { -- IntlClockMapPrivate *priv = PRIVATE (this); -- - gtk_widget_queue_draw (GTK_WIDGET (this)); - } - - static void - intlclock_map_locations_changed (IntlClock *clock, IntlClockMap *this) - { -- IntlClockMapPrivate *priv = PRIVATE (this); -- - intlclock_map_place_locations (this); - - intlclock_map_render_shadow (this); -@@ -651,6 +672,49 @@ intlclock_map_locations_changed (IntlClock *clock, IntlClockMap *this) - intlclock_map_display (this); - } - -+typedef struct { -+ IntlClockMap *map; -+ IntlClockLocation *location; -+ int count; -+} BlinkData; -+ -+static gboolean -+highlight (gpointer user_data) -+{ -+ BlinkData *data = user_data; -+ -+ if (data->count == 6) { -+ g_free (data); -+ return FALSE; -+ } -+ -+ if (data->count % 2 == 0) -+ intlclock_map_place_location (data->map, data->location, TRUE); -+ else -+ intlclock_map_place_locations (data->map); -+ intlclock_map_render_shadow (data->map); -+ intlclock_map_rotate (data->map); -+ intlclock_map_display (data->map); -+ -+ data->count++; -+ -+ return TRUE; -+} -+ -+static void -+intlclock_map_blink_location (IntlClock *clock, IntlClockLocation *loc, IntlClockMap *this) -+{ -+ BlinkData *data; -+ -+ data = g_new0 (BlinkData, 1); -+ data->map = this; -+ data->location = loc; -+ -+ highlight (data); -+ -+ g_timeout_add (300, highlight, data); -+} -+ - static gboolean - intlclock_map_needs_refresh (IntlClockMap *this) - { -diff --git a/src/intlclock-marshallers.c b/src/intlclock-marshallers.c -deleted file mode 100644 -index 8f01ab8..0000000 ---- a/src/intlclock-marshallers.c -+++ /dev/null -@@ -1,51 +0,0 @@ -- --#include -- -- --#ifdef G_ENABLE_DEBUG --#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) --#define g_marshal_value_peek_char(v) g_value_get_char (v) --#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) --#define g_marshal_value_peek_int(v) g_value_get_int (v) --#define g_marshal_value_peek_uint(v) g_value_get_uint (v) --#define g_marshal_value_peek_long(v) g_value_get_long (v) --#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) --#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) --#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) --#define g_marshal_value_peek_enum(v) g_value_get_enum (v) --#define g_marshal_value_peek_flags(v) g_value_get_flags (v) --#define g_marshal_value_peek_float(v) g_value_get_float (v) --#define g_marshal_value_peek_double(v) g_value_get_double (v) --#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) --#define g_marshal_value_peek_param(v) g_value_get_param (v) --#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) --#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) --#define g_marshal_value_peek_object(v) g_value_get_object (v) --#else /* !G_ENABLE_DEBUG */ --/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. -- * Do not access GValues directly in your code. Instead, use the -- * g_value_get_*() functions -- */ --#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int --#define g_marshal_value_peek_char(v) (v)->data[0].v_int --#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint --#define g_marshal_value_peek_int(v) (v)->data[0].v_int --#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint --#define g_marshal_value_peek_long(v) (v)->data[0].v_long --#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong --#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 --#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 --#define g_marshal_value_peek_enum(v) (v)->data[0].v_long --#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong --#define g_marshal_value_peek_float(v) (v)->data[0].v_float --#define g_marshal_value_peek_double(v) (v)->data[0].v_double --#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer --#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer --#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer --#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer --#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer --#endif /* !G_ENABLE_DEBUG */ -- -- --/* VOID:VOID (intlclock-marshallers.list:1) */ -- -diff --git a/src/intlclock-marshallers.h b/src/intlclock-marshallers.h -deleted file mode 100644 -index c022a3e..0000000 ---- a/src/intlclock-marshallers.h -+++ /dev/null -@@ -1,15 +0,0 @@ -- --#ifndef ___intlclock_marshal_MARSHAL_H__ --#define ___intlclock_marshal_MARSHAL_H__ -- --#include -- --G_BEGIN_DECLS -- --/* VOID:VOID (intlclock-marshallers.list:1) */ --#define _intlclock_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID -- --G_END_DECLS -- --#endif /* ___intlclock_marshal_MARSHAL_H__ */ -- -diff --git a/src/intlclock-marshallers.list b/src/intlclock-marshallers.list -index 5b76282..e737cac 100644 ---- a/src/intlclock-marshallers.list -+++ b/src/intlclock-marshallers.list -@@ -1 +1,3 @@ - VOID:VOID -+VOID:OBJECT -+VOID:POINTER -diff --git a/src/intlclock-sunpos.c b/src/intlclock-sunpos.c -index 942617b..89d4cc1 100644 ---- a/src/intlclock-sunpos.c -+++ b/src/intlclock-sunpos.c -@@ -1,348 +1,196 @@ - /* -- * sunpos.c -- * kirk johnson -- * july 1993 -+ * Copyright (C) 2007 Red Hat, Inc. - * -- * includes revisions from Frank T. Solensky, february 1999 -+ * 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. - * -- * code for calculating the position on the earth's surface for which -- * the sun is directly overhead (adapted from _practical astronomy -- * with your calculator, third edition_, peter duffett-smith, -- * cambridge university press, 1988.) -+ * 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. - * -- * Copyright (C) 1989, 1990, 1993-1995, 1999 Kirk Lauritz Johnson -+ * 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. - * -- * Parts of the source code (as marked) are: -- * Copyright (C) 1989, 1990, 1991 by Jim Frost -- * Copyright (C) 1992 by Jamie Zawinski -- * -- * Permission to use, copy, modify and freely distribute xearth for -- * non-commercial and not-for-profit purposes is hereby granted -- * without fee, provided that both the above copyright notice and this -- * permission notice appear in all copies and in supporting -- * documentation. -- * -- * Unisys Corporation holds worldwide patent rights on the Lempel Zev -- * Welch (LZW) compression technique employed in the CompuServe GIF -- * image file format as well as in other formats. Unisys has made it -- * clear, however, that it does not require licensing or fees to be -- * paid for freely distributed, non-commercial applications (such as -- * xearth) that employ LZW/GIF technology. Those wishing further -- * information about licensing the LZW patent should contact Unisys -- * directly at (lzw_info@unisys.com) or by writing to -- * -- * Unisys Corporation -- * Welch Licensing Department -- * M/S-C1SW19 -- * P.O. Box 500 -- * Blue Bell, PA 19424 -- * -- * The author makes no representations about the suitability of this -- * software for any purpose. It is provided "as is" without express or -- * implied warranty. -- * -- * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, -- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT -- * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ * Authors: -+ * Jonathan Blandford -+ * Matthias Clasen - */ -- --#include --#include -+ - #include -+#include -+#include - --#include "intlclock-sunpos.h" -- --#define TWOPI (2*M_PI) --#define DegsToRads(x) ((x)*(TWOPI/360)) -- --/* -- * the epoch upon which these astronomical calculations are based is -- * 1990 january 0.0, 631065600 seconds since the beginning of the -- * "unix epoch" (00:00:00 GMT, Jan. 1, 1970) -- * -- * given a number of seconds since the start of the unix epoch, -- * DaysSinceEpoch() computes the number of days since the start of the -- * astronomical epoch (1990 january 0.0) -- */ -- --#define EpochStart (631065600) --#define DaysSinceEpoch(secs) (((secs)-EpochStart)*(1.0/(24*3600))) -- --/* -- * assuming the apparent orbit of the sun about the earth is circular, -- * the rate at which the orbit progresses is given by RadsPerDay -- -- * TWOPI radians per orbit divided by 365.242191 days per year: -- */ -- --#define RadsPerDay (TWOPI/365.242191) -- --/* -- * details of sun's apparent orbit at epoch 1990.0 (after -- * duffett-smith, table 6, section 46) -- * -- * Epsilon_g (ecliptic longitude at epoch 1990.0) 279.403303 degrees -- * OmegaBar_g (ecliptic longitude of perigee) 282.768422 degrees -- * Eccentricity (eccentricity of orbit) 0.016713 -+/* 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 orbit at epoch 1990.0 */ - --#define Epsilon_g (DegsToRads(279.403303)) --#define OmegaBar_g (DegsToRads(282.768422)) --#define Eccentricity (0.016713) -+#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 perigree */ -+#define ECCENTRICITY 0.016713 /* eccentricity of orbit */ -+#define R_0 149598500 /* km */ /* semi-major access */ -+#define THETA_0 0.533128 /* degrees */ /* angular diameter at r = r_0 */ -+#define MEAN_OBLIQUITY 23.440592 /* degrees */ /* mean obliquity of earths axis at epoch 1990.0 */ - --/* -- * MeanObliquity gives the mean obliquity of the earth's axis at epoch -- * 1990.0 (computed as 23.440592 degrees according to the method given -- * in duffett-smith, section 27) -- */ --#define MeanObliquity (23.440592*(TWOPI/360)) -+#define NORMALIZE(x) \ -+ while (x>360) x-=360; while (x<0) x+= 360; - --/* -- * Lunar parameters, epoch January 0, 1990.0 -- */ --#define MoonMeanLongitude DegsToRads(318.351648) --#define MoonMeanLongitudePerigee DegsToRads( 36.340410) --#define MoonMeanLongitudeNode DegsToRads(318.510107) --#define MoonInclination DegsToRads( 5.145396) -+#define DEG_TO_RADS(x) \ -+ (x * G_PI/180.0) - --#define SideralMonth (27.3217) -+#define RADS_TO_DEG(x) \ -+ (x * 180.0/G_PI) - --/* -- * Force an angular value into the range [-PI, +PI] -+/* Calculate number of days since 4713BC. - */ --#define Normalize(x) \ -- do { \ -- if ((x) < -M_PI) \ -- do (x) += TWOPI; while ((x) < -M_PI); \ -- else if ((x) > M_PI) \ -- do (x) -= TWOPI; while ((x) > M_PI); \ -- } while (0) -- --static double solve_keplers_equation (double); --static double mean_sun (double); --static double sun_ecliptic_longitude (time_t); --static void ecliptic_to_equatorial (double, double, double *, double *); --static double julian_date (int, int, int); --static double GST (time_t); -- --/* -- * solve Kepler's equation via Newton's method -- * (after duffett-smith, section 47) -- */ --static double solve_keplers_equation(M) -- double M; -+static gdouble -+unix_time_to_julian_date (gint unix_time) - { -- double E; -- double delta; -- -- E = M; -- while (1) -- { -- delta = E - Eccentricity*sin(E) - M; -- if (fabs(delta) <= 1e-10) break; -- E -= delta / (1 - Eccentricity*cos(E)); -- } -- -- return E; -+ 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 */ - --/* -- * Calculate the position of the mean sun: where the sun would -- * be if the earth's orbit were circular instead of ellipictal. -- */ -+#define ERROR_ACCURACY 1e-6 /* radians */ - --static double mean_sun (D) -- double D; /* days since ephemeris epoch */ -+static gdouble -+solve_keplers_equation (gdouble e, -+ gdouble M) - { -- double N, M; -+ gdouble d, E; - -- N = RadsPerDay * D; -- N = fmod(N, TWOPI); -- if (N < 0) N += TWOPI; -+ /* 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; -+ } - -- M = N + Epsilon_g - OmegaBar_g; -- if (M < 0) M += TWOPI; -- return M; -+ return E; - } - --/* -- * compute ecliptic longitude of sun (in radians) -- * (after duffett-smith, section 47) -- */ --static double sun_ecliptic_longitude(ssue) -- time_t ssue; /* seconds since unix epoch */ -+ /* convert the ecliptic longitude to right ascension and declination. Section 27. */ -+static void -+ecliptic_to_equatorial (gdouble lambda, -+ gdouble beta, -+ gdouble *ra, -+ gdouble *dec) - { -- double D; -- double M_sun, E; -- double v; -+ gdouble cos_mo; -+ gdouble sin_mo; - -- D = DaysSinceEpoch(ssue); -- M_sun = mean_sun(D); -+ g_assert (ra != NULL); -+ g_assert (dec != NULL); - -- E = solve_keplers_equation(M_sun); -- v = 2 * atan(sqrt((1+Eccentricity)/(1-Eccentricity)) * tan(E/2)); -+ sin_mo = sin (DEG_TO_RADS (MEAN_OBLIQUITY)); -+ cos_mo = cos (DEG_TO_RADS (MEAN_OBLIQUITY)); - -- return (v + OmegaBar_g); -+ *ra = atan2 (sin (lambda) * cos_mo - tan (beta) * sin_mo, cos (lambda)); -+ *dec = asin (sin (beta) * cos_mo + cos (beta) * sin_mo * sin (lambda)); - } - -- --/* -- * convert from ecliptic to equatorial coordinates -- * (after duffett-smith, section 27) -- */ --static void ecliptic_to_equatorial(lambda, beta, alpha, delta) -- double lambda; /* ecliptic longitude */ -- double beta; /* ecliptic latitude */ -- double *alpha; /* (return) right ascension */ -- double *delta; /* (return) declination */ -+/* calculate GST. Section 12 */ -+static gdouble -+greenwich_sidereal_time (gdouble unix_time) - { -- double sin_e, cos_e; -+ gdouble u, JD, T, T0, UT; - -- sin_e = sin(MeanObliquity); -- cos_e = cos(MeanObliquity); -+ 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); - -- *alpha = atan2(sin(lambda)*cos_e - tan(beta)*sin_e, cos(lambda)); -- *delta = asin(sin(beta)*cos_e + cos(beta)*sin_e*sin(lambda)); -+ return T0; - } - -- --/* -- * computing julian dates (assuming gregorian calendar, thus this is -- * only valid for dates of 1582 oct 15 or later) -- * (after duffett-smith, section 4) -- */ --static double julian_date(y, m, d) -- int y; /* year (e.g. 19xx) */ -- int m; /* month (jan=1, feb=2, ...) */ -- int d; /* day of month */ -+/* Calculate the position of the sun at a given time. pages 89-91 */ -+void -+sun_position (gint unix_time, gdouble *lat, gdouble *lon) - { -- int A, B, C, D; -- double JD; -+ gdouble jd, D, N, M, E, x, v, lambda; -+ gdouble ra, dec; -+ jd = unix_time_to_julian_date (unix_time); - -- /* lazy test to ensure gregorian calendar */ -- assert(y >= 1583); -+ /* Calculate number of days since the epoch */ -+ D = jd - EPOCH; - -- if ((m == 1) || (m == 2)) -- { -- y -= 1; -- m += 12; -- } -+ N = D*360/365.242191; - -- A = y / 100; -- B = 2 - A + (A / 4); -- C = 365.25 * y; -- D = 30.6001 * (m + 1); -+ /* normalize to 0 - 360 degrees */ -+ NORMALIZE (N); - -- JD = B + C + D + d + 1720994.5; -+ /* Step 4: */ -+ M = N + EPSILON_G - MU_G; -+ NORMALIZE (M); - -- return JD; --} -- -- --/* -- * compute greenwich mean sidereal time (GST) corresponding to a given -- * number of seconds since the unix epoch -- * (after duffett-smith, section 12) -- */ --static double GST(ssue) -- time_t ssue; /* seconds since unix epoch */ --{ -- double JD; -- double T, T0; -- double UT; -- struct tm *tm; -+ /* Step 5: convert to radians */ -+ M = DEG_TO_RADS (M); - -- tm = gmtime(&ssue); -+ /* Step 6: */ -+ E = solve_keplers_equation (ECCENTRICITY, M); - -- JD = julian_date(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday); -- T = (JD - 2451545) / 36525; -+ /* Step 7: */ -+ x = sqrt ((1 + ECCENTRICITY)/(1 - ECCENTRICITY)) * tan (E/2); - -- T0 = ((T + 2.5862e-5) * T + 2400.051336) * T + 6.697374558; -+ /* Step 8, 9 */ -+ v = 2 * RADS_TO_DEG (atan (x)); -+ NORMALIZE (v); - -- T0 = fmod(T0, 24.0); -- if (T0 < 0) T0 += 24; -+ /* Step 10 */ -+ lambda = v + MU_G; -+ NORMALIZE (lambda); - -- UT = tm->tm_hour + (tm->tm_min + tm->tm_sec / 60.0) / 60.0; -+ /* convert the ecliptic longitude to right ascension and declination */ -+ ecliptic_to_equatorial (DEG_TO_RADS (lambda), 0.0, &ra, &dec); - -- T0 += UT * 1.002737909; -- T0 = fmod(T0, 24.0); -- if (T0 < 0) T0 += 24; -+ ra = ra - (G_PI/12) * greenwich_sidereal_time (unix_time); -+ ra = RADS_TO_DEG (ra); -+ dec = RADS_TO_DEG (dec); -+ NORMALIZE (ra); -+ NORMALIZE (dec); - -- return T0; -+ *lat = dec; -+ *lon = ra; - } - - --/* -- * given a particular time (expressed in seconds since the unix -- * epoch), compute position on the earth (lat, lon) such that sun is -- * directly overhead. -- */ --void sun_position(ssue, lat, lon) -- time_t ssue; /* seconds since unix epoch */ -- double *lat; /* (return) latitude */ -- double *lon; /* (return) longitude */ -+#if 0 -+int -+main (int argc, char *argv[]) - { -- double lambda; -- double alpha, delta; -- double tmp; -+ gint i; -+ gint now; -+ GTimeVal timeval; -+ gdouble lat, lon; - -- lambda = sun_ecliptic_longitude(ssue); -- ecliptic_to_equatorial(lambda, 0.0, &alpha, &delta); -+ gtk_init (&argc, &argv); - -- tmp = alpha - (TWOPI/24)*GST(ssue); -- Normalize(tmp); -- *lon = tmp * (360/TWOPI); -- *lat = delta * (360/TWOPI); --} -+ 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); -+ } - --/* -- * given a particular time (expressed in seconds since the unix -- * epoch), compute position on the earth (lat, lon) such that the -- * moon is directly overhead. -- * -- * Based on duffett-smith **2nd ed** section 61; combines some steps -- * into single expressions to reduce the number of extra variables. -- */ --void moon_position(ssue, lat, lon) -- time_t ssue; /* seconds since unix epoch */ -- double *lat; /* (return) latitude */ -- double *lon; /* (return) longitude */ --{ -- double lambda, beta; -- double D, L, Ms, Mm, N, Ev, Ae, Ec, alpha, delta; -- -- D = DaysSinceEpoch(ssue); -- lambda = sun_ecliptic_longitude(ssue); -- Ms = mean_sun(D); -- -- L = fmod(D/SideralMonth, 1.0)*TWOPI + MoonMeanLongitude; -- Normalize(L); -- Mm = L - DegsToRads(0.1114041*D) - MoonMeanLongitudePerigee; -- Normalize(Mm); -- N = MoonMeanLongitudeNode - DegsToRads(0.0529539*D); -- Normalize(N); -- Ev = DegsToRads(1.2739) * sin(2.0*(L-lambda)-Mm); -- Ae = DegsToRads(0.1858) * sin(Ms); -- Mm += Ev - Ae - DegsToRads(0.37)*sin(Ms); -- Ec = DegsToRads(6.2886) * sin(Mm); -- L += Ev + Ec - Ae + DegsToRads(0.214) * sin(2.0*Mm); -- L += DegsToRads(0.6583) * sin(2.0*(L-lambda)); -- N -= DegsToRads(0.16) * sin(Ms); -- -- L -= N; -- lambda =(fabs(cos(L)) < 1e-12) ? -- (N + sin(L) * cos(MoonInclination) * M_PI/2) : -- (N + atan2(sin(L) * cos(MoonInclination), cos(L))); -- Normalize(lambda); -- beta = asin(sin(L) * sin(MoonInclination)); -- ecliptic_to_equatorial(lambda, beta, &alpha, &delta); -- alpha -= (TWOPI/24)*GST(ssue); -- Normalize(alpha); -- *lon = alpha * (360/TWOPI); -- *lat = delta * (360/TWOPI); -+ return 0; - } -+ -+#endif -diff --git a/src/intlclock-ui.c b/src/intlclock-ui.c -index f51e4de..f0d70bd 100644 ---- a/src/intlclock-ui.c -+++ b/src/intlclock-ui.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -26,18 +27,18 @@ - #include "intlclock-map.h" - #include "intlclock-zoneinfo.h" - #include "intlclock-zonetable.h" -+#include "set-timezone.h" -+#include "gweather-xml.h" - - G_DEFINE_TYPE (IntlClockUI, intlclock_ui, G_TYPE_OBJECT) - - /* GConf keys for compatibility with the older GNOME clock */ --#define N_GCONF_PREFS 7 -+#define N_GCONF_PREFS 5 - static const char *KEY_CITIES = "cities"; - static const char *KEY_FORMAT = "format"; - static const char *KEY_SHOW_SECONDS = "show_seconds"; - static const char *KEY_SHOW_DATE = "show_date"; - static const char *KEY_SHOW_WEEK = "show_week_numbers"; --static const char *KEY_SHOW_LOCATIONS = "show_locations"; --static const char *KEY_SHOW_MAP = "show_map"; - - /* Needs to match the indices in the combo */ - typedef enum { -@@ -78,12 +79,14 @@ typedef struct { - GtkWidget *panel_box; - GtkWidget *panel_button; - GtkWidget *panel_label; -+ GtkWidget *panel_weather_icon; - - GtkTooltips *panel_tips; - - GtkWidget *panel_button_popup; - - GtkWidget *clock_vbox; -+ GtkSizeGroup *clock_group; - - GtkWidget *main_section; - GtkWidget *clock_calendar; -@@ -97,17 +100,34 @@ typedef struct { - - GtkListStore *cities_store; - -- gboolean show_locations; -- gboolean show_map; -- - GtkWidget *prefs_window; - GtkTreeView *prefs_locations; - -+ GtkWidget *prefs_location_add_button; -+ GtkWidget *prefs_location_edit_button; -+ GtkWidget *prefs_location_remove_button; -+ -+ GtkWidget *location_tree; -+ GtkWidget *find_next_location_button; -+ GtkWidget *find_location_entry; -+ GtkWidget *find_location_ok_button; -+ -+ GtkWidget *set_time_window; -+ GtkWidget *hours_spin; -+ GtkWidget *minutes_spin; -+ GtkWidget *seconds_spin; -+ GtkWidget *calendar; -+ GtkWidget *current_time_label; -+ GtkWidget *set_time_button; -+ GtkWidget *time_settings_button; -+ - gboolean format_12hr; - gboolean format_show_seconds; - gboolean format_show_date; - gboolean format_show_week; - -+ gulong zone_combo_changed; -+ - guint listeners [N_GCONF_PREFS]; - } IntlClockUIPrivate; - -@@ -118,51 +138,51 @@ static gboolean update_panel_label (gpointer this); - static void setup_gconf (IntlClockUI *this); - static void load_gconf_settings (IntlClockUI *this); - --static void bonobo_run_time_configuration (BonoboUIComponent *uic, -- IntlClockUI *this, -- const gchar *verbname); - static void bonobo_display_properties_dialog (BonoboUIComponent *uic, - IntlClockUI *this, - const gchar *verbname); --static void display_help_dialog (BonoboUIComponent *uic, -- IntlClockUI *this, -- const gchar *verbname); --static void display_about_dialog (BonoboUIComponent *uic, -- IntlClockUI *this, -- const gchar *verbname); -- --static void config_date (BonoboUIComponent *uic, -- IntlClockUI *this, -- const gchar *verbname); - - static void intlclock_reposition_events_window (IntlClockUI *this); -- - static void position_popup_window (IntlClockUI *this, - GtkWindow *window, - GtkWidget *origin); - --static void display_prefs_window_cb (GtkButton *button, gpointer this); --static void run_time_configuration (IntlClockUI *this); --static void run_time_configuration_cb (GtkButton *button, gpointer this); -+static void display_prefs_window (IntlClockUI *this, gboolean locations); - static void run_prefs_locations_add (GtkButton *button, gpointer this); - static void run_prefs_locations_edit (GtkButton *button, gpointer this); - static void run_prefs_locations_remove (GtkButton *button, gpointer this); - static void run_prefs_edit_save (GtkButton *button, gpointer this); -- -+static void run_find_location (GtkButton *button, gpointer this); -+static void run_find_location_save (GtkButton *button, gpointer this); -+static void intlclock_edit_hide (GtkWidget *widget, IntlClockUI *this); -+static void intlclock_find_hide (GtkWidget *widget, IntlClockUI *this); - static void intlclock_ui_save_cities_store (IntlClockUI *this); - - static void intlclock_ui_locations_changed (IntlClock *clock, IntlClockUI *this); - - static void create_cities_section (IntlClockUI *this); - static void create_events_window (IntlClockUI *this); --static void create_main_section (IntlClockUI *this); - static void create_map_section (IntlClockUI *this); - - static void zone_combo_changed (GtkComboBox *widget, gpointer this); -+static void update_coords (IntlClockUI *this, gboolean valid, gfloat lat, gfloat lon); -+static void fill_location_tree (IntlClockUI *this); -+static void copy_time (BonoboUIComponent *uic, -+ IntlClockUI *this, -+ const gchar *verbname); -+static void copy_date (BonoboUIComponent *uic, -+ IntlClockUI *this, -+ const gchar *verbname); -+static void config_date (BonoboUIComponent *uic, -+ IntlClockUI *this, -+ const gchar *verbname); -+ - - static const BonoboUIVerb intlclock_menu_verbs [] = { - BONOBO_UI_UNSAFE_VERB ("IntlClockPreferences", bonobo_display_properties_dialog), -- BONOBO_UI_UNSAFE_VERB ("IntlClockConfig", bonobo_run_time_configuration), -+ BONOBO_UI_UNSAFE_VERB ("ClockCopyTime", copy_time), -+ BONOBO_UI_UNSAFE_VERB ("ClockCopyDate", copy_date), -+ BONOBO_UI_UNSAFE_VERB ("ClockConfig", config_date), - BONOBO_UI_VERB_END - }; - -@@ -190,11 +210,6 @@ intlclock_ui_is_12hr (IntlClockUI *this) - static gboolean - panel_button_press_cb (GtkWidget *button, GdkEventButton *event, gpointer data) - { -- IntlClockUI *this = INTLCLOCK_UI (data); -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (button); -- - if (event->button != 1) - g_signal_stop_emission_by_name (button, "button_press_event"); - -@@ -206,7 +221,9 @@ intlclock_ui_reset_timeout (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); - -- if (GTK_WIDGET_VISIBLE (priv->events_window) || priv->format_show_seconds) { -+ if (GTK_WIDGET_VISIBLE (priv->events_window) || -+ (priv->set_time_window && GTK_WIDGET_VISIBLE (priv->set_time_window)) || -+ priv->format_show_seconds) { - intlclock_set_tick_timeout (INTLCLOCK (priv->clock), 1); - } else { - intlclock_set_tick_timeout (INTLCLOCK (priv->clock), 60); -@@ -244,20 +261,6 @@ panel_button_clicked_cb (GtkButton *button, gpointer data) - intlclock_ui_reset_timeout (this); - } - --static gboolean --panel_events_button_press_cb (GtkWidget *button, GdkEventButton *event, gpointer data) --{ -- IntlClockUI *this = INTLCLOCK_UI (data); -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (button); -- -- if (event->button != 1) -- g_signal_stop_emission_by_name (button, "button_press_event"); -- -- return FALSE; --} -- - static void - position_popup_window (IntlClockUI *this, - GtkWindow *window, -@@ -375,147 +378,6 @@ intlclock_events_window_size_allocate_cb (GtkWidget *widget, GtkAllocation *allo - intlclock_reposition_events_window (this); - } - --static gboolean --intlclock_window_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) --{ -- IntlClockUIPrivate *priv = PRIVATE (user_data); -- -- cairo_t *cr; -- -- cr = gdk_cairo_create (widget->window); -- -- cairo_rectangle ( -- cr, -- event->area.x, event->area.y, -- event->area.width, event->area.height); -- -- cairo_clip (cr); -- --/* draw window background */ -- -- cairo_rectangle ( -- cr, -- widget->allocation.x + 0.5, widget->allocation.y + 0.5, -- widget->allocation.width - 1, widget->allocation.height - 1); -- -- cairo_set_source_rgb ( -- cr, -- widget->style->bg [GTK_STATE_ACTIVE].red / 65535.0, -- widget->style->bg [GTK_STATE_ACTIVE].green / 65535.0, -- widget->style->bg [GTK_STATE_ACTIVE].blue / 65535.0); -- -- cairo_fill_preserve (cr); -- --/* draw window outline */ -- -- cairo_set_source_rgb ( -- cr, -- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); -- -- cairo_set_line_width (cr, 1.0); -- cairo_stroke (cr); -- --/* draw main pane background */ -- -- cairo_rectangle ( -- cr, -- priv->main_section->allocation.x + 0.5, priv->main_section->allocation --.y + 0.5, -- priv->main_section->allocation.width - 1, priv->main_section->allocation.height - 1); -- -- cairo_set_source_rgb ( -- cr, -- widget->style->bg [GTK_STATE_NORMAL].red / 65535.0, -- widget->style->bg [GTK_STATE_NORMAL].green / 65535.0, -- widget->style->bg [GTK_STATE_NORMAL].blue / 65535.0); -- -- cairo_fill (cr); -- --/* draw map pane background */ -- -- if (priv->show_map) { -- cairo_rectangle ( -- cr, -- priv->map_section->allocation.x + 0.5, -- priv->map_section->allocation.y + 0.5, -- priv->map_section->allocation.width - 1, -- priv->map_section->allocation.height - 1); -- -- cairo_set_source_rgb ( -- cr, -- widget->style->bg [GTK_STATE_NORMAL].red / 65535.0, -- widget->style->bg [GTK_STATE_NORMAL].green / 65535.0, -- widget->style->bg [GTK_STATE_NORMAL].blue / 65535.0); -- -- cairo_fill (cr); -- } -- --/* draw internal window outline */ -- -- cairo_rectangle ( -- cr, -- priv->clock_vbox->allocation.x + 0.5, priv->clock_vbox->allocation.y + 0.5, -- priv->clock_vbox->allocation.width - 1, priv->clock_vbox->allocation.height - 1); -- -- cairo_set_source_rgb ( -- cr, -- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); -- -- cairo_stroke (cr); -- --/* draw map/cities pane separator */ -- -- if (priv->show_map) { -- cairo_move_to ( -- cr, -- priv->map_section->allocation.x + 0.5, -- priv->map_section->allocation.y + priv->map_section->allocation.height - 0.5); -- -- cairo_line_to ( -- cr, -- priv->map_section->allocation.x + priv->map_section->allocation.width - 0.5, -- priv->map_section->allocation.y + priv->map_section->allocation.height - 0.5); -- -- cairo_set_source_rgb ( -- cr, -- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); -- -- cairo_stroke (cr); -- } -- --/* draw cities/main pane separator */ -- -- if (priv->show_locations) { -- cairo_move_to ( -- cr, -- priv->cities_section->allocation.x + 0.5, -- priv->cities_section->allocation.y + priv->cities_section->allocation.height - 0.5); -- -- cairo_line_to ( -- cr, -- priv->cities_section->allocation.x + priv->cities_section->allocation.width - 0.5, -- priv->cities_section->allocation.y + priv->cities_section->allocation.height - 0.5); -- -- cairo_set_source_rgb ( -- cr, -- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, -- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); -- -- cairo_stroke (cr); -- } -- -- cairo_destroy (cr); -- -- return FALSE; --} -- - static void - intlclock_ui_tick (IntlClock *clock, IntlClockUI *this) - { -@@ -529,10 +391,7 @@ intlclock_ui_tick (IntlClock *clock, IntlClockUI *this) - static void - intlclock_ui_locations_changed (IntlClock *clock, IntlClockUI *this) - { -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- create_cities_section (this); -- intlclock_map_refresh (INTLCLOCK_MAP (priv->map_widget)); -+ create_cities_section (this); - } - - static gboolean -@@ -550,12 +409,20 @@ update_panel_label (gpointer this) - time (&now_t); - localtime_r (&now_t, &now); - -+ if (priv->current_time_label && -+ GTK_WIDGET_VISIBLE (priv->current_time_label)) { -+ date = intlclock_format_time (priv->clock, &now, -+ FALSE, FALSE, TRUE, -+ FALSE, FALSE, NULL, TRUE); -+ gtk_label_set_markup (GTK_LABEL (priv->current_time_label), date); -+ g_free (date); -+ } -+ - date = intlclock_format_time (priv->clock, &now, - priv->format_show_date, - priv->format_12hr, - priv->format_show_seconds, - FALSE, priv->format_show_date, NULL, TRUE); -- - gtk_label_set_markup (GTK_LABEL (priv->panel_label), date); - g_free (date); - -@@ -583,6 +450,7 @@ create_panel_buttons (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); - PanelAppletOrient orient; -+ GtkWidget *box; - - orient = panel_applet_get_orient (priv->panel_applet); - -@@ -590,13 +458,18 @@ create_panel_buttons (IntlClockUI *this) - case PANEL_APPLET_ORIENT_UP: - case PANEL_APPLET_ORIENT_DOWN: - priv->panel_box = gtk_hbox_new (FALSE, 0); -+ box = gtk_hbox_new (FALSE, 6); - break; - case PANEL_APPLET_ORIENT_RIGHT: - case PANEL_APPLET_ORIENT_LEFT: - priv->panel_box = gtk_vbox_new (FALSE, 0); -+ box = gtk_vbox_new (FALSE, 6); - break; -+ default: -+ g_assert_not_reached (); - } - priv->panel_label = gtk_label_new (NULL); -+ priv->panel_weather_icon = gtk_image_new (); - priv->panel_button = gtk_toggle_button_new (); - priv->panel_tips = gtk_tooltips_new (); - -@@ -626,8 +499,9 @@ create_panel_buttons (IntlClockUI *this) - gtk_button_set_relief (GTK_BUTTON (priv->panel_button), - GTK_RELIEF_NONE); - -- gtk_container_add (GTK_CONTAINER (priv->panel_button), -- priv->panel_label); -+ gtk_container_add (GTK_CONTAINER (priv->panel_button), box); -+ gtk_container_add (GTK_CONTAINER (box), priv->panel_weather_icon); -+ gtk_container_add (GTK_CONTAINER (box), priv->panel_label); - - g_signal_connect ( - G_OBJECT (priv->panel_button), "clicked", -@@ -655,12 +529,13 @@ create_panel_buttons (IntlClockUI *this) - ); - - gtk_widget_show (priv->panel_label); -+ gtk_widget_show (priv->panel_weather_icon); -+ gtk_widget_show (box); - - gtk_box_pack_start (GTK_BOX (priv->panel_box), priv->panel_button, - FALSE, FALSE, 0); - -- gtk_container_add (GTK_CONTAINER (priv->panel_applet), -- priv->panel_box); -+ gtk_container_add (GTK_CONTAINER (priv->panel_applet), priv->panel_box); - - gtk_widget_show_all (priv->panel_box); - } -@@ -671,10 +546,16 @@ intlclock_ui_change_orient (PanelApplet *applet, - IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); -- -- if (GTK_IS_WIDGET (priv->panel_box)) -- gtk_widget_destroy (priv->panel_box); -+ GdkPixbuf *pixbuf = NULL; -+ -+ if (GTK_IS_WIDGET (priv->panel_box)) { -+ pixbuf = g_object_ref (gtk_image_get_pixbuf (GTK_IMAGE (priv->panel_weather_icon))); -+ gtk_widget_destroy (priv->panel_box); -+ } - create_panel_buttons (this); -+ intlclock_ui_update_weather_icon (this, pixbuf); -+ if (pixbuf) -+ g_object_unref (pixbuf); - } - - static void -@@ -706,6 +587,16 @@ create_panel_button_popup (IntlClockUI *this) - "hidden", "1", - NULL); - } -+ -+ if (!can_set_system_time ()) { -+ popup_component = panel_applet_get_popup_component -+ (PANEL_APPLET (priv->panel_applet)); -+ -+ bonobo_ui_component_set_prop (popup_component, -+ "/commands/IntlClockConfig", -+ "sensitive", "0", -+ NULL); -+ } - } - - static void -@@ -714,7 +605,7 @@ create_events_window (IntlClockUI *this) - IntlClockUIPrivate *priv = PRIVATE (this); - - priv->events_window = -- GTK_WIDGET (intlclock_events_popup_new (priv->clock, priv->panel_applet)); -+ GTK_WIDGET (intlclock_events_popup_new (priv->clock, priv->panel_applet, this)); - - g_signal_connect (G_OBJECT (priv->events_window), "size-allocate", - G_CALLBACK (intlclock_events_window_size_allocate_cb), this); -@@ -723,41 +614,32 @@ create_events_window (IntlClockUI *this) - } - - static void --create_clock_window (IntlClockUI *this) -+add_to_group (GtkWidget *child, gpointer data) - { -- IntlClockUIPrivate *priv = PRIVATE (this); -- GtkSettings *settings; -- GtkStyle *style; -+ GtkSizeGroup *group = data; - -- priv->clock_vbox = intlclock_events_popup_get_clock_container -- (INTLCLOCK_EVENTS_POPUP (priv->events_window)); -- gtk_widget_show (priv->clock_vbox); -+ gtk_size_group_add_widget (group, child); - } - - static void --create_main_section (IntlClockUI *this) -+create_clock_window (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); -- IntlClockLocation *loc; -- GtkWidget *header, *subheader; -- GtkWidget *prefs_button; -- GtkWidget *prefs_button_box; -- -- if (!priv->main_section) { -- priv->main_section = gtk_vbox_new (FALSE, 6); -- gtk_container_set_border_width -- (GTK_CONTAINER (priv->main_section), -- MAIN_SECTION_PADDING); -- gtk_box_pack_end (GTK_BOX (priv->clock_vbox), -- priv->main_section, FALSE, FALSE, 0); -+ GtkWidget *clock_container; - -- } else { -- gtk_container_foreach (GTK_CONTAINER (priv->main_section), -- (GtkCallback)gtk_widget_destroy, -- NULL); -- } -+ clock_container = intlclock_events_popup_get_clock_container -+ (INTLCLOCK_EVENTS_POPUP (priv->events_window)); -+ gtk_widget_show (clock_container); -+ -+ priv->clock_vbox = gtk_vbox_new (FALSE, 6); -+ gtk_container_add (GTK_CONTAINER (clock_container), priv->clock_vbox); - -- gtk_widget_show_all (priv->main_section); -+ priv->clock_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); -+ gtk_size_group_set_ignore_hidden (priv->clock_group, FALSE); -+ -+ gtk_container_foreach (GTK_CONTAINER (clock_container), -+ (GtkCallback)add_to_group, -+ priv->clock_group); - } - - static gint -@@ -824,7 +706,6 @@ create_cities_section (IntlClockUI *this) - IntlClockUIPrivate *priv = PRIVATE (this); - GList *node; - IntlClockLocationTile *city; -- GtkWidget *header, *subheader, *image;; - GList *cities; - - if (priv->cities_section) { -@@ -832,12 +713,8 @@ create_cities_section (IntlClockUI *this) - priv->cities_section = NULL; - } - -- if (!priv->show_locations) { -- return; -- } -- - priv->cities_section = gtk_vbox_new (FALSE, 6); -- gtk_container_set_border_width (GTK_CONTAINER (priv->cities_section), 8); -+ gtk_container_set_border_width (GTK_CONTAINER (priv->cities_section), 0); - - cities = intlclock_get_locations (priv->clock); - if (g_list_length (cities) == 0) { -@@ -884,10 +761,6 @@ create_map_section (IntlClockUI *this) - priv->map_widget = NULL; - } - -- if (!priv->show_map) { -- return; -- } -- - map = intlclock_map_new (priv->clock); - - priv->map_section = gtk_alignment_new (0, 0, 1, 1); -@@ -895,11 +768,10 @@ create_map_section (IntlClockUI *this) - - gtk_container_add (GTK_CONTAINER (priv->map_section), priv->map_widget); - -- gtk_box_pack_start (GTK_BOX (priv->clock_vbox), -- priv->map_section, FALSE, FALSE, 0); -- - gtk_alignment_set_padding (GTK_ALIGNMENT (priv->map_section), - 1, 1, 1, 1); -+ gtk_box_pack_start (GTK_BOX (priv->clock_vbox), -+ priv->map_section, FALSE, FALSE, 0); - - gtk_widget_show (priv->map_widget); - gtk_widget_show (priv->map_section); -@@ -927,7 +799,6 @@ create_cities_store (IntlClockUI *this) - - while (list) { - IntlClockLocation *loc = INTLCLOCK_LOCATION (list->data); -- gfloat latitude, longitude; - - gtk_list_store_append (priv->cities_store, &iter); - gtk_list_store_set (priv->cities_store, &iter, -@@ -953,12 +824,16 @@ intlclock_prefs_hide (GtkWidget *widget, IntlClockUI *this) - IntlClockUIPrivate *priv = PRIVATE (this); - GtkWidget *tree; - -+ intlclock_edit_hide (widget, this); -+ - gtk_widget_hide (priv->prefs_window); - - tree = glade_xml_get_widget (priv->glade_xml, "cities_list"); - - gtk_tree_selection_unselect_all - (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree))); -+ -+ intlclock_ui_reset_timeout (this); - } - - static gboolean -@@ -974,8 +849,6 @@ intlclock_edit_clear (GtkWidget *widget, IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); - -- GtkWidget *edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); -- - GtkWidget *zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); - GtkWidget *name_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-name-entry"); - -@@ -1003,6 +876,8 @@ intlclock_edit_hide (GtkWidget *widget, IntlClockUI *this) - - GtkWidget *edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); - -+ intlclock_find_hide (widget, this); -+ - gtk_widget_hide (edit_window); - - intlclock_edit_clear (widget, this); -@@ -1016,6 +891,23 @@ intlclock_edit_hide_event (GtkWidget *widget, GdkEvent *event, IntlClockUI *this - return TRUE; - } - -+static void -+intlclock_find_hide (GtkWidget *widget, IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ -+ GtkWidget *find_window = glade_xml_get_widget (priv->glade_xml, "find-location-window"); -+ -+ gtk_widget_hide (find_window); -+} -+ -+static gboolean -+intlclock_find_hide_event (GtkWidget *widget, GdkEvent *event, IntlClockUI *this) -+{ -+ intlclock_find_hide (widget, this); -+ -+ return TRUE; -+} - - static void - set_12hr_format_radio_cb (GtkWidget *widget, IntlClockUI *this) -@@ -1057,28 +949,6 @@ set_seconds_check_cb (GtkWidget *widget, IntlClockUI *this) - } - - static void --set_locations_check_cb (GtkWidget *widget, IntlClockUI *this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- panel_applet_gconf_set_bool (PANEL_APPLET (priv->panel_applet), -- KEY_SHOW_LOCATIONS, -- GTK_TOGGLE_BUTTON (widget)->active, -- NULL); --} -- --static void --set_map_check_cb (GtkWidget *widget, IntlClockUI *this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- panel_applet_gconf_set_bool (PANEL_APPLET (priv->panel_applet), -- KEY_SHOW_MAP, -- GTK_TOGGLE_BUTTON (widget)->active, -- NULL); --} -- --static void - fill_prefs_window (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); -@@ -1087,6 +957,9 @@ fill_prefs_window (IntlClockUI *this) - GtkCellRenderer *renderer; - GtkTreeViewColumn *col; - -+ time_t now_t; -+ struct tm now; -+ - /* Set the 12 hour / 24 hour widget */ - widget = glade_xml_get_widget (priv->glade_xml, "12hr_radio"); - g_signal_connect (widget, "toggled", -@@ -1109,18 +982,6 @@ fill_prefs_window (IntlClockUI *this) - g_signal_connect (widget, "toggled", G_CALLBACK (set_seconds_check_cb), - this); - -- /* Set the "Show Locations" checkbox */ -- widget = glade_xml_get_widget (priv->glade_xml, "show_locations_check"); -- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), priv->show_locations); -- g_signal_connect (widget, "toggled", G_CALLBACK (set_locations_check_cb), -- this); -- -- /* Set the "Show Map" checkbox */ -- widget = glade_xml_get_widget (priv->glade_xml, "show_map_check"); -- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), priv->show_map); -- g_signal_connect (widget, "toggled", G_CALLBACK (set_map_check_cb), -- this); -- - /* Fill the Cities list */ - widget = glade_xml_get_widget (priv->glade_xml, "cities_list"); - -@@ -1136,6 +997,15 @@ fill_prefs_window (IntlClockUI *this) - - gtk_tree_view_set_model (GTK_TREE_VIEW (widget), - GTK_TREE_MODEL (priv->cities_store)); -+ -+ /* Fill the time settings */ -+ tzset (); -+ time (&now_t); -+ localtime_r (&now_t, &now); -+ -+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->seconds_spin), now.tm_sec); -+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->minutes_spin), now.tm_min); -+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->hours_spin), now.tm_hour); - } - - static gint -@@ -1150,19 +1020,334 @@ sort_zoneinfo_by_l10n_name (gconstpointer a, gconstpointer b) - return strcmp (name_a, name_b); - } - -+static void -+intlclock_prefs_locations_changed (GtkTreeSelection *selection, -+ IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ gint n; -+ -+ n = gtk_tree_selection_count_selected_rows (selection); -+ gtk_widget_set_sensitive (priv->prefs_location_edit_button, n > 0); -+ gtk_widget_set_sensitive (priv->prefs_location_remove_button, n > 0); -+} -+ - static void --display_prefs_window (IntlClockUI *this) -+location_tree_selection_changed (GtkTreeSelection *selection, -+ IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ GtkTreeModel *model; -+ GtkTreeIter iter; -+ WeatherLocation *loc = NULL; -+ gboolean can_save = FALSE; -+ -+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) { -+ gtk_tree_model_get (model, &iter, GWEATHER_XML_COL_POINTER, &loc, -1); -+ if (loc != NULL) -+ can_save = TRUE; -+ } -+ -+ gtk_widget_set_sensitive (priv->find_location_ok_button, can_save); -+} -+ -+static void -+wrap_cb (GtkSpinButton *spin, -+ IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ 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 *)priv->seconds_spin) -+ gtk_spin_button_spin (GTK_SPIN_BUTTON (priv->minutes_spin), -+ direction, 1.0); -+ else if (spin == (GtkSpinButton *)priv->minutes_spin) -+ gtk_spin_button_spin (GTK_SPIN_BUTTON (priv->hours_spin), -+ direction, 1.0); -+ else { -+ guint year, month, day; -+ GDate *date; -+ -+ gtk_calendar_get_date (GTK_CALENDAR (priv->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 (priv->calendar), -+ month, year); -+ gtk_calendar_select_day (GTK_CALENDAR (priv->calendar), -+ day); -+ -+ g_date_free (date); -+ } -+} -+ -+static void -+update_set_time_button (IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ gint can_set; -+ -+ can_set = can_set_system_time (); -+ -+ if (priv->time_settings_button) -+ gtk_widget_set_sensitive (priv->time_settings_button, can_set != 0); -+ if (priv->set_time_button) -+ gtk_button_set_label (GTK_BUTTON (priv->set_time_button), -+ can_set == 1 ? -+ _("Set System Time...") : -+ _("Set System Time")); -+} -+ -+static void -+set_time_callback (IntlClockUI *this, GError *error) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ GtkWidget *window; -+ GtkWidget *dialog; -+ -+ if (error) { -+ dialog = gtk_message_dialog_new (NULL, -+ 0, -+ GTK_MESSAGE_ERROR, -+ GTK_BUTTONS_OK, -+ _("Failed to set the system time")); -+ -+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), 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 (this); -+ -+ window = glade_xml_get_widget (priv->glade_xml, "set-time-window"); -+ gtk_widget_hide (window); -+} -+ -+static void -+set_time (GtkWidget *widget, IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ struct tm t; -+ gint64 time; -+ guint year, month, day; -+ -+ t.tm_sec = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->seconds_spin)); -+ t.tm_min = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->minutes_spin)); -+ t.tm_hour = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->hours_spin)); -+ gtk_calendar_get_date (GTK_CALENDAR (priv->calendar), &year, &month, &day); -+ t.tm_year = year - 1900; -+ t.tm_mon = month; -+ t.tm_mday = day; -+ -+ time = mktime (&t); -+ -+ set_system_time_async (time, (GFunc)set_time_callback, this, NULL); -+} -+ -+static gboolean -+find_location (GtkTreeModel *model, -+ GtkTreeIter *iter, -+ const gchar *location, -+ gboolean go_parent) -+{ -+ GtkTreeIter iter_child; -+ GtkTreeIter iter_parent; -+ gchar *aux_loc; -+ gboolean valid; -+ int len; -+ -+ len = strlen (location); -+ -+ if (len <= 0) { -+ return FALSE; -+ } -+ -+ do { -+ gtk_tree_model_get (model, iter, GWEATHER_XML_COL_LOC, &aux_loc, -1); -+ -+ if (g_ascii_strncasecmp (aux_loc, location, len) == 0) { -+ g_free (aux_loc); -+ return TRUE; -+ } -+ -+ if (gtk_tree_model_iter_has_child (model, iter)) { -+ gtk_tree_model_iter_nth_child (model, &iter_child, iter, 0); -+ if (find_location (model, &iter_child, location, FALSE)) { -+ /* Manual copying of the iter */ -+ iter->stamp = iter_child.stamp; -+ iter->user_data = iter_child.user_data; -+ iter->user_data2 = iter_child.user_data2; -+ iter->user_data3 = iter_child.user_data3; -+ -+ g_free (aux_loc); -+ -+ return TRUE; -+ } -+ } -+ -+ g_free (aux_loc); -+ -+ valid = gtk_tree_model_iter_next (model, iter); -+ } while (valid); -+ -+ if (go_parent) { -+ iter_parent = *iter; -+ while (gtk_tree_model_iter_parent (model, iter, &iter_parent)) { -+ if (gtk_tree_model_iter_next (model, iter)) -+ return find_location (model, iter, location, TRUE); -+ iter_parent = *iter; -+ } -+ } -+ -+ return FALSE; -+} -+ -+static void -+find_next_location (GtkButton *button, IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ GtkTreeView *tree; -+ GtkTreeModel *model; -+ GtkEntry *entry; -+ GtkTreeSelection *selection; -+ GtkTreeIter iter; -+ GtkTreeIter iter_parent; -+ GtkTreePath *path; -+ const gchar *location; -+ -+ tree = GTK_TREE_VIEW (priv->location_tree); -+ model = gtk_tree_view_get_model (tree); -+ entry = GTK_ENTRY (priv->find_location_entry); -+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree)); -+ -+ if (gtk_tree_selection_count_selected_rows (selection) >= 1) { -+ gtk_tree_selection_get_selected (selection, &model, &iter); -+ /* Select next or select parent */ -+ if (!gtk_tree_model_iter_next (model, &iter)) { -+ iter_parent = iter; -+ if (!gtk_tree_model_iter_parent (model, &iter, &iter_parent) || -+ !gtk_tree_model_iter_next (model, &iter)) -+ gtk_tree_model_get_iter_first (model, &iter); -+ } -+ } -+ else { -+ gtk_tree_model_get_iter_first (model, &iter); -+ } -+ location = gtk_entry_get_text (entry); -+ -+ if (find_location (model, &iter, location, TRUE)) { -+ gtk_widget_set_sensitive (priv->find_next_location_button, TRUE); -+ path = gtk_tree_model_get_path (model, &iter); -+ gtk_tree_view_expand_to_path (tree, path); -+ gtk_tree_selection_select_path (selection, path); -+ gtk_tree_view_scroll_to_cell (tree, path, NULL, TRUE, 0.5, 0); -+ -+ gtk_tree_path_free (path); -+ } -+ else { -+ gtk_widget_set_sensitive (priv->find_next_location_button, FALSE); -+ } -+} -+ -+static void -+find_entry_changed (GtkEditable *entry, IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ GtkTreeView *tree; -+ GtkTreeModel *model; -+ GtkTreeSelection *selection; -+ GtkTreeIter iter; -+ GtkTreePath *path; -+ const gchar *location; -+ -+ tree = GTK_TREE_VIEW (priv->location_tree); -+ model = gtk_tree_view_get_model (tree); -+ -+ selection = gtk_tree_view_get_selection (tree); -+ gtk_tree_model_get_iter_first (model, &iter); -+ -+ location = gtk_entry_get_text (GTK_ENTRY (entry)); -+ if (find_location (model, &iter, location, TRUE)) { -+ gtk_widget_set_sensitive (priv->find_next_location_button, TRUE); -+ path = gtk_tree_model_get_path (model, &iter); -+ gtk_tree_view_expand_to_path (tree, path); -+ gtk_tree_selection_select_iter (selection, &iter); -+ gtk_tree_view_scroll_to_cell (tree, path, NULL, TRUE, 0.5, 0); -+ gtk_tree_path_free (path); -+ } -+ else { -+ gtk_widget_set_sensitive (priv->find_next_location_button, FALSE); -+ } -+} -+ -+static void -+cancel_time_settings (GtkWidget *button, IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ -+ gtk_widget_hide (priv->set_time_window); -+ -+ intlclock_ui_reset_timeout (this); -+} -+ -+static void -+run_time_settings (GtkWidget *button, IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (this); -+ GtkWidget *cancel_set_time_button; -+ -+ if (!priv->set_time_button) { -+ priv->set_time_button = glade_xml_get_widget (priv->glade_xml, "set-time-button"); -+ g_signal_connect (priv->set_time_button, "clicked", G_CALLBACK (set_time), this); -+ -+ cancel_set_time_button = glade_xml_get_widget (priv->glade_xml, "cancel-set-time-button"); -+ g_signal_connect (cancel_set_time_button, "clicked", G_CALLBACK (cancel_time_settings), this); -+ -+ priv->current_time_label = glade_xml_get_widget (priv->glade_xml, "current_time_label"); -+ } -+ -+ priv->set_time_window = glade_xml_get_widget (priv->glade_xml, "set-time-window"); -+ gtk_window_present (GTK_WINDOW (priv->set_time_window)); -+ -+ intlclock_ui_reset_timeout (this); -+} -+ -+static void -+display_prefs_window (IntlClockUI *this, gboolean locations) - { - IntlClockUIPrivate *priv = PRIVATE (this); - GtkWidget *edit_window; -- GtkWidget *prefs_window; - GtkWidget *prefs_close_button; -- GtkWidget *prefs_settings_button; - GtkWidget *edit_cancel_button; - GtkWidget *edit_ok_button; - GtkWidget *zone_combo; -- -- GtkWidget *tmp_button; -+ GtkWidget *find_window; -+ GtkWidget *find_location_button; -+ GtkWidget *find_location_cancel_button; -+ GtkTreeSelection *selection; - - if (!priv->prefs_window) { - priv->prefs_window = -@@ -1170,43 +1355,42 @@ display_prefs_window (IntlClockUI *this) - - prefs_close_button = - glade_xml_get_widget (priv->glade_xml, "prefs-close-button"); -- -- prefs_settings_button = -- glade_xml_get_widget (priv->glade_xml, "prefs-time-settings-button"); -- - priv->prefs_locations = - GTK_TREE_VIEW (glade_xml_get_widget (priv->glade_xml, "cities_list")); - -+ selection = gtk_tree_view_get_selection (priv->prefs_locations); -+ g_signal_connect (G_OBJECT (selection), "changed", -+ G_CALLBACK (intlclock_prefs_locations_changed), this); -+ - g_signal_connect (G_OBJECT (priv->prefs_window), "delete_event", - G_CALLBACK (intlclock_prefs_hide_event), this); - - g_signal_connect (G_OBJECT (prefs_close_button), "clicked", - G_CALLBACK (intlclock_prefs_hide), this); - -- g_signal_connect (G_OBJECT (prefs_settings_button), "clicked", -- G_CALLBACK (run_time_configuration_cb), this); -- -- tmp_button = -+ priv->prefs_location_remove_button = - glade_xml_get_widget (priv->glade_xml, "prefs-locations-remove-button"); - -- g_signal_connect (G_OBJECT (tmp_button), "clicked", -+ g_signal_connect (G_OBJECT (priv->prefs_location_remove_button), "clicked", - G_CALLBACK (run_prefs_locations_remove), this); -- -- tmp_button = -+ -+ priv->prefs_location_add_button = - glade_xml_get_widget (priv->glade_xml, "prefs-locations-add-button"); - -- g_signal_connect (G_OBJECT (tmp_button), "clicked", -+ g_signal_connect (G_OBJECT (priv->prefs_location_add_button), "clicked", - G_CALLBACK (run_prefs_locations_add), this); - -- tmp_button = -+ priv->prefs_location_edit_button = - glade_xml_get_widget (priv->glade_xml, "prefs-locations-edit-button"); - -- g_signal_connect (G_OBJECT (tmp_button), "clicked", -+ g_signal_connect (G_OBJECT (priv->prefs_location_edit_button), "clicked", - G_CALLBACK (run_prefs_locations_edit), this); - - edit_window = glade_xml_get_widget (priv->glade_xml, - "edit-location-window"); - -+ gtk_window_set_transient_for (GTK_WINDOW (edit_window), -+ GTK_WINDOW (priv->prefs_window)); - - g_signal_connect (G_OBJECT (edit_window), "delete_event", - G_CALLBACK (intlclock_edit_hide_event), this); -@@ -1219,7 +1403,35 @@ display_prefs_window (IntlClockUI *this) - - zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); - -- g_signal_connect (G_OBJECT (zone_combo), "changed", -+ find_window = glade_xml_get_widget (priv->glade_xml, -+ "find-location-window"); -+ -+ gtk_window_set_transient_for (GTK_WINDOW (find_window), -+ GTK_WINDOW (edit_window)); -+ -+ g_signal_connect (G_OBJECT (find_window), "delete_event", -+ G_CALLBACK (intlclock_find_hide_event), this); -+ -+ find_location_button = -+ glade_xml_get_widget (priv->glade_xml, "find-location-button"); -+ -+ priv->find_location_ok_button = -+ glade_xml_get_widget (priv->glade_xml, "find-location-ok-button"); -+ -+ find_location_cancel_button = -+ glade_xml_get_widget (priv->glade_xml, "find-location-cancel-button"); -+ -+ priv->find_next_location_button = -+ glade_xml_get_widget (priv->glade_xml, "find-next-location-button"); -+ -+ priv->find_location_entry = -+ glade_xml_get_widget (priv->glade_xml, "find-location-entry"); -+ -+ priv->location_tree = -+ glade_xml_get_widget (priv->glade_xml, "find-location-tree"); -+ -+ priv->zone_combo_changed = -+ g_signal_connect (G_OBJECT (zone_combo), "changed", - G_CALLBACK (zone_combo_changed), this); - - -@@ -1229,16 +1441,72 @@ display_prefs_window (IntlClockUI *this) - g_signal_connect (G_OBJECT (edit_ok_button), "clicked", - G_CALLBACK (run_prefs_edit_save), this); - -+ g_signal_connect (find_location_button, "clicked", -+ G_CALLBACK (run_find_location), this); -+ -+ g_signal_connect (G_OBJECT (find_location_cancel_button), "clicked", -+ G_CALLBACK (intlclock_find_hide), this); -+ -+ g_signal_connect (G_OBJECT (priv->find_location_ok_button), "clicked", -+ G_CALLBACK (run_find_location_save), this); -+ -+ g_signal_connect (G_OBJECT (priv->find_next_location_button), "clicked", -+ G_CALLBACK (find_next_location), this); -+ -+ g_signal_connect (G_OBJECT (priv->find_location_entry), "changed", -+ G_CALLBACK (find_entry_changed), this); -+ -+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->location_tree)); -+ g_signal_connect (selection, "changed", -+ G_CALLBACK (location_tree_selection_changed), this); -+ - /* We have to put an item in the combo box in the glade file - to get the simpler, string-only store. Here we remove that - item. */ - gtk_combo_box_remove_text (GTK_COMBO_BOX (zone_combo), 0); - -+ /* Set up the time setting section */ -+ -+ priv->time_settings_button = glade_xml_get_widget (priv->glade_xml, "time-settings-button"); -+ g_signal_connect (priv->time_settings_button, "clicked", G_CALLBACK (run_time_settings), this); -+ -+ priv->calendar = glade_xml_get_widget (priv->glade_xml, "calendar"); -+ priv->hours_spin = glade_xml_get_widget (priv->glade_xml, "hours_spin"); -+ priv->minutes_spin = glade_xml_get_widget (priv->glade_xml, "minutes_spin"); -+ priv->seconds_spin = glade_xml_get_widget (priv->glade_xml, "seconds_spin"); -+ -+ gtk_entry_set_width_chars (GTK_ENTRY (priv->hours_spin), 2); -+ gtk_entry_set_width_chars (GTK_ENTRY (priv->minutes_spin), 2); -+ gtk_entry_set_width_chars (GTK_ENTRY (priv->seconds_spin), 2); -+ -+ gtk_entry_set_alignment (GTK_ENTRY (priv->hours_spin), 1.0); -+ gtk_entry_set_alignment (GTK_ENTRY (priv->minutes_spin), 1.0); -+ gtk_entry_set_alignment (GTK_ENTRY (priv->seconds_spin), 1.0); -+ g_signal_connect (priv->seconds_spin, "wrapped", G_CALLBACK (wrap_cb), this); -+ g_signal_connect (priv->minutes_spin, "wrapped", G_CALLBACK (wrap_cb), this); -+ g_signal_connect (priv->hours_spin, "wrapped", G_CALLBACK (wrap_cb), this); -+ - /* fill it with the current preferences */ - fill_prefs_window (this); - } - -+ if (locations) { -+ GtkWidget *notebook = -+ glade_xml_get_widget (priv->glade_xml, "notebook"); -+ gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 1); -+ } -+ -+ update_set_time_button (this); -+ - gtk_window_present (GTK_WINDOW (priv->prefs_window)); -+ -+ intlclock_ui_reset_timeout (this); -+} -+ -+void -+intlclock_ui_edit_locations (IntlClockUI *ui) -+{ -+ display_prefs_window (ui, TRUE); - } - - static void -@@ -1306,16 +1574,11 @@ intlclock_ui_new (IntlClock *clock, PanelApplet *applet) - create_events_window (this); - create_clock_window (this); - create_cities_store (this); -- -- if (priv->show_locations) { -- create_cities_section (this); -- } -- -- if (priv->show_map) { -- create_map_section (this); -- intlclock_map_refresh (INTLCLOCK_MAP (priv->map_widget)); -- } -- -+ create_cities_section (this); -+ create_map_section (this); -+ -+ intlclock_map_refresh (INTLCLOCK_MAP (priv->map_widget)); -+ - intlclock_ui_reset_timeout (this); - - return this; -@@ -1365,9 +1628,6 @@ intlclock_ui_init (IntlClockUI *this) - - priv->cities_store = NULL; - -- priv->show_locations = TRUE; -- priv->show_map = TRUE; -- - priv->prefs_window = NULL; - - priv->format_12hr = TRUE; -@@ -1547,56 +1807,6 @@ gconf_show_week_changed (GConfClient *client, - } - - static void --gconf_show_locations_changed (GConfClient *client, -- guint cnxn_id, -- GConfEntry *entry, -- IntlClockUI *this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- GtkWidget *widget; -- -- gboolean value; -- -- if (!entry->value || entry->value->type != GCONF_VALUE_BOOL) -- return; -- -- value = gconf_value_get_bool (entry->value); -- -- priv->show_locations = (value != 0); -- -- widget = glade_xml_get_widget (priv->glade_xml, "show_locations_check"); -- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), -- priv->show_locations); -- -- create_cities_section (this); --} -- --static void --gconf_show_map_changed (GConfClient *client, -- guint cnxn_id, -- GConfEntry *entry, -- IntlClockUI *this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- GtkWidget *widget; -- -- gboolean value; -- -- if (!entry->value || entry->value->type != GCONF_VALUE_BOOL) -- return; -- -- value = gconf_value_get_bool (entry->value); -- -- priv->show_map = (value != 0); -- -- widget = glade_xml_get_widget (priv->glade_xml, "show_map_check"); -- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), -- priv->show_map); -- -- create_map_section (this); --} -- --static void - location_start_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, -@@ -1614,6 +1824,7 @@ location_start_element (GMarkupParseContext *context, - gchar *timezone = NULL; - gfloat latitude = 0.0; - gfloat longitude = 0.0; -+ gchar *code = NULL; - - int index = 0; - -@@ -1633,6 +1844,8 @@ location_start_element (GMarkupParseContext *context, - 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]; - } - } - -@@ -1642,7 +1855,7 @@ location_start_element (GMarkupParseContext *context, - return; - } - -- loc = intlclock_location_new (name, timezone, latitude, longitude); -+ loc = intlclock_location_new (name, timezone, latitude, longitude, code); - - *(GList **)user_data = g_list_append (ret, loc); - } -@@ -1713,10 +1926,11 @@ gconf_loc_to_string (IntlClockLocation *loc) - prev_locale = setlocale (LC_NUMERIC, "POSIX"); - - ret = g_markup_printf_escaped -- ("", -+ ("", - intlclock_location_get_name (loc), - intlclock_location_get_timezone (loc), -- latitude, longitude); -+ latitude, longitude, -+ intlclock_location_get_weather_code (loc)); - - setlocale (LC_NUMERIC, ""); - -@@ -1727,7 +1941,7 @@ static void - intlclock_ui_save_cities_store (IntlClockUI *this) - { - IntlClockUIPrivate *priv = PRIVATE (this); -- IntlClockLocation *loc, *cur; -+ IntlClockLocation *loc; - GList *node = intlclock_get_locations (priv->clock); - - GSList *root = NULL; -@@ -1803,24 +2017,6 @@ setup_gconf (IntlClockUI *this) - g_free (key); - - key = panel_applet_gconf_get_full_key -- (PANEL_APPLET (priv->panel_applet), KEY_SHOW_LOCATIONS); -- priv->listeners [index++] = -- gconf_client_notify_add ( -- client, key, -- (GConfClientNotifyFunc) gconf_show_locations_changed, -- this, NULL, NULL); -- g_free (key); -- -- key = panel_applet_gconf_get_full_key -- (PANEL_APPLET (priv->panel_applet), KEY_SHOW_MAP); -- priv->listeners [index++] = -- gconf_client_notify_add ( -- client, key, -- (GConfClientNotifyFunc) gconf_show_map_changed, -- this, NULL, NULL); -- g_free (key); -- -- key = panel_applet_gconf_get_full_key - (PANEL_APPLET (priv->panel_applet), KEY_CITIES); - priv->listeners [index++] = - gconf_client_notify_add ( -@@ -1868,14 +2064,6 @@ load_gconf_settings (IntlClockUI *this) - panel_applet_gconf_get_bool (priv->panel_applet, - KEY_SHOW_WEEK, NULL); - -- priv->show_locations = -- panel_applet_gconf_get_bool (priv->panel_applet, -- KEY_SHOW_LOCATIONS, NULL); -- -- priv->show_map = -- panel_applet_gconf_get_bool (priv->panel_applet, -- KEY_SHOW_MAP, NULL); -- - values = panel_applet_gconf_get_list (priv->panel_applet, KEY_CITIES, - GCONF_VALUE_STRING, NULL); - -@@ -1892,92 +2080,72 @@ static void bonobo_display_properties_dialog (BonoboUIComponent *uic, - IntlClockUI *this, - const gchar *verbname) - { -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- display_prefs_window (this); -+ display_prefs_window (this, FALSE); - } - --static void bonobo_run_time_configuration (BonoboUIComponent *uic, -- IntlClockUI *this, -- const gchar *verbname) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- run_time_configuration (this); --} -- --static void display_prefs_window_cb (GtkButton *button, gpointer this) -+static void -+copy_time (BonoboUIComponent *uic, -+ IntlClockUI *this, -+ const gchar *verbname) - { - IntlClockUIPrivate *priv = PRIVATE (this); -+ gchar *utf8; -+ time_t now_t; -+ struct tm now; - -- display_prefs_window (this); --} -+ tzset (); -+ time (&now_t); -+ localtime_r (&now_t, &now); - --static void --run_time_configuration_cb (GtkButton *button, gpointer this) --{ -- IntlClockUIPrivate *priv = PRIVATE (this); -+ utf8 = intlclock_format_time (priv->clock, &now, FALSE, -+ priv->format_12hr, -+ priv->format_show_seconds, -+ FALSE, FALSE, NULL, FALSE); -+ -+ gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY), -+ utf8, -1); -+ gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), -+ utf8, -1); - -- run_time_configuration (this); -+ g_free (utf8); - } - - static void --run_time_configuration (IntlClockUI *this) -+copy_date (BonoboUIComponent *uic, -+ IntlClockUI *this, -+ const gchar *verbname) - { -- IntlClockUIPrivate *priv = PRIVATE (this); -- -- GtkWidget *dialog; -- GError *err; -- char **argv; -- char *path; -+ char string[256]; -+ char *utf8, *loc; - -- GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (priv->events_window)); -- gchar *tool = "/opt/gnome/bin/gnomesu /sbin/yast2 timezone"; -- -- if (!tool || tool[0] == '\0') -- return; -- -- if (!g_shell_parse_argv (tool, NULL, &argv, NULL)) -- return; -- -- if (!(path = g_find_program_in_path (argv [0]))) { -- g_strfreev (argv); -- return; -- } -- -- g_free (path); -- -- err = NULL; -- if (gdk_spawn_on_screen (screen, -- NULL, -- argv, -- NULL, -- G_SPAWN_SEARCH_PATH, -- NULL, -- NULL, -- NULL, -- &err)) { -- g_strfreev (argv); -- return; -- } -- -- g_strfreev (argv); -+ time_t now_t; -+ struct tm now; - -- dialog = gtk_message_dialog_new (NULL, -- GTK_DIALOG_DESTROY_WITH_PARENT, -- GTK_MESSAGE_ERROR, -- GTK_BUTTONS_OK, -- _("Failed to launch time configuration tool: %s"), -- err->message); -- g_error_free (err); -+ tzset (); -+ time (&now_t); -+ localtime_r (&now_t, &now); - -- g_signal_connect (dialog, "response", -- G_CALLBACK (gtk_widget_destroy), NULL); -+ loc = g_locale_from_utf8 (_("%A, %B %d %Y"), -1, NULL, NULL, NULL); -+ if (!loc) -+ strcpy (string, "???"); -+ else if (strftime (string, sizeof (string), loc, &now) <= 0) -+ strcpy (string, "???"); -+ g_free (loc); - -- gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); -- gtk_window_set_screen (GTK_WINDOW (dialog), screen); -+ 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); -+} - -- gtk_widget_show_all (dialog); -+static void -+config_date (BonoboUIComponent *uic, -+ IntlClockUI *this, -+ const char *verbname) -+{ -+ run_time_settings (NULL, this); - } - - static void -@@ -2000,6 +2168,46 @@ remove_tree_row (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, - } - - static void -+update_coords (IntlClockUI *this, gboolean valid, gfloat lat, gfloat lon) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -+ GtkWidget *lat_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-latitude-entry"); -+ GtkWidget *lon_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-entry"); -+ GtkWidget *lat_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-latitude-combo"); -+ GtkWidget *lon_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-combo"); -+ gchar *tmp; -+ -+ 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; -+ } -+ -+ 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); -+ } -+} -+ -+static void - zone_combo_changed (GtkComboBox *widget, gpointer this) - { - IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -@@ -2009,17 +2217,12 @@ zone_combo_changed (GtkComboBox *widget, gpointer this) - gchar *city = NULL; - gfloat lat = 0; - gfloat lon = 0; -- gchar *tmp; -+ GtkTreeModel *model; -+ gchar *name; - - GtkWidget *name_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-name-entry"); -- -- GtkWidget *lat_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-latitude-entry"); -- -- GtkWidget *lon_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-entry"); -- -- GtkWidget *lat_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-latitude-combo"); -- -- GtkWidget *lon_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-combo"); -+ GtkWidget *edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); -+ gchar *weather_code; - - IntlClockCountry *country; - IntlClockZoneInfo *info; -@@ -2028,6 +2231,14 @@ zone_combo_changed (GtkComboBox *widget, gpointer this) - return; - } - -+ /* only fill in other field if name is not set yet, to -+ * allow correcting a guessed timezone -+ */ -+ name = gtk_entry_get_text (name_entry); -+ if (name && name[0]) { -+ return; -+ } -+ - info = intlclock_zonetable_get_l10n_zone (zones, timezone); - g_free (timezone); - -@@ -2049,26 +2260,13 @@ zone_combo_changed (GtkComboBox *widget, gpointer this) - g_free (city); - - intlclock_zoneinfo_get_coords (info, &lat, &lon); -+ update_coords (this, TRUE, lat, lon); - -- 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); -- } -+ fill_location_tree (this); -+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->location_tree)); -+ weather_code = find_weather_code (model, city, lat * M_PI/180.0, lon * M_PI/180.0); -+ g_object_set_data_full (G_OBJECT (edit_window), "weather-code", -+ weather_code, g_free); - } - - static void -@@ -2144,12 +2342,8 @@ edit_tree_row (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, - IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); - - IntlClockLocation *loc; -- int i; -- int timezone_idx = -1; - gchar *tmp; - gfloat lat, lon; -- GList *list; -- GList *cur; - - /* fill the dialog with this location's data, show it */ - GtkWidget *edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); -@@ -2205,13 +2399,165 @@ static void - run_prefs_locations_remove (GtkButton *button, gpointer this) - { - IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -- GtkTreeModel *model = gtk_tree_view_get_model (priv->prefs_locations);; - GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->prefs_locations)); - - gtk_tree_selection_selected_foreach (sel, remove_tree_row, this); - } - - static void -+run_find_location (GtkButton *button, gpointer this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -+ -+ GtkWidget *window = glade_xml_get_widget (priv->glade_xml, "find-location-window"); -+ -+ gtk_tree_view_collapse_all (priv->location_tree); -+ gtk_widget_grab_focus (priv->find_location_entry); -+ gtk_window_present (GTK_WINDOW (window)); -+} -+ -+static gdouble -+distance (gdouble lat1, gdouble lon1, -+ gdouble lat2, gdouble lon2) -+{ -+ gdouble radius = 6372.795; -+ -+ return acos (cos (lat1) * cos (lat2) * cos (lon1 - lon2) + sin (lat1) * sin (lat2)) * radius; -+} -+ -+static gchar * -+find_timezone (IntlClockUI *this, -+ const char *name, -+ gfloat lat, -+ gfloat lon) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -+ IntlClockZoneTable *zonetab = intlclock_get_zonetable (priv->clock); -+ GList *zones, *l; -+ double dist, d; -+ gfloat zlat, zlon; -+ IntlClockZoneInfo *best; -+ -+ g_print ("find zone for %s (%f %f)\n", name, lat, lon); -+ dist = 1e6; -+ best = NULL; -+ zones = intlclock_zonetable_get_zones (zonetab); -+ for (l = zones; l; l = l->next) { -+ IntlClockZoneInfo *info = l->data; -+ intlclock_zoneinfo_get_coords (info, &zlat, &zlon); -+ -+ d = distance (lat, lon, zlat*M_PI/180.0, zlon*M_PI/180.0); -+ -+ if (d < dist) { -+ best = info; -+ dist = d; -+ } -+ } -+ -+ intlclock_zoneinfo_get_coords (best, &zlat, &zlon); -+ g_print ("best: %s (%f, %f), distance: %f\n", -+ intlclock_zoneinfo_get_name (best), zlat, zlon, dist); -+ -+ return g_strdup (intlclock_zoneinfo_get_name (best)); -+} -+ -+static void -+update_timezone (IntlClockUI *this, -+ const char *name, -+ gfloat lat, -+ gfloat lon) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -+ GtkWidget *zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); -+ GtkTreeModel *model; -+ gchar *timezone; -+ IntlClockLocation *loc; -+ -+ timezone = find_timezone (this, name, lat, lon); -+ loc = intlclock_location_new (name, timezone, lat*180.0/M_PI, lon*180.0/M_PI, NULL); -+ -+ g_signal_handler_block (zone_combo, priv->zone_combo_changed); -+ -+ fill_timezone_combo_from_location (this, zone_combo, loc); -+ -+ g_signal_handler_unblock (zone_combo, priv->zone_combo_changed); -+ -+ g_object_unref (loc); -+ g_free (timezone); -+} -+ -+static void -+run_find_location_save (GtkButton *button, gpointer this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -+ GtkTreeSelection *selection; -+ GtkTreeModel *model; -+ GtkTreeIter iter; -+ WeatherLocation *loc = NULL; -+ GtkWidget *name_entry; -+ GtkWidget *edit_window; -+ -+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->location_tree)); -+ if (!gtk_tree_selection_get_selected (selection, &model, &iter)) -+ return; -+ -+ gtk_tree_model_get (model, &iter, GWEATHER_XML_COL_POINTER, &loc, -1); -+ -+ if (!loc) -+ return; -+ -+ edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); -+ name_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-name-entry"); -+ gtk_entry_set_text (GTK_ENTRY (name_entry), loc->name); -+ g_object_set_data_full (G_OBJECT (edit_window), "weather-code", -+ g_strdup (loc->code), g_free); -+ -+ update_coords (this, loc->latlon_valid, loc->latitude*180.0/M_PI, loc->longitude*180.0/M_PI); -+ -+ update_timezone (this, loc->name, loc->latitude, loc->longitude); -+ -+ intlclock_find_hide (button, this); -+} -+ -+static void -+location_row_activated (GtkTreeView *tree_view, -+ GtkTreePath *path, -+ GtkTreeViewColumn *column, -+ IntlClockUI *this) -+{ -+ run_find_location_save (tree_view, this); -+} -+ -+static void -+fill_location_tree (IntlClockUI *this) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -+ GtkTreeView *tree; -+ GtkTreeModel *model; -+ GtkTreeViewColumn *column; -+ GtkCellRenderer *cell; -+ -+ tree = (GtkTreeView*)priv->location_tree; -+ -+ if (gtk_tree_view_get_model (tree) != NULL) -+ return; -+ -+ model = (GtkTreeModel*)gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); -+ gtk_tree_view_set_model (tree, model); -+ -+ cell = gtk_cell_renderer_text_new (); -+ column = gtk_tree_view_column_new_with_attributes ("not used", cell, -+ "text", GWEATHER_XML_COL_LOC, NULL); -+ gtk_tree_view_append_column (tree, column); -+ gtk_tree_view_set_expander_column (tree, column); -+ -+ g_signal_connect (tree, "row-activated", -+ G_CALLBACK (location_row_activated), this); -+ -+ gweather_xml_load_locations (tree, NULL); -+} -+ -+static void - run_prefs_locations_add (GtkButton *button, gpointer this) - { - IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); -@@ -2220,7 +2566,8 @@ run_prefs_locations_add (GtkButton *button, gpointer this) - GtkWidget *zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); - - fill_timezone_combo_from_location (this, zone_combo, NULL); -- -+ fill_location_tree (this); -+ - g_object_set_data (G_OBJECT (edit_window), "intlclock-location", NULL); - gtk_window_present (GTK_WINDOW (edit_window)); - } -@@ -2230,7 +2577,6 @@ run_prefs_locations_edit (GtkButton *button, gpointer this) - { - IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); - -- GtkTreeModel *model = gtk_tree_view_get_model (priv->prefs_locations);; - GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->prefs_locations)); - - gtk_tree_selection_selected_foreach (sel, edit_tree_row, this); -@@ -2245,7 +2591,6 @@ run_prefs_edit_save (GtkButton *button, gpointer this) - IntlClockZoneTable *zones = intlclock_get_zonetable (priv->clock); - - IntlClockLocation *loc = g_object_get_data (G_OBJECT (edit_window), "intlclock-location"); -- - GtkWidget *zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); - GtkWidget *name_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-name-entry"); - -@@ -2255,6 +2600,8 @@ run_prefs_edit_save (GtkButton *button, gpointer this) - GtkWidget *lon_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-combo"); - - gchar *timezone_l10n = gtk_combo_box_get_active_text (GTK_COMBO_BOX (zone_combo)); -+ gchar *weather_code = g_object_get_data (G_OBJECT (edit_window), "weather-code"); -+ - IntlClockZoneInfo *info = intlclock_zonetable_get_l10n_zone (zones, timezone_l10n); - - if (!info) { -@@ -2281,9 +2628,11 @@ run_prefs_edit_save (GtkButton *button, gpointer this) - intlclock_location_set_timezone (loc, intlclock_zoneinfo_get_name (info)); - intlclock_location_set_name (loc, name); - intlclock_location_set_coords (loc, lat, lon); -+ intlclock_location_set_weather_code (loc, weather_code); - } else { - GList *locs; -- loc = intlclock_location_new (name, intlclock_zoneinfo_get_name (info), lat, lon); -+ -+ loc = intlclock_location_new (name, intlclock_zoneinfo_get_name (info), lat, lon, weather_code); - - locs = g_list_copy (intlclock_get_locations (priv->clock)); - locs = g_list_append (locs, loc); -@@ -2294,3 +2643,11 @@ run_prefs_edit_save (GtkButton *button, gpointer this) - - intlclock_edit_hide (edit_window, this); - } -+ -+void -+intlclock_ui_update_weather_icon (IntlClockUI *ui, GdkPixbuf *pixbuf) -+{ -+ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (ui)); -+ -+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->panel_weather_icon), pixbuf); -+} -diff --git a/src/intlclock-ui.h b/src/intlclock-ui.h -index ecbee03..a10099a 100644 ---- a/src/intlclock-ui.h -+++ b/src/intlclock-ui.h -@@ -29,6 +29,8 @@ GType intlclock_ui_get_type (void); - - IntlClockUI *intlclock_ui_new (IntlClock *clock, PanelApplet *applet); - gboolean intlclock_ui_is_12hr (IntlClockUI *ui); -+void intlclock_ui_edit_locations (IntlClockUI *ui); -+void intlclock_ui_update_weather_icon (IntlClockUI *ui, GdkPixbuf *pixbuf); - - G_END_DECLS - #endif /* __INTLCLOCK_UI_H__ */ -diff --git a/src/intlclock-zonetable.c b/src/intlclock-zonetable.c -index a2a0b6f..e6e27cb 100644 ---- a/src/intlclock-zonetable.c -+++ b/src/intlclock-zonetable.c -@@ -27,8 +27,6 @@ typedef struct { - GHashTable *country_table; - } IntlClockZoneTablePrivate; - --#define USE_CRIPPLED_ZONELIST 1 -- - /* Seeded with the list from Nat's Blackberry */ - char *available_zones[] = { - /* Eniwetok (-12) */ -diff --git a/src/intlclock.c b/src/intlclock.c -index 02f5b0a..552c45c 100644 ---- a/src/intlclock.c -+++ b/src/intlclock.c -@@ -32,6 +32,8 @@ typedef struct { - enum { - TICK, - LOCATIONS_CHANGED, -+ BLINK_LOCATION, -+ CURRENT_TIMEZONE_CHANGED, - LAST_SIGNAL - }; - -@@ -87,7 +89,25 @@ intlclock_class_init (IntlClockClass *this_class) - _intlclock_marshal_VOID__VOID, - G_TYPE_NONE, 0); - -- g_type_class_add_private (this_class, sizeof (IntlClockPrivate)); -+ intlclock_signals[BLINK_LOCATION] = g_signal_new -+ ("blink-location", -+ G_OBJECT_CLASS_TYPE (obj_class), -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (IntlClockClass, blink_location), -+ NULL, NULL, -+ _intlclock_marshal_VOID__OBJECT, -+ G_TYPE_NONE, 1, INTLCLOCK_LOCATION_TYPE); -+ -+ intlclock_signals[CURRENT_TIMEZONE_CHANGED] = g_signal_new -+ ("current-timezone-changed", -+ G_OBJECT_CLASS_TYPE (obj_class), -+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, -+ G_STRUCT_OFFSET (IntlClockClass, current_timezone_changed), -+ NULL, NULL, -+ _intlclock_marshal_VOID__VOID, -+ G_TYPE_NONE, 0); -+ -+ g_type_class_add_private (this_class, sizeof (IntlClockPrivate)); - } - - static void -@@ -133,7 +153,7 @@ intlclock_set_locations (IntlClock *this, GList *locations) - - priv->locations = locations; - -- g_signal_emit_by_name (this, "locations-changed"); -+ g_signal_emit (this, intlclock_signals[LOCATIONS_CHANGED], 0); - } - - GList * -@@ -202,7 +222,7 @@ intlclock_emit_tick (gpointer data) - IntlClock *this = INTLCLOCK (data); - IntlClockPrivate *priv = PRIVATE (this); - -- g_signal_emit_by_name (this, "tick"); -+ g_signal_emit (this, intlclock_signals[TICK], 0); - - if (priv->in_partial_timeout) { - intlclock_reset_timeout (this); -@@ -353,3 +373,9 @@ intlclock_free_locations (IntlClock *this) - g_list_free (priv->locations); - priv->locations = NULL; - } -+ -+void -+intlclock_blink_location (IntlClock *this, IntlClockLocation *loc) -+{ -+ g_signal_emit (this, intlclock_signals[BLINK_LOCATION], 0, loc); -+} -diff --git a/src/intlclock.h b/src/intlclock.h -index 3b0012c..20c681d 100644 ---- a/src/intlclock.h -+++ b/src/intlclock.h -@@ -27,6 +27,9 @@ typedef struct - - void (* tick) (IntlClock *clock); - void (* locations_changed) (IntlClock *clock); -+ void (* blink_location) (IntlClock *clock, IntlClockLocation *loc); -+ void (* current_timezone_changed) (IntlClock *clock); -+ - } IntlClockClass; - - GType intlclock_get_type (void); -@@ -35,6 +38,7 @@ IntlClock *intlclock_new (void); - - void intlclock_set_locations (IntlClock *this, GList *list); - GList *intlclock_get_locations (IntlClock *this); -+void intlclock_blink_location (IntlClock *this, IntlClockLocation *loc); - - IntlClockZoneTable *intlclock_get_zonetable (IntlClock *this); - gchar *intlclock_format_time (IntlClock *this, struct tm *now, -diff --git a/src/set-timezone.c b/src/set-timezone.c -new file mode 100644 -index 0000000..5c96149 ---- /dev/null -+++ b/src/set-timezone.c -@@ -0,0 +1,426 @@ -+/* -*- 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 -+#include -+ -+static DBusGConnection * -+get_session_bus (void) -+{ -+ GError *error; -+ static DBusGConnection *bus = NULL; -+ -+ if (bus == NULL) { -+ error = NULL; -+ bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); -+ if (bus == NULL) { -+ g_warning ("Couldn't connect to session bus: %s", -+ error->message); -+ g_error_free (error); -+ } -+ } -+ -+ return bus; -+} -+ -+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; -+} -+ -+static PolKitContext * -+get_pk_context (void) -+{ -+ static PolKitContext *pk_context = NULL; -+ -+ if (pk_context == NULL) { -+ pk_context = polkit_context_new (); -+ if (!polkit_context_init (pk_context, NULL)) { -+ polkit_context_unref (pk_context); -+ pk_context = NULL; -+ } -+ } -+ -+ return pk_context; -+} -+ -+gboolean -+set_system_timezone (const char *filename, GError **err) -+{ -+ DBusGConnection *session_bus; -+ DBusGConnection *system_bus; -+ DBusGProxy *mechanism_proxy; -+ DBusGProxy *polkit_gnome_proxy; -+ gboolean ret = FALSE; -+ -+ session_bus = get_session_bus (); -+ if (session_bus == NULL) -+ goto out; -+ -+ system_bus = get_system_bus (); -+ if (system_bus == NULL) -+ goto out; -+ -+ mechanism_proxy = dbus_g_proxy_new_for_name (system_bus, -+ "org.gnome.ClockApplet.Mechanism", -+ "/", -+ "org.gnome.ClockApplet.Mechanism"); -+ -+ polkit_gnome_proxy = dbus_g_proxy_new_for_name (session_bus, -+ "org.gnome.PolicyKit", -+ "/org/gnome/PolicyKit/Manager", -+ "org.gnome.PolicyKit.Manager"); -+ -+ if (filename != NULL) { -+ GError *error; -+ -+ g_debug ("Trying to set timezone '%s'", filename); -+ try_again: -+ error = NULL; -+ /* first, try to call into the mechanism */ -+ if (!dbus_g_proxy_call_with_timeout (mechanism_proxy, -+ "SetTimezone", -+ INT_MAX, -+ &error, -+ /* parameters: */ -+ G_TYPE_STRING, filename, -+ G_TYPE_INVALID, -+ /* return values: */ -+ G_TYPE_INVALID)) { -+ if (dbus_g_error_has_name (error, "org.gnome.ClockApplet.Mechanism.NotPrivileged")) { -+ char **tokens; -+ char *polkit_result_textual; -+ char *polkit_action; -+ gboolean gained_privilege; -+ -+ tokens = g_strsplit (error->message, " ", 2); -+ g_error_free (error); -+ if (g_strv_length (tokens) != 2) { -+ g_warning ("helper return string malformed"); -+ g_strfreev (tokens); -+ goto out; -+ } -+ polkit_action = tokens[0]; -+ polkit_result_textual = tokens[1]; -+ -+ g_debug ("helper refused; returned polkit_result='%s' and polkit_action='%s'", -+ polkit_result_textual, polkit_action); -+ -+ /* Now ask the user for auth... */ -+ if (!dbus_g_proxy_call_with_timeout (polkit_gnome_proxy, -+ "ShowDialog", -+ INT_MAX, -+ &error, -+ /* parameters: */ -+ G_TYPE_STRING, polkit_action, -+ G_TYPE_UINT, 0, /* X11 window ID; none */ -+ G_TYPE_INVALID, -+ /* return values: */ -+ G_TYPE_BOOLEAN, &gained_privilege, -+ G_TYPE_INVALID)) { -+ g_propagate_error (err, error); -+ g_strfreev (tokens); -+ goto out; -+ } -+ g_strfreev (tokens); -+ -+ if (gained_privilege) { -+ g_debug ("Gained privilege; trying to set timezone again"); -+ goto try_again; -+ } -+ -+ } else { -+ g_propagate_error (err, error); -+ } -+ goto out; -+ } -+ -+ g_debug ("Successfully set time zone to '%s'", filename); -+ } -+ -+ ret = TRUE; -+out: -+ g_object_unref (mechanism_proxy); -+ g_object_unref (polkit_gnome_proxy); -+ -+ return ret; -+} -+ -+static gint -+can_do (const gchar *pk_action_id) -+{ -+ DBusConnection *system_bus; -+ PolKitCaller *pk_caller; -+ PolKitAction *pk_action; -+ PolKitResult pk_result; -+ PolKitContext *pk_context; -+ DBusError dbus_error; -+ gint res = 0; -+ -+ system_bus = dbus_g_connection_get_connection (get_system_bus ()); -+ if (system_bus == NULL) -+ goto out; -+ -+ pk_context = get_pk_context (); -+ if (pk_context == NULL) -+ goto out; -+ -+ pk_caller = NULL; -+ pk_action = NULL; -+ -+ pk_action = polkit_action_new (); -+ polkit_action_set_action_id (pk_action, pk_action_id); -+ -+ dbus_error_init (&dbus_error); -+ pk_caller = polkit_caller_new_from_pid (system_bus, getpid (), &dbus_error); -+ if (pk_caller == NULL) { -+ fprintf (stderr, "cannot get caller from dbus name\n"); -+ goto out; -+ } -+ -+ pk_result = polkit_context_can_caller_do_action (pk_context, pk_action, pk_caller); -+ -+ switch (pk_result) { -+ default: -+ case POLKIT_RESULT_UNKNOWN: -+ case POLKIT_RESULT_NO: -+ res = 0; -+ break; -+ case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH: -+ case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_SESSION: -+ case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_ALWAYS: -+ case POLKIT_RESULT_ONLY_VIA_SELF_AUTH: -+ case POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_SESSION: -+ case POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_ALWAYS: -+ res = 1; -+ break; -+ case POLKIT_RESULT_YES: -+ res = 2; -+ break; -+ } -+ -+out: -+ if (pk_action != NULL) -+ polkit_action_unref (pk_action); -+ if (pk_caller != NULL) -+ polkit_caller_unref (pk_caller); -+ -+ return res; -+} -+ -+gint -+can_set_system_timezone (void) -+{ -+ return can_do ("org.gnome.clockapplet.mechanism.settimezone"); -+} -+ -+gint -+can_set_system_time (void) -+{ -+ return can_do ("org.gnome.clockapplet.mechanism.settime"); -+} -+ -+typedef struct { -+ gint ref_count; -+ gint64 time; -+ 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); -+ } -+} -+ -+static void set_time_async (SetTimeCallbackData *data); -+ -+static void -+auth_notify (DBusGProxy *proxy, -+ DBusGProxyCall *call, -+ void *user_data) -+{ -+ SetTimeCallbackData *data = user_data; -+ GError *error = NULL; -+ gboolean gained_privilege; -+ -+ if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_BOOLEAN, &gained_privilege, G_TYPE_INVALID)) { -+ if (gained_privilege) -+ set_time_async (data); -+ } -+ else { -+ if (data->callback) -+ data->callback (data->data, error); -+ else -+ g_error_free (error); -+ } -+} -+ -+static void -+do_auth_async (const gchar *action, -+ const gchar *result, -+ SetTimeCallbackData *data) -+{ -+ DBusGConnection *bus; -+ DBusGProxy *proxy; -+ -+ g_debug ("helper refused; returned polkit_result='%s' and polkit_action='%s'", -+ result, action); -+ -+ /* Now ask the user for auth... */ -+ bus = get_session_bus (); -+ if (bus == NULL) -+ return; -+ -+ proxy = dbus_g_proxy_new_for_name (bus, -+ "org.gnome.PolicyKit", -+ "/org/gnome/PolicyKit/Manager", -+ "org.gnome.PolicyKit.Manager"); -+ -+ data->ref_count++; -+ dbus_g_proxy_begin_call_with_timeout (proxy, -+ "ShowDialog", -+ auth_notify, -+ data, free_data, -+ INT_MAX, -+ G_TYPE_STRING, action, -+ G_TYPE_UINT, 0, -+ G_TYPE_INVALID); -+} -+ -+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 (dbus_g_error_has_name (error, "org.gnome.ClockApplet.Mechanism.NotPrivileged")) { -+ gchar **tokens; -+ -+ tokens = g_strsplit (error->message, " ", 2); -+ g_error_free (error); -+ if (g_strv_length (tokens) == 2) -+ do_auth_async (tokens[0], tokens[1], data); -+ else -+ g_warning ("helper return string malformed"); -+ g_strfreev (tokens); -+ } -+ 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; -+ DBusGProxyCall *call; -+ -+ bus = get_system_bus (); -+ if (bus == NULL) -+ return; -+ -+ proxy = dbus_g_proxy_new_for_name (bus, -+ "org.gnome.ClockApplet.Mechanism", -+ "/", -+ "org.gnome.ClockApplet.Mechanism"); -+ -+ data->ref_count++; -+ 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); -+} -+ -+void -+set_system_time_async (gint64 time, -+ GFunc callback, -+ gpointer d, -+ GDestroyNotify notify) -+{ -+ SetTimeCallbackData *data; -+ -+ if (time == -1) -+ return; -+ -+ data = g_new (SetTimeCallbackData, 1); -+ data->ref_count = 1; -+ data->time = time; -+ data->callback = callback; -+ data->data = d; -+ data->notify = notify; -+ -+ set_time_async (data); -+ free_data (data); -+} -diff --git a/src/set-timezone.h b/src/set-timezone.h -new file mode 100644 -index 0000000..c71622c ---- /dev/null -+++ b/src/set-timezone.h -@@ -0,0 +1,36 @@ -+/* -*- 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 -+ -+gboolean set_system_timezone (const char *filename, -+ GError **err); -+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); -+ -+#endif diff --git a/intlclock-changes-20071014.patch b/intlclock-changes-20071014.patch new file mode 100644 index 0000000..2dd2910 --- /dev/null +++ b/intlclock-changes-20071014.patch @@ -0,0 +1,12308 @@ +diff --git a/configure.in b/configure.in +index 4e818da..6c75db1 100644 +--- a/configure.in ++++ b/configure.in +@@ -59,7 +59,7 @@ if test -n "$LIBECAL_REQUIREMENT"; then + fi + AM_CONDITIONAL(HAVE_LIBECAL, test -n "$LIBECAL_REQUIREMENT") + +-PKG_CHECK_MODULES(INTLCLOCK, [ glib-2.0 gobject-2.0 gtk+-2.0 gdk-2.0 librsvg-2.0 libpanelapplet-2.0 libgnome-2.0 gconf-2.0 $LIBECAL_REQUIREMENT ]) ++PKG_CHECK_MODULES(INTLCLOCK, [ glib-2.0 gobject-2.0 gtk+-2.0 gdk-2.0 librsvg-2.0 libpanelapplet-2.0 libgnome-2.0 gconf-2.0 $LIBECAL_REQUIREMENT dbus-glib-1 gweather libxml-2.0 polkit polkit-dbus ]) + + AC_SUBST(INTLCLOCK_CFLAGS) + AC_SUBST(INTLCLOCK_LIBS) +diff --git a/data/GNOME_IntlClockApplet.xml b/data/GNOME_IntlClockApplet.xml +index dd2e8b8..a88dc3d 100644 +--- a/data/GNOME_IntlClockApplet.xml ++++ b/data/GNOME_IntlClockApplet.xml +@@ -1,9 +1,14 @@ + + + ++ ++ ++ + ++ _label="Ad_just Date & Time" ++ pixtype="stock" pixname="gtk-preferences"/> + + +diff --git a/data/GNOME_IntlClockApplet_Factory.server.in.in b/data/GNOME_IntlClockApplet_Factory.server.in.in +index 1446822..705fb76 100644 +--- a/data/GNOME_IntlClockApplet_Factory.server.in.in ++++ b/data/GNOME_IntlClockApplet_Factory.server.in.in +@@ -20,7 +20,7 @@ + + + +- ++ + + + + ++ 6 + True + False + 0 + + +- ++ + 6 + True + True +@@ -37,194 +38,35 @@ + False + + +- +- 6 ++ ++ 12 + True +- 4 +- 3 + False +- 6 +- 6 ++ 18 + + +- +- True +- Clock options: +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 0 +- 1 +- 0 +- 1 +- fill +- +- +- +- +- +- +- True +- +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 0 +- 1 +- 1 +- 2 +- fill +- +- +- +- +- +- +- True +- +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 0 +- 1 +- 2 +- 3 +- fill +- +- +- +- +- +- +- True +- +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 0 +- 1 +- 3 +- 4 +- fill +- +- +- +- +- +- +- True +- +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 2 +- 3 +- 3 +- 4 +- fill +- +- +- +- +- +- +- True +- True +- Show s_econds +- True +- GTK_RELIEF_NORMAL +- True +- False +- False +- True +- +- +- 1 +- 3 +- 2 +- 3 +- fill +- +- +- +- +- +- ++ + True + False + 6 + + +- ++ + True +- True +- 12 _hour format +- True +- GTK_RELIEF_NORMAL +- True +- False +- False +- True ++ <b>Clock Options</b> ++ False ++ True ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 + + + 0 +@@ -234,138 +76,150 @@ + + + +- ++ + True +- True +- 24 h_our format +- True +- GTK_RELIEF_NORMAL +- True +- False +- False +- True +- 12hr_radio ++ False ++ 0 ++ ++ ++ ++ True ++ ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ False ++ 6 ++ ++ ++ ++ True ++ False ++ 13 ++ ++ ++ ++ True ++ True ++ 12 _hour format ++ True ++ GTK_RELIEF_NORMAL ++ True ++ False ++ False ++ True ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ True ++ 24 h_our format ++ True ++ GTK_RELIEF_NORMAL ++ True ++ False ++ False ++ True ++ 12hr_radio ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ True ++ Show the _date ++ True ++ GTK_RELIEF_NORMAL ++ True ++ False ++ False ++ True ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ True ++ Show _seconds ++ True ++ GTK_RELIEF_NORMAL ++ True ++ False ++ False ++ True ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ 0 ++ True ++ True ++ ++ + + + 0 +- False +- False ++ True ++ True + + + + +- 1 +- 2 +- 0 +- 1 +- fill +- fill +- +- +- +- +- +- True +- True +- Show the _date +- True +- GTK_RELIEF_NORMAL +- True +- False +- False +- True +- +- +- 1 +- 2 +- 1 +- 2 +- fill +- +- +- +- +- +- +- True +- +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 2 +- 3 +- 0 +- 1 +- fill +- +- +- +- +- +- +- True +- +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 2 +- 3 +- 1 +- 2 +- fill +- +- +- +- +- +- +- True +- +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 1 +- 2 +- 3 +- 4 +- fill +- ++ 0 ++ False ++ True + + + +@@ -376,7 +230,7 @@ + + + +- ++ + True + General + False +@@ -399,332 +253,105 @@ + + + +- +- 6 ++ ++ 12 + True +- 8 +- 4 + False +- 6 +- 6 +- +- +- +- True +- +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 3 +- 4 +- 0 +- 1 +- fill +- +- +- +- +- +- +- True +- +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 3 +- 4 +- 1 +- 2 +- fill +- +- +- ++ 18 + + +- ++ + True +- True +- GTK_POLICY_NEVER +- GTK_POLICY_NEVER +- GTK_SHADOW_IN +- GTK_CORNER_TOP_LEFT ++ False ++ 12 + + +- ++ + True + True +- False +- False +- False +- True +- False +- False +- True ++ GTK_POLICY_NEVER ++ GTK_POLICY_NEVER ++ GTK_SHADOW_IN ++ GTK_CORNER_TOP_LEFT ++ ++ ++ ++ True ++ True ++ False ++ False ++ False ++ True ++ False ++ False ++ True ++ ++ + ++ ++ 0 ++ True ++ True ++ + +- +- +- 0 +- 3 +- 2 +- 8 +- fill +- +- +- +- +- +- True +- 0 +- 0.5 +- 0 +- 1 +- 0 +- 0 +- 0 +- 0 + + +- ++ + True +- False ++ GTK_BUTTONBOX_START + 6 + + +- ++ ++ 24 ++ 25 + True +- +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0.5 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 ++ True ++ True ++ gtk-add ++ True ++ GTK_RELIEF_NORMAL ++ True + +- +- 0 +- False +- False +- + + + +- ++ ++ 24 ++ 24 + True +- GTK_BUTTONBOX_START +- 6 +- +- +- +- 24 +- 25 +- True +- True +- True +- gtk-add +- True +- GTK_RELIEF_NORMAL +- True +- +- +- +- +- +- 24 +- 24 +- True +- True +- True +- gtk-edit +- True +- GTK_RELIEF_NORMAL +- True +- +- +- +- +- +- True +- True +- True +- gtk-remove +- True +- GTK_RELIEF_NORMAL +- True +- +- ++ True ++ True ++ gtk-edit ++ True ++ GTK_RELIEF_NORMAL ++ True + +- +- 0 +- False +- False +- + + + +- ++ + True +- +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0.5 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 ++ True ++ True ++ gtk-remove ++ True ++ GTK_RELIEF_NORMAL ++ True + +- +- 0 +- False +- False +- + + ++ ++ 0 ++ False ++ False ++ + + + +- 3 +- 4 +- 2 +- 8 +- +- fill +- +- +- +- +- +- True +- True +- Show the world _map in the clock +- True +- GTK_RELIEF_NORMAL +- True +- False +- False +- True +- +- +- 0 +- 1 +- 1 +- 2 +- fill +- +- +- +- +- +- +- True +- +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0.5 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 2 +- 3 +- 1 +- 2 +- +- +- +- +- +- +- True +- +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 1 +- 2 +- 1 +- 2 +- fill +- +- +- +- +- +- +- True +- True +- S_how locations in the clock +- True +- GTK_RELIEF_NORMAL +- True +- False +- False +- True +- +- +- 0 +- 3 +- 0 +- 1 +- fill +- ++ 0 ++ True ++ True + + + +@@ -735,7 +362,7 @@ + + + +- ++ + True + Locations + False +@@ -772,95 +399,20 @@ + 0 + + +- +- True +- GTK_BUTTONBOX_DEFAULT_STYLE +- 0 +- +- +- 0 +- False +- False +- +- +- +- +- ++ + True + GTK_BUTTONBOX_END + 6 + + +- ++ + True + True + True ++ Time Settings ++ True + GTK_RELIEF_NORMAL + True +- +- +- +- True +- 0.5 +- 0.5 +- 0 +- 0 +- 0 +- 0 +- 0 +- 0 +- +- +- +- True +- False +- 2 +- +- +- +- True +- gtk-properties +- 4 +- 0.5 +- 0.5 +- 0 +- 0 +- +- +- 0 +- False +- False +- +- +- +- +- +- True +- Time _Settings +- True +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0.5 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 0 +- False +- False +- +- +- +- +- +- + + + +@@ -910,13 +462,13 @@ + + + ++ 12 + True + False +- 0 ++ 24 + + + +- 6 + True + 1 + 3 +@@ -926,7 +478,6 @@ + + + +- 6 + True + False + 6 +@@ -974,62 +525,6 @@ + 6 + + +- +- True +- Timezone: +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 0 +- 1 +- 0 +- 1 +- fill +- +- +- +- +- +- +- True +- Location Name: +- False +- False +- GTK_JUSTIFY_LEFT +- False +- False +- 0 +- 0.5 +- 0 +- 0 +- PANGO_ELLIPSIZE_NONE +- -1 +- False +- 0 +- +- +- 0 +- 1 +- 1 +- 2 +- fill +- +- +- +- +- + + True + True +@@ -1070,45 +565,6 @@ + + + +- +- True +- Dummy Item +- False +- True +- True +- +- +- 1 +- 4 +- 0 +- 1 +- fill +- fill +- +- +- +- +- +- True +- True +- True +- True +- 0 +- +- True +- +- False +- +- +- 1 +- 4 +- 1 +- 2 +- +- +- +- +- + + True + Longitude: +@@ -1145,7 +601,7 @@ + 0 + + True +- ++ + False + + +@@ -1258,7 +714,7 @@ South + 0 + + True +- ++ + False + + +@@ -1269,6 +725,131 @@ South + + + ++ ++ ++ ++ True ++ Location Name: ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ 1 ++ 0 ++ 1 ++ fill ++ ++ ++ ++ ++ ++ ++ True ++ Timezone: ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ 1 ++ 1 ++ 2 ++ fill ++ ++ ++ ++ ++ ++ ++ True ++ False ++ 6 ++ ++ ++ ++ True ++ True ++ True ++ True ++ 0 ++ ++ True ++ ++ False ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ True ++ Find... ++ True ++ GTK_RELIEF_NORMAL ++ True ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ 1 ++ 4 ++ 0 ++ 1 ++ fill ++ fill ++ ++ ++ ++ ++ ++ True ++ Dummy Item ++ False ++ True ++ True ++ ++ ++ 1 ++ 4 ++ 1 ++ 2 ++ fill ++ fill ++ ++ + + + 0 +@@ -1294,60 +875,33 @@ South + + + +- +- 6 ++ + True +- False +- 0 ++ GTK_BUTTONBOX_END ++ 6 + + +- ++ + True +- GTK_BUTTONBOX_DEFAULT_STYLE +- 0 ++ True ++ True ++ gtk-cancel ++ True ++ GTK_RELIEF_NORMAL ++ True + +- +- 0 +- False +- False +- + + + +- ++ + True +- GTK_BUTTONBOX_END +- 6 +- +- +- +- True +- True +- True +- gtk-cancel +- True +- GTK_RELIEF_NORMAL +- True +- +- +- +- +- +- True +- True +- True +- gtk-ok +- True +- GTK_RELIEF_NORMAL +- True +- +- ++ True ++ True ++ gtk-ok ++ True ++ GTK_RELIEF_NORMAL ++ True + +- +- 0 +- True +- True +- + + + +@@ -1723,4 +1277,580 @@ South + + + ++ ++ ++ GTK_WINDOW_TOPLEVEL ++ GTK_WIN_POS_NONE ++ False ++ True ++ False ++ True ++ False ++ False ++ GDK_WINDOW_TYPE_HINT_NORMAL ++ GDK_GRAVITY_NORTH_WEST ++ True ++ False ++ ++ ++ ++ 12 ++ True ++ False ++ 24 ++ ++ ++ ++ True ++ False ++ 6 ++ ++ ++ ++ True ++ True ++ GTK_POLICY_AUTOMATIC ++ GTK_POLICY_AUTOMATIC ++ GTK_SHADOW_IN ++ GTK_CORNER_TOP_LEFT ++ ++ ++ ++ True ++ True ++ False ++ False ++ False ++ False ++ False ++ False ++ False ++ ++ ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ False ++ 6 ++ ++ ++ ++ True ++ _Find: ++ True ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ find-location-entry ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ True ++ True ++ True ++ 0 ++ ++ True ++ ++ False ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ True ++ GTK_RELIEF_NORMAL ++ True ++ ++ ++ ++ True ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ 0 ++ 0 ++ 0 ++ 0 ++ ++ ++ ++ True ++ False ++ 2 ++ ++ ++ ++ True ++ gtk-find ++ 4 ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ Find _Next ++ True ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ GTK_BUTTONBOX_END ++ 0 ++ ++ ++ ++ True ++ True ++ True ++ gtk-cancel ++ True ++ GTK_RELIEF_NORMAL ++ True ++ ++ ++ ++ ++ ++ True ++ True ++ True ++ gtk-ok ++ True ++ GTK_RELIEF_NORMAL ++ True ++ ++ ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ ++ ++ 12 ++ Time Settings ++ GTK_WINDOW_TOPLEVEL ++ GTK_WIN_POS_NONE ++ False ++ True ++ False ++ True ++ False ++ False ++ GDK_WINDOW_TYPE_HINT_NORMAL ++ GDK_GRAVITY_NORTH_WEST ++ True ++ False ++ ++ ++ ++ True ++ False ++ 6 ++ ++ ++ ++ True ++ <b>Time Settings</b> ++ False ++ True ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ False ++ 0 ++ ++ ++ ++ True ++ ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ False ++ 12 ++ ++ ++ ++ True ++ True ++ GTK_CALENDAR_SHOW_HEADING ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ False ++ 6 ++ ++ ++ ++ True ++ Current Time: ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ Time: ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ False ++ 6 ++ ++ ++ ++ True ++ 23:59:59 ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ False ++ 0 ++ ++ ++ ++ True ++ True ++ 1 ++ 0 ++ True ++ GTK_UPDATE_ALWAYS ++ False ++ True ++ 23 0 23 1 12 12 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ True ++ 1 ++ 0 ++ True ++ GTK_UPDATE_ALWAYS ++ False ++ True ++ 59 0 59 1 30 30 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ True ++ 1 ++ 0 ++ True ++ GTK_UPDATE_ALWAYS ++ False ++ True ++ 59 0 59 1 30 30 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ 0 ++ False ++ True ++ ++ ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ False ++ 0 ++ ++ ++ ++ True ++ GTK_BUTTONBOX_END ++ 6 ++ ++ ++ ++ True ++ True ++ True ++ gtk-cancel ++ True ++ GTK_RELIEF_NORMAL ++ True ++ ++ ++ ++ ++ ++ True ++ True ++ Set System Time ++ True ++ GTK_RELIEF_NORMAL ++ True ++ ++ ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ 0 ++ False ++ False ++ GTK_PACK_END ++ ++ ++ ++ ++ ++ + +diff --git a/data/intlclock.schemas.in b/data/intlclock.schemas.in +index 2ab6772..00fee4f 100644 +--- a/data/intlclock.schemas.in ++++ b/data/intlclock.schemas.in +@@ -89,41 +89,54 @@ + + + +- /schemas/apps/intlclock_applet/prefs/show_locations ++ /schemas/apps/intlclock_applet/prefs/cities ++ clock-applet ++ list ++ string ++ [] ++ ++ List of cities for the clock. ++ ++ List of cities to display in the international clock. ++ ++ ++ ++ ++ ++ /schemas/apps/intlclock_applet/prefs/expand_locations + clock-applet + bool + true + +- Show other locations in clock ++ Expand the location section in clock + +- If true, show a list of locations in the international clock. ++ If true, expand the list of locations in the international clock. + + + + + +- /schemas/apps/intlclock_applet/prefs/show_map ++ /schemas/apps/intlclock_applet/prefs/expand_tasks + clock-applet + bool + true + +- Show world map in clock ++ Expand the tasks section in clock + +- If true, show the world map in the international clock. ++ If true, expand the list of tasks in the international clock. + + + + + +- /schemas/apps/intlclock_applet/prefs/cities ++ /schemas/apps/intlclock_applet/prefs/expand_appointments + clock-applet +- list +- string +- [] ++ bool ++ true + +- List of cities for the clock. ++ Expand the appointments section in clock + +- List of cities to display in the international clock. ++ If true, expand the list of appointments in the international clock. + + + +diff --git a/intltool-extract.in b/intltool-extract.in +deleted file mode 100755 +index bb6c368..340fc8d +--- a/intltool-extract.in ++++ /dev/null +@@ -1,841 +0,0 @@ +-#!@INTLTOOL_PERL@ -w +-# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- +- +-# +-# The Intltool Message Extractor +-# +-# Copyright (C) 2000-2001, 2003 Free Software Foundation. +-# +-# Intltool 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. +-# +-# Intltool 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., 675 Mass Ave, Cambridge, MA 02139, USA. +-# +-# As a special exception to the GNU General Public License, if you +-# distribute this file as part of a program that contains a +-# configuration script generated by Autoconf, you may include it under +-# the same distribution terms that you use for the rest of that program. +-# +-# Authors: Kenneth Christiansen +-# Darin Adler +-# +- +-## Release information +-my $PROGRAM = "intltool-extract"; +-my $PACKAGE = "intltool"; +-my $VERSION = "0.35.0"; +- +-## Loaded modules +-use strict; +-use File::Basename; +-use Getopt::Long; +- +-## Scalars used by the option stuff +-my $TYPE_ARG = "0"; +-my $LOCAL_ARG = "0"; +-my $HELP_ARG = "0"; +-my $VERSION_ARG = "0"; +-my $UPDATE_ARG = "0"; +-my $QUIET_ARG = "0"; +-my $SRCDIR_ARG = "."; +- +-my $FILE; +-my $OUTFILE; +- +-my $gettext_type = ""; +-my $input; +-my %messages = (); +-my %loc = (); +-my %count = (); +-my %comments = (); +-my $strcount = 0; +- +-my $XMLCOMMENT = ""; +- +-## Use this instead of \w for XML files to handle more possible characters. +-my $w = "[-A-Za-z0-9._:]"; +- +-## Always print first +-$| = 1; +- +-## Handle options +-GetOptions ( +- "type=s" => \$TYPE_ARG, +- "local|l" => \$LOCAL_ARG, +- "help|h" => \$HELP_ARG, +- "version|v" => \$VERSION_ARG, +- "update" => \$UPDATE_ARG, +- "quiet|q" => \$QUIET_ARG, +- "srcdir=s" => \$SRCDIR_ARG, +- ) or &error; +- +-&split_on_argument; +- +- +-## Check for options. +-## This section will check for the different options. +- +-sub split_on_argument { +- +- if ($VERSION_ARG) { +- &version; +- +- } elsif ($HELP_ARG) { +- &help; +- +- } elsif ($LOCAL_ARG) { +- &place_local; +- &extract; +- +- } elsif ($UPDATE_ARG) { +- &place_normal; +- &extract; +- +- } elsif (@ARGV > 0) { +- &place_normal; +- &message; +- &extract; +- +- } else { +- &help; +- +- } +-} +- +-sub place_normal { +- $FILE = $ARGV[0]; +- $OUTFILE = "$FILE.h"; +-} +- +-sub place_local { +- $FILE = $ARGV[0]; +- $OUTFILE = fileparse($FILE, ()); +- if (!-e "tmp/") { +- system("mkdir tmp/"); +- } +- $OUTFILE = "./tmp/$OUTFILE.h" +-} +- +-sub determine_type { +- if ($TYPE_ARG =~ /^gettext\/(.*)/) { +- $gettext_type=$1 +- } +-} +- +-## Sub for printing release information +-sub version{ +- print <<_EOF_; +-${PROGRAM} (${PACKAGE}) $VERSION +-Copyright (C) 2000, 2003 Free Software Foundation, Inc. +-Written by Kenneth Christiansen, 2000. +- +-This is free software; see the source for copying conditions. There is NO +-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +-_EOF_ +- exit; +-} +- +-## Sub for printing usage information +-sub help { +- print <<_EOF_; +-Usage: ${PROGRAM} [OPTION]... [FILENAME] +-Generates a header file from an XML source file. +- +-It grabs all strings between <_translatable_node> and its end tag in +-XML files. Read manpage (man ${PROGRAM}) for more info. +- +- --type=TYPE Specify the file type of FILENAME. Currently supports: +- "gettext/glade", "gettext/ini", "gettext/keys" +- "gettext/rfc822deb", "gettext/schemas", +- "gettext/scheme", "gettext/xml" +- -l, --local Writes output into current working directory +- (conflicts with --update) +- --update Writes output into the same directory the source file +- reside (conflicts with --local) +- --srcdir Root of the source tree +- -v, --version Output version information and exit +- -h, --help Display this help and exit +- -q, --quiet Quiet mode +- +-Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE") +-or send email to . +-_EOF_ +- exit; +-} +- +-## Sub for printing error messages +-sub error{ +- print STDERR "Try `${PROGRAM} --help' for more information.\n"; +- exit; +-} +- +-sub message { +- print "Generating C format header file for translation.\n" unless $QUIET_ARG; +-} +- +-sub extract { +- &determine_type; +- +- &convert; +- +- open OUT, ">$OUTFILE"; +- binmode (OUT) if $^O eq 'MSWin32'; +- &msg_write; +- close OUT; +- +- print "Wrote $OUTFILE\n" unless $QUIET_ARG; +-} +- +-sub convert { +- +- ## Reading the file +- { +- local (*IN); +- local $/; #slurp mode +- open (IN, "<$SRCDIR_ARG/$FILE") || die "can't open $SRCDIR_ARG/$FILE: $!"; +- $input = ; +- } +- +- &type_ini if $gettext_type eq "ini"; +- &type_keys if $gettext_type eq "keys"; +- &type_xml if $gettext_type eq "xml"; +- &type_glade if $gettext_type eq "glade"; +- &type_scheme if $gettext_type eq "scheme"; +- &type_schemas if $gettext_type eq "schemas"; +- &type_rfc822deb if $gettext_type eq "rfc822deb"; +-} +- +-sub entity_decode_minimal +-{ +- local ($_) = @_; +- +- s/'/'/g; # ' +- s/"/"/g; # " +- s/&/&/g; +- +- return $_; +-} +- +-sub entity_decode +-{ +- local ($_) = @_; +- +- s/'/'/g; # ' +- s/"/"/g; # " +- s/&/&/g; +- s/<//g; +- +- return $_; +-} +- +-sub escape_char +-{ +- return '\"' if $_ eq '"'; +- return '\n' if $_ eq "\n"; +- return '\\' if $_ eq '\\'; +- +- return $_; +-} +- +-sub escape +-{ +- my ($string) = @_; +- return join "", map &escape_char, split //, $string; +-} +- +-sub type_ini { +- ### For generic translatable desktop files ### +- while ($input =~ /^_.*=(.*)$/mg) { +- $messages{$1} = []; +- } +-} +- +-sub type_keys { +- ### For generic translatable mime/keys files ### +- while ($input =~ /^\s*_\w+=(.*)$/mg) { +- $messages{$1} = []; +- } +-} +- +-sub type_xml { +- ### For generic translatable XML files ### +- my $tree = readXml($input); +- parseTree(0, $tree); +-} +- +-sub print_var { +- my $var = shift; +- my $vartype = ref $var; +- +- if ($vartype =~ /ARRAY/) { +- my @arr = @{$var}; +- print "[ "; +- foreach my $el (@arr) { +- print_var($el); +- print ", "; +- } +- print "] "; +- } elsif ($vartype =~ /HASH/) { +- my %hash = %{$var}; +- print "{ "; +- foreach my $key (keys %hash) { +- print "$key => "; +- print_var($hash{$key}); +- print ", "; +- } +- print "} "; +- } else { +- print $var; +- } +-} +- +-# Same syntax as getAttributeString in intltool-merge.in.in, similar logic (look for ## differences comment) +-sub getAttributeString +-{ +- my $sub = shift; +- my $do_translate = shift || 1; +- my $language = shift || ""; +- my $translate = shift; +- my $result = ""; +- foreach my $e (reverse(sort(keys %{ $sub }))) { +- my $key = $e; +- my $string = $sub->{$e}; +- my $quote = '"'; +- +- $string =~ s/^[\s]+//; +- $string =~ s/[\s]+$//; +- +- if ($string =~ /^'.*'$/) +- { +- $quote = "'"; +- } +- $string =~ s/^['"]//g; +- $string =~ s/['"]$//g; +- +- ## differences from intltool-merge.in.in +- if ($key =~ /^_/) { +- $comments{entity_decode($string)} = $XMLCOMMENT if $XMLCOMMENT; +- $messages{entity_decode($string)} = []; +- $$translate = 2; +- } +- ## differences end here from intltool-merge.in.in +- $result .= " $key=$quote$string$quote"; +- } +- return $result; +-} +- +-# Verbatim copy from intltool-merge.in.in +-sub getXMLstring +-{ +- my $ref = shift; +- my $spacepreserve = shift || 0; +- my @list = @{ $ref }; +- my $result = ""; +- +- my $count = scalar(@list); +- my $attrs = $list[0]; +- my $index = 1; +- +- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); +- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); +- +- while ($index < $count) { +- my $type = $list[$index]; +- my $content = $list[$index+1]; +- if (! $type ) { +- # We've got CDATA +- if ($content) { +- # lets strip the whitespace here, and *ONLY* here +- $content =~ s/\s+/ /gs if (!$spacepreserve); +- $result .= $content; +- } +- } elsif ( "$type" ne "1" ) { +- # We've got another element +- $result .= "<$type"; +- $result .= getAttributeString(@{$content}[0], 0); # no nested translatable elements +- if ($content) { +- my $subresult = getXMLstring($content, $spacepreserve); +- if ($subresult) { +- $result .= ">".$subresult . ""; +- } else { +- $result .= "/>"; +- } +- } else { +- $result .= "/>"; +- } +- } +- $index += 2; +- } +- return $result; +-} +- +-# Verbatim copy from intltool-merge.in.in, except for MULTIPLE_OUTPUT handling removed +-# Translate list of nodes if necessary +-sub translate_subnodes +-{ +- my $fh = shift; +- my $content = shift; +- my $language = shift || ""; +- my $singlelang = shift || 0; +- my $spacepreserve = shift || 0; +- +- my @nodes = @{ $content }; +- +- my $count = scalar(@nodes); +- my $index = 0; +- while ($index < $count) { +- my $type = $nodes[$index]; +- my $rest = $nodes[$index+1]; +- traverse($fh, $type, $rest, $language, $spacepreserve); +- $index += 2; +- } +-} +- +-# Based on traverse() in intltool-merge.in.in +-sub traverse +-{ +- my $fh = shift; # unused, to allow us to sync code between -merge and -extract +- my $nodename = shift; +- my $content = shift; +- my $language = shift || ""; +- my $spacepreserve = shift || 0; +- +- if ($nodename && "$nodename" eq "1") { +- $XMLCOMMENT = $content; +- } elsif ($nodename) { +- # element +- my @all = @{ $content }; +- my $attrs = shift @all; +- my $translate = 0; +- my $outattr = getAttributeString($attrs, 1, $language, \$translate); +- +- if ($nodename =~ /^_/) { +- $translate = 1; +- $nodename =~ s/^_//; +- } +- my $lookup = ''; +- +- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); +- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); +- +- if ($translate) { +- $lookup = getXMLstring($content, $spacepreserve); +- if (!$spacepreserve) { +- $lookup =~ s/^\s+//s; +- $lookup =~ s/\s+$//s; +- } +- +- if ($lookup && $translate != 2) { +- $comments{$lookup} = $XMLCOMMENT if $XMLCOMMENT; +- $messages{$lookup} = []; +- } elsif ($translate == 2) { +- translate_subnodes($fh, \@all, $language, 1, $spacepreserve); +- } +- } else { +- $XMLCOMMENT = ""; +- my $count = scalar(@all); +- if ($count > 0) { +- my $index = 0; +- while ($index < $count) { +- my $type = $all[$index]; +- my $rest = $all[$index+1]; +- traverse($fh, $type, $rest, $language, $spacepreserve); +- $index += 2; +- } +- } +- } +- $XMLCOMMENT = ""; +- } +-} +- +- +-# Verbatim copy from intltool-merge.in.in, $fh for compatibility +-sub parseTree +-{ +- my $fh = shift; +- my $ref = shift; +- my $language = shift || ""; +- +- my $name = shift @{ $ref }; +- my $cont = shift @{ $ref }; +- +- while (!$name || "$name" eq "1") { +- $name = shift @{ $ref }; +- $cont = shift @{ $ref }; +- } +- +- my $spacepreserve = 0; +- my $attrs = @{$cont}[0]; +- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); +- +- traverse($fh, $name, $cont, $language, $spacepreserve); +-} +- +-# Verbatim copy from intltool-merge.in.in +-sub intltool_tree_comment +-{ +- my $expat = shift; +- my $data = $expat->original_string(); +- my $clist = $expat->{Curlist}; +- my $pos = $#$clist; +- +- $data =~ s/^$//s; +- push @$clist, 1 => $data; +-} +- +-# Verbatim copy from intltool-merge.in.in +-sub intltool_tree_cdatastart +-{ +- my $expat = shift; +- my $clist = $expat->{Curlist}; +- my $pos = $#$clist; +- +- push @$clist, 0 => $expat->original_string(); +-} +- +-# Verbatim copy from intltool-merge.in.in +-sub intltool_tree_cdataend +-{ +- my $expat = shift; +- my $clist = $expat->{Curlist}; +- my $pos = $#$clist; +- +- $clist->[$pos] .= $expat->original_string(); +-} +- +-# Verbatim copy from intltool-merge.in.in +-sub intltool_tree_char +-{ +- my $expat = shift; +- my $text = shift; +- my $clist = $expat->{Curlist}; +- my $pos = $#$clist; +- +- # Use original_string so that we retain escaped entities +- # in CDATA sections. +- # +- if ($pos > 0 and $clist->[$pos - 1] eq '0') { +- $clist->[$pos] .= $expat->original_string(); +- } else { +- push @$clist, 0 => $expat->original_string(); +- } +-} +- +-# Verbatim copy from intltool-merge.in.in +-sub intltool_tree_start +-{ +- my $expat = shift; +- my $tag = shift; +- my @origlist = (); +- +- # Use original_string so that we retain escaped entities +- # in attribute values. We must convert the string to an +- # @origlist array to conform to the structure of the Tree +- # Style. +- # +- my @original_array = split /\x/, $expat->original_string(); +- my $source = $expat->original_string(); +- +- # Remove leading tag. +- # +- $source =~ s|^\s*<\s*(\S+)||s; +- +- # Grab attribute key/value pairs and push onto @origlist array. +- # +- while ($source) +- { +- if ($source =~ /^\s*([\w:-]+)\s*[=]\s*["]/) +- { +- $source =~ s|^\s*([\w:-]+)\s*[=]\s*["]([^"]*)["]||s; +- push @origlist, $1; +- push @origlist, '"' . $2 . '"'; +- } +- elsif ($source =~ /^\s*([\w:-]+)\s*[=]\s*[']/) +- { +- $source =~ s|^\s*([\w:-]+)\s*[=]\s*[']([^']*)[']||s; +- push @origlist, $1; +- push @origlist, "'" . $2 . "'"; +- } +- else +- { +- last; +- } +- } +- +- my $ol = [ { @origlist } ]; +- +- push @{ $expat->{Lists} }, $expat->{Curlist}; +- push @{ $expat->{Curlist} }, $tag => $ol; +- $expat->{Curlist} = $ol; +-} +- +-# Copied from intltool-merge.in.in and added comment handler. +-sub readXml +-{ +- my $xmldoc = shift || return; +- my $ret = eval 'require XML::Parser'; +- if(!$ret) { +- die "You must have XML::Parser installed to run $0\n\n"; +- } +- my $xp = new XML::Parser(Style => 'Tree'); +- $xp->setHandlers(Char => \&intltool_tree_char); +- $xp->setHandlers(Start => \&intltool_tree_start); +- $xp->setHandlers(CdataStart => \&intltool_tree_cdatastart); +- $xp->setHandlers(CdataEnd => \&intltool_tree_cdataend); +- +- ## differences from intltool-merge.in.in +- $xp->setHandlers(Comment => \&intltool_tree_comment); +- ## differences end here from intltool-merge.in.in +- +- my $tree = $xp->parse($xmldoc); +- #print_var($tree); +- +-# Hello thereHowdydo +-# would be: +-# [foo, [{}, 1, "comment", head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]], bar, +-# [{}, 0, "Howdy", ref, [{}]], 0, "do" ] ] +- +- return $tree; +-} +- +-sub type_schemas { +- ### For schemas XML files ### +- +- # FIXME: We should handle escaped < (less than) +- while ($input =~ / +- \s* +- (\s*(?:\s*)?(.*?)\s*<\/default>\s*)? +- (\s*(?:\s*)?(.*?)\s*<\/short>\s*)? +- (\s*(?:\s*)?(.*?)\s*<\/long>\s*)? +- <\/locale> +- /sgx) { +- my @totranslate = ($3,$6,$9); +- my @eachcomment = ($2,$5,$8); +- foreach (@totranslate) { +- my $currentcomment = shift @eachcomment; +- next if !$_; +- s/\s+/ /g; +- $messages{entity_decode_minimal($_)} = []; +- $comments{entity_decode_minimal($_)} = $currentcomment if (defined($currentcomment)); +- } +- } +-} +- +-sub type_rfc822deb { +- ### For rfc822-style Debian configuration files ### +- +- my $lineno = 1; +- my $type = ''; +- while ($input =~ /\G(.*?)(^|\n)(_+)([^:]+):[ \t]*(.*?)(?=\n\S|$)/sg) +- { +- my ($pre, $newline, $underscore, $tag, $text) = ($1, $2, $3, $4, $5); +- while ($pre =~ m/\n/g) +- { +- $lineno ++; +- } +- $lineno += length($newline); +- my @str_list = rfc822deb_split(length($underscore), $text); +- for my $str (@str_list) +- { +- $strcount++; +- $messages{$str} = []; +- $loc{$str} = $lineno; +- $count{$str} = $strcount; +- my $usercomment = ''; +- while($pre =~ s/(^|\n)#([^\n]*)$//s) +- { +- $usercomment = "\n" . $2 . $usercomment; +- } +- $comments{$str} = $tag . $usercomment; +- } +- $lineno += ($text =~ s/\n//g); +- } +-} +- +-sub rfc822deb_split { +- # Debian defines a special way to deal with rfc822-style files: +- # when a value contain newlines, it consists of +- # 1. a short form (first line) +- # 2. a long description, all lines begin with a space, +- # and paragraphs are separated by a single dot on a line +- # This routine returns an array of all paragraphs, and reformat +- # them. +- # When first argument is 2, the string is a comma separated list of +- # values. +- my $type = shift; +- my $text = shift; +- $text =~ s/^[ \t]//mg; +- return (split(/, */, $text, 0)) if $type ne 1; +- return ($text) if $text !~ /\n/; +- +- $text =~ s/([^\n]*)\n//; +- my @list = ($1); +- my $str = ''; +- for my $line (split (/\n/, $text)) +- { +- chomp $line; +- if ($line =~ /^\.\s*$/) +- { +- # New paragraph +- $str =~ s/\s*$//; +- push(@list, $str); +- $str = ''; +- } +- elsif ($line =~ /^\s/) +- { +- # Line which must not be reformatted +- $str .= "\n" if length ($str) && $str !~ /\n$/; +- $line =~ s/\s+$//; +- $str .= $line."\n"; +- } +- else +- { +- # Continuation line, remove newline +- $str .= " " if length ($str) && $str !~ /\n$/; +- $str .= $line; +- } +- } +- $str =~ s/\s*$//; +- push(@list, $str) if length ($str); +- return @list; +-} +- +-sub type_glade { +- ### For translatable Glade XML files ### +- +- my $tags = "label|title|text|format|copyright|comments|preview_text|tooltip|message"; +- +- while ($input =~ /<($tags)>([^<]+)<\/($tags)>/sg) { +- # Glade sometimes uses tags that normally mark translatable things for +- # little bits of non-translatable content. We work around this by not +- # translating strings that only includes something like label4 or window1. +- $messages{entity_decode($2)} = [] unless $2 =~ /^(window|label|dialog)[0-9]+$/; +- } +- +- while ($input =~ /(..[^<]*)<\/items>/sg) { +- for my $item (split (/\n/, $1)) { +- $messages{entity_decode($item)} = []; +- } +- } +- +- ## handle new glade files +- while ($input =~ /<(property|atkproperty)\s+[^>]*translatable\s*=\s*"yes"(?:\s+[^>]*comments\s*=\s*"([^"]*)")?[^>]*>([^<]+)<\/\1>/sg) { +- $messages{entity_decode($3)} = [] unless $3 =~ /^(window|label)[0-9]+$/; +- if (defined($2) and !($3 =~ /^(window|label)[0-9]+$/)) { +- $comments{entity_decode($3)} = entity_decode($2) ; +- } +- } +- while ($input =~ /]*)"\s+description="([^>]+)"\/>/sg) { +- $messages{entity_decode_minimal($2)} = []; +- } +-} +- +-sub type_scheme { +- my ($line, $i, $state, $str, $trcomment, $char); +- for $line (split(/\n/, $input)) { +- $i = 0; +- $state = 0; # 0 - nothing, 1 - string, 2 - translatable string +- while ($i < length($line)) { +- if (substr($line,$i,1) eq "\"") { +- if ($state == 2) { +- $comments{$str} = $trcomment if ($trcomment); +- $messages{$str} = []; +- $str = ''; +- $state = 0; $trcomment = ""; +- } elsif ($state == 1) { +- $str = ''; +- $state = 0; $trcomment = ""; +- } else { +- $state = 1; +- $str = ''; +- if ($i>0 && substr($line,$i-1,1) eq '_') { +- $state = 2; +- } +- } +- } elsif (!$state) { +- if (substr($line,$i,1) eq ";") { +- $trcomment = substr($line,$i+1); +- $trcomment =~ s/^;*\s*//; +- $i = length($line); +- } elsif ($trcomment && substr($line,$i,1) !~ /\s|\(|\)|_/) { +- $trcomment = ""; +- } +- } else { +- if (substr($line,$i,1) eq "\\") { +- $char = substr($line,$i+1,1); +- if ($char ne "\"" && $char ne "\\") { +- $str = $str . "\\"; +- } +- $i++; +- } +- $str = $str . substr($line,$i,1); +- } +- $i++; +- } +- } +-} +- +-sub msg_write { +- my @msgids; +- if (%count) +- { +- @msgids = sort { $count{$a} <=> $count{$b} } keys %count; +- } +- else +- { +- @msgids = sort keys %messages; +- } +- for my $message (@msgids) +- { +- my $offsetlines = 1; +- $offsetlines++ if $message =~ /%/; +- if (defined ($comments{$message})) +- { +- while ($comments{$message} =~ m/\n/g) +- { +- $offsetlines++; +- } +- } +- print OUT "# ".($loc{$message} - $offsetlines). " \"$FILE\"\n" +- if defined $loc{$message}; +- print OUT "/* ".$comments{$message}." */\n" +- if defined $comments{$message}; +- print OUT "/* xgettext:no-c-format */\n" if $message =~ /%/; +- +- my @lines = split (/\n/, $message, -1); +- for (my $n = 0; $n < @lines; $n++) +- { +- if ($n == 0) +- { +- print OUT "char *s = N_(\""; +- } +- else +- { +- print OUT " \""; +- } +- +- print OUT escape($lines[$n]); +- +- if ($n < @lines - 1) +- { +- print OUT "\\n\"\n"; +- } +- else +- { +- print OUT "\");\n"; +- } +- } +- } +-} +- +diff --git a/intltool-extract.in b/intltool-extract.in +new file mode 120000 +index bb6c368..340fc8d +--- /dev/null ++++ b/intltool-extract.in +@@ -0,0 +1 @@ ++/usr/share/intltool/intltool-extract.in +\ No newline at end of file +diff --git a/intltool-merge.in b/intltool-merge.in +deleted file mode 100755 +index d0535ab..2238bbd +--- a/intltool-merge.in ++++ /dev/null +@@ -1,1356 +0,0 @@ +-#!@INTLTOOL_PERL@ -w +-# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- +- +-# +-# The Intltool Message Merger +-# +-# Copyright (C) 2000, 2003 Free Software Foundation. +-# Copyright (C) 2000, 2001 Eazel, Inc +-# +-# Intltool is free software; you can redistribute it and/or +-# modify it under the terms of the GNU General Public License +-# version 2 published by the Free Software Foundation. +-# +-# Intltool 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., 675 Mass Ave, Cambridge, MA 02139, USA. +-# +-# As a special exception to the GNU General Public License, if you +-# distribute this file as part of a program that contains a +-# configuration script generated by Autoconf, you may include it under +-# the same distribution terms that you use for the rest of that program. +-# +-# Authors: Maciej Stachowiak +-# Kenneth Christiansen +-# Darin Adler +-# +-# Proper XML UTF-8'ification written by Cyrille Chepelov +-# +- +-## Release information +-my $PROGRAM = "intltool-merge"; +-my $PACKAGE = "intltool"; +-my $VERSION = "0.35.0"; +- +-## Loaded modules +-use strict; +-use Getopt::Long; +-use Text::Wrap; +-use File::Basename; +- +-my $must_end_tag = -1; +-my $last_depth = -1; +-my $translation_depth = -1; +-my @tag_stack = (); +-my @entered_tag = (); +-my @translation_strings = (); +-my $leading_space = ""; +- +-## Scalars used by the option stuff +-my $HELP_ARG = 0; +-my $VERSION_ARG = 0; +-my $BA_STYLE_ARG = 0; +-my $XML_STYLE_ARG = 0; +-my $KEYS_STYLE_ARG = 0; +-my $DESKTOP_STYLE_ARG = 0; +-my $SCHEMAS_STYLE_ARG = 0; +-my $RFC822DEB_STYLE_ARG = 0; +-my $QUIET_ARG = 0; +-my $PASS_THROUGH_ARG = 0; +-my $UTF8_ARG = 0; +-my $MULTIPLE_OUTPUT = 0; +-my $cache_file; +- +-## Handle options +-GetOptions +-( +- "help" => \$HELP_ARG, +- "version" => \$VERSION_ARG, +- "quiet|q" => \$QUIET_ARG, +- "oaf-style|o" => \$BA_STYLE_ARG, ## for compatibility +- "ba-style|b" => \$BA_STYLE_ARG, +- "xml-style|x" => \$XML_STYLE_ARG, +- "keys-style|k" => \$KEYS_STYLE_ARG, +- "desktop-style|d" => \$DESKTOP_STYLE_ARG, +- "schemas-style|s" => \$SCHEMAS_STYLE_ARG, +- "rfc822deb-style|r" => \$RFC822DEB_STYLE_ARG, +- "pass-through|p" => \$PASS_THROUGH_ARG, +- "utf8|u" => \$UTF8_ARG, +- "multiple-output|m" => \$MULTIPLE_OUTPUT, +- "cache|c=s" => \$cache_file +- ) or &error; +- +-my $PO_DIR; +-my $FILE; +-my $OUTFILE; +- +-my %po_files_by_lang = (); +-my %translations = (); +-my $iconv = $ENV{"ICONV"} || $ENV{"INTLTOOL_ICONV"} || "@INTLTOOL_ICONV@"; +-my $devnull = ($^O eq 'MSWin32' ? 'NUL:' : '/dev/null'); +- +-# Use this instead of \w for XML files to handle more possible characters. +-my $w = "[-A-Za-z0-9._:]"; +- +-# XML quoted string contents +-my $q = "[^\\\"]*"; +- +-## Check for options. +- +-if ($VERSION_ARG) +-{ +- &print_version; +-} +-elsif ($HELP_ARG) +-{ +- &print_help; +-} +-elsif ($BA_STYLE_ARG && @ARGV > 2) +-{ +- &utf8_sanity_check; +- &preparation; +- &print_message; +- &ba_merge_translations; +- &finalize; +-} +-elsif ($XML_STYLE_ARG && @ARGV > 2) +-{ +- &utf8_sanity_check; +- &preparation; +- &print_message; +- &xml_merge_output; +- &finalize; +-} +-elsif ($KEYS_STYLE_ARG && @ARGV > 2) +-{ +- &utf8_sanity_check; +- &preparation; +- &print_message; +- &keys_merge_translations; +- &finalize; +-} +-elsif ($DESKTOP_STYLE_ARG && @ARGV > 2) +-{ +- &utf8_sanity_check; +- &preparation; +- &print_message; +- &desktop_merge_translations; +- &finalize; +-} +-elsif ($SCHEMAS_STYLE_ARG && @ARGV > 2) +-{ +- &utf8_sanity_check; +- &preparation; +- &print_message; +- &schemas_merge_translations; +- &finalize; +-} +-elsif ($RFC822DEB_STYLE_ARG && @ARGV > 2) +-{ +- &preparation; +- &print_message; +- &rfc822deb_merge_translations; +- &finalize; +-} +-else +-{ +- &print_help; +-} +- +-exit; +- +-## Sub for printing release information +-sub print_version +-{ +- print <<_EOF_; +-${PROGRAM} (${PACKAGE}) ${VERSION} +-Written by Maciej Stachowiak, Darin Adler and Kenneth Christiansen. +- +-Copyright (C) 2000-2003 Free Software Foundation, Inc. +-Copyright (C) 2000-2001 Eazel, Inc. +-This is free software; see the source for copying conditions. There is NO +-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +-_EOF_ +- exit; +-} +- +-## Sub for printing usage information +-sub print_help +-{ +- print <<_EOF_; +-Usage: ${PROGRAM} [OPTION]... PO_DIRECTORY FILENAME OUTPUT_FILE +-Generates an output file that includes some localized attributes from an +-untranslated source file. +- +-Mandatory options: (exactly one must be specified) +- -b, --ba-style includes translations in the bonobo-activation style +- -d, --desktop-style includes translations in the desktop style +- -k, --keys-style includes translations in the keys style +- -s, --schemas-style includes translations in the schemas style +- -r, --rfc822deb-style includes translations in the RFC822 style +- -x, --xml-style includes translations in the standard xml style +- +-Other options: +- -u, --utf8 convert all strings to UTF-8 before merging +- (default for everything except RFC822 style) +- -p, --pass-through deprecated, does nothing and issues a warning +- -m, --multiple-output output one localized file per locale, instead of +- a single file containing all localized elements +- -c, --cache=FILE specify cache file name +- (usually \$top_builddir/po/.intltool-merge-cache) +- -q, --quiet suppress most messages +- --help display this help and exit +- --version output version information and exit +- +-Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE") +-or send email to . +-_EOF_ +- exit; +-} +- +- +-## Sub for printing error messages +-sub print_error +-{ +- print STDERR "Try `${PROGRAM} --help' for more information.\n"; +- exit; +-} +- +- +-sub print_message +-{ +- print "Merging translations into $OUTFILE.\n" unless $QUIET_ARG; +-} +- +- +-sub preparation +-{ +- $PO_DIR = $ARGV[0]; +- $FILE = $ARGV[1]; +- $OUTFILE = $ARGV[2]; +- +- &gather_po_files; +- &get_translation_database; +-} +- +-# General-purpose code for looking up translations in .po files +- +-sub po_file2lang +-{ +- my ($tmp) = @_; +- $tmp =~ s/^.*\/(.*)\.po$/$1/; +- return $tmp; +-} +- +-sub gather_po_files +-{ +- for my $po_file (glob "$PO_DIR/*.po") { +- $po_files_by_lang{po_file2lang($po_file)} = $po_file; +- } +-} +- +-sub get_local_charset +-{ +- my ($encoding) = @_; +- my $alias_file = $ENV{"G_CHARSET_ALIAS"} || "@INTLTOOL_LIBDIR@/charset.alias"; +- +- # seek character encoding aliases in charset.alias (glib) +- +- if (open CHARSET_ALIAS, $alias_file) +- { +- while () +- { +- next if /^\#/; +- return $1 if (/^\s*([-._a-zA-Z0-9]+)\s+$encoding\b/i) +- } +- +- close CHARSET_ALIAS; +- } +- +- # if not found, return input string +- +- return $encoding; +-} +- +-sub get_po_encoding +-{ +- my ($in_po_file) = @_; +- my $encoding = ""; +- +- open IN_PO_FILE, $in_po_file or die; +- while () +- { +- ## example: "Content-Type: text/plain; charset=ISO-8859-1\n" +- if (/Content-Type\:.*charset=([-a-zA-Z0-9]+)\\n/) +- { +- $encoding = $1; +- last; +- } +- } +- close IN_PO_FILE; +- +- if (!$encoding) +- { +- print STDERR "Warning: no encoding found in $in_po_file. Assuming ISO-8859-1\n" unless $QUIET_ARG; +- $encoding = "ISO-8859-1"; +- } +- +- system ("$iconv -f $encoding -t UTF-8 <$devnull 2>$devnull"); +- if ($?) { +- $encoding = get_local_charset($encoding); +- } +- +- return $encoding +-} +- +-sub utf8_sanity_check +-{ +- print STDERR "Warning: option --pass-through has been removed.\n" if $PASS_THROUGH_ARG; +- $UTF8_ARG = 1; +-} +- +-sub get_translation_database +-{ +- if ($cache_file) { +- &get_cached_translation_database; +- } else { +- &create_translation_database; +- } +-} +- +-sub get_newest_po_age +-{ +- my $newest_age; +- +- foreach my $file (values %po_files_by_lang) +- { +- my $file_age = -M $file; +- $newest_age = $file_age if !$newest_age || $file_age < $newest_age; +- } +- +- $newest_age = 0 if !$newest_age; +- +- return $newest_age; +-} +- +-sub create_cache +-{ +- print "Generating and caching the translation database\n" unless $QUIET_ARG; +- +- &create_translation_database; +- +- open CACHE, ">$cache_file" || die; +- print CACHE join "\x01", %translations; +- close CACHE; +-} +- +-sub load_cache +-{ +- print "Found cached translation database\n" unless $QUIET_ARG; +- +- my $contents; +- open CACHE, "<$cache_file" || die; +- { +- local $/; +- $contents = ; +- } +- close CACHE; +- %translations = split "\x01", $contents; +-} +- +-sub get_cached_translation_database +-{ +- my $cache_file_age = -M $cache_file; +- if (defined $cache_file_age) +- { +- if ($cache_file_age <= &get_newest_po_age) +- { +- &load_cache; +- return; +- } +- print "Found too-old cached translation database\n" unless $QUIET_ARG; +- } +- +- &create_cache; +-} +- +-sub create_translation_database +-{ +- for my $lang (keys %po_files_by_lang) +- { +- my $po_file = $po_files_by_lang{$lang}; +- +- if ($UTF8_ARG) +- { +- my $encoding = get_po_encoding ($po_file); +- +- if (lc $encoding eq "utf-8") +- { +- open PO_FILE, "<$po_file"; +- } +- else +- { +- print "NOTICE: $po_file is not in UTF-8 but $encoding, converting...\n" unless $QUIET_ARG;; +- +- open PO_FILE, "$iconv -f $encoding -t UTF-8 $po_file|"; +- } +- } +- else +- { +- open PO_FILE, "<$po_file"; +- } +- +- my $nextfuzzy = 0; +- my $inmsgid = 0; +- my $inmsgstr = 0; +- my $msgid = ""; +- my $msgstr = ""; +- +- while () +- { +- $nextfuzzy = 1 if /^#, fuzzy/; +- +- if (/^msgid "((\\.|[^\\])*)"/ ) +- { +- $translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr; +- $msgid = ""; +- $msgstr = ""; +- +- if ($nextfuzzy) { +- $inmsgid = 0; +- } else { +- $msgid = unescape_po_string($1); +- $inmsgid = 1; +- } +- $inmsgstr = 0; +- $nextfuzzy = 0; +- } +- +- if (/^msgstr "((\\.|[^\\])*)"/) +- { +- $msgstr = unescape_po_string($1); +- $inmsgstr = 1; +- $inmsgid = 0; +- } +- +- if (/^"((\\.|[^\\])*)"/) +- { +- $msgid .= unescape_po_string($1) if $inmsgid; +- $msgstr .= unescape_po_string($1) if $inmsgstr; +- } +- } +- $translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr; +- } +-} +- +-sub finalize +-{ +-} +- +-sub unescape_one_sequence +-{ +- my ($sequence) = @_; +- +- return "\\" if $sequence eq "\\\\"; +- return "\"" if $sequence eq "\\\""; +- return "\n" if $sequence eq "\\n"; +- return "\r" if $sequence eq "\\r"; +- return "\t" if $sequence eq "\\t"; +- return "\b" if $sequence eq "\\b"; +- return "\f" if $sequence eq "\\f"; +- return "\a" if $sequence eq "\\a"; +- return chr(11) if $sequence eq "\\v"; # vertical tab, see ascii(7) +- +- return chr(hex($1)) if ($sequence =~ /\\x([0-9a-fA-F]{2})/); +- return chr(oct($1)) if ($sequence =~ /\\([0-7]{3})/); +- +- # FIXME: Is \0 supported as well? Kenneth and Rodney don't want it, see bug #48489 +- +- return $sequence; +-} +- +-sub unescape_po_string +-{ +- my ($string) = @_; +- +- $string =~ s/(\\x[0-9a-fA-F]{2}|\\[0-7]{3}|\\.)/unescape_one_sequence($1)/eg; +- +- return $string; +-} +- +-## NOTE: deal with < - < but not > - > because it seems its ok to have +-## > in the entity. For further info please look at #84738. +-sub entity_decode +-{ +- local ($_) = @_; +- +- s/'/'/g; # ' +- s/"/"/g; # " +- s/&/&/g; +- s/</; +- close INPUT; +- } +- +- open OUTPUT, ">$OUTFILE" or die "can't open $OUTFILE: $!"; +- # Binmode so that selftest works ok if using a native Win32 Perl... +- binmode (OUTPUT) if $^O eq 'MSWin32'; +- +- while ($source =~ s|^(.*?)([ \t]*<\s*$w+\s+($w+\s*=\s*"$q"\s*)+/?>)([ \t]*\n)?||s) +- { +- print OUTPUT $1; +- +- my $node = $2 . "\n"; +- +- my @strings = (); +- $_ = $node; +- while (s/(\s)_($w+\s*=\s*"($q)")/$1$2/s) { +- push @strings, entity_decode($3); +- } +- print OUTPUT; +- +- my %langs; +- for my $string (@strings) +- { +- for my $lang (keys %po_files_by_lang) +- { +- $langs{$lang} = 1 if $translations{$lang, $string}; +- } +- } +- +- for my $lang (sort keys %langs) +- { +- $_ = $node; +- s/(\sname\s*=\s*)"($q)"/$1"$2-$lang"/s; +- s/(\s)_($w+\s*=\s*")($q)"/$1 . $2 . entity_encoded_translation($lang, $3) . '"'/seg; +- print OUTPUT; +- } +- } +- +- print OUTPUT $source; +- +- close OUTPUT; +-} +- +- +-## XML (non-bonobo-activation) merge code +- +- +-# Process tag attributes +-# Only parameter is a HASH containing attributes -> values mapping +-sub getAttributeString +-{ +- my $sub = shift; +- my $do_translate = shift || 0; +- my $language = shift || ""; +- my $result = ""; +- my $translate = shift; +- foreach my $e (reverse(sort(keys %{ $sub }))) { +- my $key = $e; +- my $string = $sub->{$e}; +- my $quote = '"'; +- +- $string =~ s/^[\s]+//; +- $string =~ s/[\s]+$//; +- +- if ($string =~ /^'.*'$/) +- { +- $quote = "'"; +- } +- $string =~ s/^['"]//g; +- $string =~ s/['"]$//g; +- +- if ($do_translate && $key =~ /^_/) { +- $key =~ s|^_||g; +- if ($language) { +- # Handle translation +- my $decode_string = entity_decode($string); +- my $translation = $translations{$language, $decode_string}; +- if ($translation) { +- $translation = entity_encode($translation); +- $string = $translation; +- } +- $$translate = 2; +- } else { +- $$translate = 2 if ($translate && (!$$translate)); # watch not to "overwrite" $translate +- } +- } +- +- $result .= " $key=$quote$string$quote"; +- } +- return $result; +-} +- +-# Returns a translatable string from XML node, it works on contents of every node in XML::Parser tree +-sub getXMLstring +-{ +- my $ref = shift; +- my $spacepreserve = shift || 0; +- my @list = @{ $ref }; +- my $result = ""; +- +- my $count = scalar(@list); +- my $attrs = $list[0]; +- my $index = 1; +- +- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); +- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); +- +- while ($index < $count) { +- my $type = $list[$index]; +- my $content = $list[$index+1]; +- if (! $type ) { +- # We've got CDATA +- if ($content) { +- # lets strip the whitespace here, and *ONLY* here +- $content =~ s/\s+/ /gs if (!$spacepreserve); +- $result .= $content; +- } +- } elsif ( "$type" ne "1" ) { +- # We've got another element +- $result .= "<$type"; +- $result .= getAttributeString(@{$content}[0], 0); # no nested translatable elements +- if ($content) { +- my $subresult = getXMLstring($content, $spacepreserve); +- if ($subresult) { +- $result .= ">".$subresult . ""; +- } else { +- $result .= "/>"; +- } +- } else { +- $result .= "/>"; +- } +- } +- $index += 2; +- } +- return $result; +-} +- +-# Translate list of nodes if necessary +-sub translate_subnodes +-{ +- my $fh = shift; +- my $content = shift; +- my $language = shift || ""; +- my $singlelang = shift || 0; +- my $spacepreserve = shift || 0; +- +- my @nodes = @{ $content }; +- +- my $count = scalar(@nodes); +- my $index = 0; +- while ($index < $count) { +- my $type = $nodes[$index]; +- my $rest = $nodes[$index+1]; +- if ($singlelang) { +- my $oldMO = $MULTIPLE_OUTPUT; +- $MULTIPLE_OUTPUT = 1; +- traverse($fh, $type, $rest, $language, $spacepreserve); +- $MULTIPLE_OUTPUT = $oldMO; +- } else { +- traverse($fh, $type, $rest, $language, $spacepreserve); +- } +- $index += 2; +- } +-} +- +-sub isWellFormedXmlFragment +-{ +- my $ret = eval 'require XML::Parser'; +- if(!$ret) { +- die "You must have XML::Parser installed to run $0\n\n"; +- } +- +- my $fragment = shift; +- return 0 if (!$fragment); +- +- $fragment = "$fragment"; +- my $xp = new XML::Parser(Style => 'Tree'); +- my $tree = 0; +- eval { $tree = $xp->parse($fragment); }; +- return $tree; +-} +- +-sub traverse +-{ +- my $fh = shift; +- my $nodename = shift; +- my $content = shift; +- my $language = shift || ""; +- my $spacepreserve = shift || 0; +- +- if (!$nodename) { +- if ($content =~ /^[\s]*$/) { +- $leading_space .= $content; +- } +- print $fh $content; +- } else { +- # element +- my @all = @{ $content }; +- my $attrs = shift @all; +- my $translate = 0; +- my $outattr = getAttributeString($attrs, 1, $language, \$translate); +- +- if ($nodename =~ /^_/) { +- $translate = 1; +- $nodename =~ s/^_//; +- } +- my $lookup = ''; +- +- $spacepreserve = 0 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?default["']?$/)); +- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); +- +- print $fh "<$nodename", $outattr; +- if ($translate) { +- $lookup = getXMLstring($content, $spacepreserve); +- if (!$spacepreserve) { +- $lookup =~ s/^\s+//s; +- $lookup =~ s/\s+$//s; +- } +- +- if ($lookup || $translate == 2) { +- my $translation = $translations{$language, $lookup} if isWellFormedXmlFragment($translations{$language, $lookup}); +- if ($MULTIPLE_OUTPUT && ($translation || $translate == 2)) { +- $translation = $lookup if (!$translation); +- print $fh " xml:lang=\"", $language, "\"" if $language; +- print $fh ">"; +- if ($translate == 2) { +- translate_subnodes($fh, \@all, $language, 1, $spacepreserve); +- } else { +- print $fh $translation; +- } +- print $fh ""; +- +- return; # this means there will be no same translation with xml:lang="$language"... +- # if we want them both, just remove this "return" +- } else { +- print $fh ">"; +- if ($translate == 2) { +- translate_subnodes($fh, \@all, $language, 1, $spacepreserve); +- } else { +- print $fh $lookup; +- } +- print $fh ""; +- } +- } else { +- print $fh "/>"; +- } +- +- for my $lang (sort keys %po_files_by_lang) { +- if ($MULTIPLE_OUTPUT && $lang ne "$language") { +- next; +- } +- if ($lang) { +- # Handle translation +- # +- my $translate = 0; +- my $localattrs = getAttributeString($attrs, 1, $lang, \$translate); +- my $translation = $translations{$lang, $lookup} if isWellFormedXmlFragment($translations{$lang, $lookup}); +- if ($translate && !$translation) { +- $translation = $lookup; +- } +- +- if ($translation || $translate) { +- print $fh "\n"; +- $leading_space =~ s/.*\n//g; +- print $fh $leading_space; +- print $fh "<", $nodename, " xml:lang=\"", $lang, "\"", $localattrs, ">"; +- if ($translate == 2) { +- translate_subnodes($fh, \@all, $lang, 1, $spacepreserve); +- } else { +- print $fh $translation; +- } +- print $fh ""; +- } +- } +- } +- +- } else { +- my $count = scalar(@all); +- if ($count > 0) { +- print $fh ">"; +- my $index = 0; +- while ($index < $count) { +- my $type = $all[$index]; +- my $rest = $all[$index+1]; +- traverse($fh, $type, $rest, $language, $spacepreserve); +- $index += 2; +- } +- print $fh ""; +- } else { +- print $fh "/>"; +- } +- } +- } +-} +- +-sub intltool_tree_comment +-{ +- my $expat = shift; +- my $data = shift; +- my $clist = $expat->{Curlist}; +- my $pos = $#$clist; +- +- push @$clist, 1 => $data; +-} +- +-sub intltool_tree_cdatastart +-{ +- my $expat = shift; +- my $clist = $expat->{Curlist}; +- my $pos = $#$clist; +- +- push @$clist, 0 => $expat->original_string(); +-} +- +-sub intltool_tree_cdataend +-{ +- my $expat = shift; +- my $clist = $expat->{Curlist}; +- my $pos = $#$clist; +- +- $clist->[$pos] .= $expat->original_string(); +-} +- +-sub intltool_tree_char +-{ +- my $expat = shift; +- my $text = shift; +- my $clist = $expat->{Curlist}; +- my $pos = $#$clist; +- +- # Use original_string so that we retain escaped entities +- # in CDATA sections. +- # +- if ($pos > 0 and $clist->[$pos - 1] eq '0') { +- $clist->[$pos] .= $expat->original_string(); +- } else { +- push @$clist, 0 => $expat->original_string(); +- } +-} +- +-sub intltool_tree_start +-{ +- my $expat = shift; +- my $tag = shift; +- my @origlist = (); +- +- # Use original_string so that we retain escaped entities +- # in attribute values. We must convert the string to an +- # @origlist array to conform to the structure of the Tree +- # Style. +- # +- my @original_array = split /\x/, $expat->original_string(); +- my $source = $expat->original_string(); +- +- # Remove leading tag. +- # +- $source =~ s|^\s*<\s*(\S+)||s; +- +- # Grab attribute key/value pairs and push onto @origlist array. +- # +- while ($source) +- { +- if ($source =~ /^\s*([\w:-]+)\s*[=]\s*["]/) +- { +- $source =~ s|^\s*([\w:-]+)\s*[=]\s*["]([^"]*)["]||s; +- push @origlist, $1; +- push @origlist, '"' . $2 . '"'; +- } +- elsif ($source =~ /^\s*([\w:-]+)\s*[=]\s*[']/) +- { +- $source =~ s|^\s*([\w:-]+)\s*[=]\s*[']([^']*)[']||s; +- push @origlist, $1; +- push @origlist, "'" . $2 . "'"; +- } +- else +- { +- last; +- } +- } +- +- my $ol = [ { @origlist } ]; +- +- push @{ $expat->{Lists} }, $expat->{Curlist}; +- push @{ $expat->{Curlist} }, $tag => $ol; +- $expat->{Curlist} = $ol; +-} +- +-sub readXml +-{ +- my $filename = shift || return; +- if(!-f $filename) { +- die "ERROR Cannot find filename: $filename\n"; +- } +- +- my $ret = eval 'require XML::Parser'; +- if(!$ret) { +- die "You must have XML::Parser installed to run $0\n\n"; +- } +- my $xp = new XML::Parser(Style => 'Tree'); +- $xp->setHandlers(Char => \&intltool_tree_char); +- $xp->setHandlers(Start => \&intltool_tree_start); +- $xp->setHandlers(CdataStart => \&intltool_tree_cdatastart); +- $xp->setHandlers(CdataEnd => \&intltool_tree_cdataend); +- my $tree = $xp->parsefile($filename); +- +-# Hello thereHowdydo +-# would be: +-# [foo, [{}, head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]], bar, [{}, +-# 0, "Howdy", ref, [{}]], 0, "do" ] ] +- +- return $tree; +-} +- +-sub print_header +-{ +- my $infile = shift; +- my $fh = shift; +- my $source; +- +- if(!-f $infile) { +- die "ERROR Cannot find filename: $infile\n"; +- } +- +- print $fh qq{\n}; +- { +- local $/; +- open DOCINPUT, "<${FILE}" or die; +- $source = ; +- close DOCINPUT; +- } +- if ($source =~ /()/s) +- { +- print $fh "$1\n"; +- } +- elsif ($source =~ /(]*>)/s) +- { +- print $fh "$1\n"; +- } +-} +- +-sub parseTree +-{ +- my $fh = shift; +- my $ref = shift; +- my $language = shift || ""; +- +- my $name = shift @{ $ref }; +- my $cont = shift @{ $ref }; +- +- while (!$name || "$name" eq "1") { +- $name = shift @{ $ref }; +- $cont = shift @{ $ref }; +- } +- +- my $spacepreserve = 0; +- my $attrs = @{$cont}[0]; +- $spacepreserve = 1 if ((exists $attrs->{"xml:space"}) && ($attrs->{"xml:space"} =~ /^["']?preserve["']?$/)); +- +- traverse($fh, $name, $cont, $language, $spacepreserve); +-} +- +-sub xml_merge_output +-{ +- my $source; +- +- if ($MULTIPLE_OUTPUT) { +- for my $lang (sort keys %po_files_by_lang) { +- if ( ! -e $lang ) { +- mkdir $lang or die "Cannot create subdirectory $lang: $!\n"; +- } +- open OUTPUT, ">$lang/$OUTFILE" or die "Cannot open $lang/$OUTFILE: $!\n"; +- binmode (OUTPUT) if $^O eq 'MSWin32'; +- my $tree = readXml($FILE); +- print_header($FILE, \*OUTPUT); +- parseTree(\*OUTPUT, $tree, $lang); +- close OUTPUT; +- print "CREATED $lang/$OUTFILE\n" unless $QUIET_ARG; +- } +- } +- open OUTPUT, ">$OUTFILE" or die "Cannot open $OUTFILE: $!\n"; +- binmode (OUTPUT) if $^O eq 'MSWin32'; +- my $tree = readXml($FILE); +- print_header($FILE, \*OUTPUT); +- parseTree(\*OUTPUT, $tree); +- close OUTPUT; +- print "CREATED $OUTFILE\n" unless $QUIET_ARG; +-} +- +-sub keys_merge_translations +-{ +- open INPUT, "<${FILE}" or die; +- open OUTPUT, ">${OUTFILE}" or die; +- binmode (OUTPUT) if $^O eq 'MSWin32'; +- +- while () +- { +- if (s/^(\s*)_(\w+=(.*))/$1$2/) +- { +- my $string = $3; +- +- print OUTPUT; +- +- my $non_translated_line = $_; +- +- for my $lang (sort keys %po_files_by_lang) +- { +- my $translation = $translations{$lang, $string}; +- next if !$translation; +- +- $_ = $non_translated_line; +- s/(\w+)=.*/[$lang]$1=$translation/; +- print OUTPUT; +- } +- } +- else +- { +- print OUTPUT; +- } +- } +- +- close OUTPUT; +- close INPUT; +-} +- +-sub desktop_merge_translations +-{ +- open INPUT, "<${FILE}" or die; +- open OUTPUT, ">${OUTFILE}" or die; +- binmode (OUTPUT) if $^O eq 'MSWin32'; +- +- while () +- { +- if (s/^(\s*)_(\w+=(.*))/$1$2/) +- { +- my $string = $3; +- +- print OUTPUT; +- +- my $non_translated_line = $_; +- +- for my $lang (sort keys %po_files_by_lang) +- { +- my $translation = $translations{$lang, $string}; +- next if !$translation; +- +- $_ = $non_translated_line; +- s/(\w+)=.*/${1}[$lang]=$translation/; +- print OUTPUT; +- } +- } +- else +- { +- print OUTPUT; +- } +- } +- +- close OUTPUT; +- close INPUT; +-} +- +-sub schemas_merge_translations +-{ +- my $source; +- +- { +- local $/; # slurp mode +- open INPUT, "<$FILE" or die "can't open $FILE: $!"; +- $source = ; +- close INPUT; +- } +- +- open OUTPUT, ">$OUTFILE" or die; +- binmode (OUTPUT) if $^O eq 'MSWin32'; +- +- # FIXME: support attribute translations +- +- # Empty nodes never need translation, so unmark all of them. +- # For example, <_foo/> is just replaced by . +- $source =~ s|<\s*_($w+)\s*/>|<$1/>|g; +- +- while ($source =~ s/ +- (.*?) +- (\s+)((\s*) +- (\s*(?:\s*)?(.*?)\s*<\/default>)?(\s*) +- (\s*(?:\s*)?(.*?)\s*<\/short>)?(\s*) +- (\s*(?:\s*)?(.*?)\s*<\/long>)?(\s*) +- <\/locale>) +- //sx) +- { +- print OUTPUT $1; +- +- my $locale_start_spaces = $2 ? $2 : ''; +- my $default_spaces = $4 ? $4 : ''; +- my $short_spaces = $7 ? $7 : ''; +- my $long_spaces = $10 ? $10 : ''; +- my $locale_end_spaces = $13 ? $13 : ''; +- my $c_default_block = $3 ? $3 : ''; +- my $default_string = $6 ? $6 : ''; +- my $short_string = $9 ? $9 : ''; +- my $long_string = $12 ? $12 : ''; +- +- print OUTPUT "$locale_start_spaces$c_default_block"; +- +- $default_string =~ s/\s+/ /g; +- $default_string = entity_decode($default_string); +- $short_string =~ s/\s+/ /g; +- $short_string = entity_decode($short_string); +- $long_string =~ s/\s+/ /g; +- $long_string = entity_decode($long_string); +- +- for my $lang (sort keys %po_files_by_lang) +- { +- my $default_translation = $translations{$lang, $default_string}; +- my $short_translation = $translations{$lang, $short_string}; +- my $long_translation = $translations{$lang, $long_string}; +- +- next if (!$default_translation && !$short_translation && +- !$long_translation); +- +- print OUTPUT "\n$locale_start_spaces"; +- +- print OUTPUT "$default_spaces"; +- +- if ($default_translation) +- { +- $default_translation = entity_encode($default_translation); +- print OUTPUT "$default_translation"; +- } +- +- print OUTPUT "$short_spaces"; +- +- if ($short_translation) +- { +- $short_translation = entity_encode($short_translation); +- print OUTPUT "$short_translation"; +- } +- +- print OUTPUT "$long_spaces"; +- +- if ($long_translation) +- { +- $long_translation = entity_encode($long_translation); +- print OUTPUT "$long_translation"; +- } +- +- print OUTPUT "$locale_end_spaces"; +- } +- } +- +- print OUTPUT $source; +- +- close OUTPUT; +-} +- +-sub rfc822deb_merge_translations +-{ +- my %encodings = (); +- for my $lang (keys %po_files_by_lang) { +- $encodings{$lang} = ($UTF8_ARG ? 'UTF-8' : get_po_encoding($po_files_by_lang{$lang})); +- } +- +- my $source; +- +- $Text::Wrap::huge = 'overflow'; +- $Text::Wrap::break = qr/\n|\s(?=\S)/; +- +- { +- local $/; # slurp mode +- open INPUT, "<$FILE" or die "can't open $FILE: $!"; +- $source = ; +- close INPUT; +- } +- +- open OUTPUT, ">${OUTFILE}" or die; +- binmode (OUTPUT) if $^O eq 'MSWin32'; +- +- while ($source =~ /(^|\n+)(_*)([^:\s]+)(:[ \t]*)(.*?)(?=\n[\S\n]|$)/sg) +- { +- my $sep = $1; +- my $non_translated_line = $3.$4; +- my $string = $5; +- my $underscore = length($2); +- next if $underscore eq 0 && $non_translated_line =~ /^#/; +- # Remove [] dummy strings +- my $stripped = $string; +- $stripped =~ s/\[\s[^\[\]]*\],/,/g if $underscore eq 2; +- $stripped =~ s/\[\s[^\[\]]*\]$//; +- $non_translated_line .= $stripped; +- +- print OUTPUT $sep.$non_translated_line; +- +- if ($underscore) +- { +- my @str_list = rfc822deb_split($underscore, $string); +- +- for my $lang (sort keys %po_files_by_lang) +- { +- my $is_translated = 1; +- my $str_translated = ''; +- my $first = 1; +- +- for my $str (@str_list) +- { +- my $translation = $translations{$lang, $str}; +- +- if (!$translation) +- { +- $is_translated = 0; +- last; +- } +- +- # $translation may also contain [] dummy +- # strings, mostly to indicate an empty string +- $translation =~ s/\[\s[^\[\]]*\]$//; +- +- if ($first) +- { +- if ($underscore eq 2) +- { +- $str_translated .= $translation; +- } +- else +- { +- $str_translated .= +- Text::Tabs::expand($translation) . +- "\n"; +- } +- } +- else +- { +- if ($underscore eq 2) +- { +- $str_translated .= ', ' . $translation; +- } +- else +- { +- $str_translated .= Text::Tabs::expand( +- Text::Wrap::wrap(' ', ' ', $translation)) . +- "\n .\n"; +- } +- } +- $first = 0; +- +- # To fix some problems with Text::Wrap::wrap +- $str_translated =~ s/(\n )+\n/\n .\n/g; +- } +- next unless $is_translated; +- +- $str_translated =~ s/\n \.\n$//; +- $str_translated =~ s/\s+$//; +- +- $_ = $non_translated_line; +- s/^(\w+):\s*.*/$sep${1}-$lang.$encodings{$lang}: $str_translated/s; +- print OUTPUT; +- } +- } +- } +- print OUTPUT "\n"; +- +- close OUTPUT; +- close INPUT; +-} +- +-sub rfc822deb_split +-{ +- # Debian defines a special way to deal with rfc822-style files: +- # when a value contain newlines, it consists of +- # 1. a short form (first line) +- # 2. a long description, all lines begin with a space, +- # and paragraphs are separated by a single dot on a line +- # This routine returns an array of all paragraphs, and reformat +- # them. +- # When first argument is 2, the string is a comma separated list of +- # values. +- my $type = shift; +- my $text = shift; +- $text =~ s/^[ \t]//mg; +- return (split(/, */, $text, 0)) if $type ne 1; +- return ($text) if $text !~ /\n/; +- +- $text =~ s/([^\n]*)\n//; +- my @list = ($1); +- my $str = ''; +- +- for my $line (split (/\n/, $text)) +- { +- chomp $line; +- if ($line =~ /^\.\s*$/) +- { +- # New paragraph +- $str =~ s/\s*$//; +- push(@list, $str); +- $str = ''; +- } +- elsif ($line =~ /^\s/) +- { +- # Line which must not be reformatted +- $str .= "\n" if length ($str) && $str !~ /\n$/; +- $line =~ s/\s+$//; +- $str .= $line."\n"; +- } +- else +- { +- # Continuation line, remove newline +- $str .= " " if length ($str) && $str !~ /\n$/; +- $str .= $line; +- } +- } +- +- $str =~ s/\s*$//; +- push(@list, $str) if length ($str); +- +- return @list; +-} +- +diff --git a/intltool-merge.in b/intltool-merge.in +new file mode 120000 +index d0535ab..2238bbd +--- /dev/null ++++ b/intltool-merge.in +@@ -0,0 +1 @@ ++/usr/share/intltool/intltool-merge.in +\ No newline at end of file +diff --git a/intltool-update.in b/intltool-update.in +deleted file mode 100755 +index 661d8fe..0b1800f +--- a/intltool-update.in ++++ /dev/null +@@ -1,1089 +0,0 @@ +-#!@INTLTOOL_PERL@ -w +-# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- +- +-# +-# The Intltool Message Updater +-# +-# Copyright (C) 2000-2003 Free Software Foundation. +-# +-# Intltool is free software; you can redistribute it and/or +-# modify it under the terms of the GNU General Public License +-# version 2 published by the Free Software Foundation. +-# +-# Intltool 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., 675 Mass Ave, Cambridge, MA 02139, USA. +-# +-# As a special exception to the GNU General Public License, if you +-# distribute this file as part of a program that contains a +-# configuration script generated by Autoconf, you may include it under +-# the same distribution terms that you use for the rest of that program. +-# +-# Authors: Kenneth Christiansen +-# Maciej Stachowiak +-# Darin Adler +- +-## Release information +-my $PROGRAM = "intltool-update"; +-my $VERSION = "0.35.0"; +-my $PACKAGE = "intltool"; +- +-## Loaded modules +-use strict; +-use Getopt::Long; +-use Cwd; +-use File::Copy; +-use File::Find; +- +-## Scalars used by the option stuff +-my $HELP_ARG = 0; +-my $VERSION_ARG = 0; +-my $DIST_ARG = 0; +-my $POT_ARG = 0; +-my $HEADERS_ARG = 0; +-my $MAINTAIN_ARG = 0; +-my $REPORT_ARG = 0; +-my $VERBOSE = 0; +-my $GETTEXT_PACKAGE = ""; +-my $OUTPUT_FILE = ""; +- +-my @languages; +-my %varhash = (); +-my %po_files_by_lang = (); +- +-# Regular expressions to categorize file types. +-# FIXME: Please check if the following is correct +- +-my $xml_support = +-"xml(?:\\.in)*|". # http://www.w3.org/XML/ (Note: .in is not required) +-"ui|". # Bonobo specific - User Interface desc. files +-"lang|". # ? +-"glade2?(?:\\.in)*|". # Glade specific - User Interface desc. files (Note: .in is not required) +-"scm(?:\\.in)*|". # ? (Note: .in is not required) +-"oaf(?:\\.in)+|". # DEPRECATED: Replaces by Bonobo .server files +-"etspec|". # ? +-"server(?:\\.in)+|". # Bonobo specific +-"sheet(?:\\.in)+|". # ? +-"schemas(?:\\.in)+|". # GConf specific +-"pong(?:\\.in)+|". # DEPRECATED: PONG is not used [by GNOME] any longer. +-"kbd(?:\\.in)+"; # GOK specific. +- +-my $ini_support = +-"icon(?:\\.in)+|". # http://www.freedesktop.org/Standards/icon-theme-spec +-"desktop(?:\\.in)+|". # http://www.freedesktop.org/Standards/menu-spec +-"caves(?:\\.in)+|". # GNOME Games specific +-"directory(?:\\.in)+|". # http://www.freedesktop.org/Standards/menu-spec +-"soundlist(?:\\.in)+|". # GNOME specific +-"keys(?:\\.in)+|". # GNOME Mime database specific +-"theme(?:\\.in)+|". # http://www.freedesktop.org/Standards/icon-theme-spec +-"service(?:\\.in)+"; # DBus specific +- +-my $buildin_gettext_support = +-"c|y|cs|cc|cpp|c\\+\\+|h|hh|gob|py"; +- +-## Always flush buffer when printing +-$| = 1; +- +-## Sometimes the source tree will be rooted somewhere else. +-my $SRCDIR = "."; +-my $POTFILES_in; +- +-$SRCDIR = $ENV{"srcdir"} if $ENV{"srcdir"}; +-$POTFILES_in = "<$SRCDIR/POTFILES.in"; +- +-my $devnull = ($^O eq 'MSWin32' ? 'NUL:' : '/dev/null'); +- +-## Handle options +-GetOptions +-( +- "help" => \$HELP_ARG, +- "version" => \$VERSION_ARG, +- "dist|d" => \$DIST_ARG, +- "pot|p" => \$POT_ARG, +- "headers|s" => \$HEADERS_ARG, +- "maintain|m" => \$MAINTAIN_ARG, +- "report|r" => \$REPORT_ARG, +- "verbose|x" => \$VERBOSE, +- "gettext-package|g=s" => \$GETTEXT_PACKAGE, +- "output-file|o=s" => \$OUTPUT_FILE, +- ) or &Console_WriteError_InvalidOption; +- +-&Console_Write_IntltoolHelp if $HELP_ARG; +-&Console_Write_IntltoolVersion if $VERSION_ARG; +- +-my $arg_count = ($DIST_ARG > 0) +- + ($POT_ARG > 0) +- + ($HEADERS_ARG > 0) +- + ($MAINTAIN_ARG > 0) +- + ($REPORT_ARG > 0); +- +-&Console_Write_IntltoolHelp if $arg_count > 1; +- +-# --version and --help don't require a module name +-my $MODULE = $GETTEXT_PACKAGE || &FindPackageName || "unknown"; +- +-if ($POT_ARG) +-{ +- &GenerateHeaders; +- &GeneratePOTemplate; +-} +-elsif ($HEADERS_ARG) +-{ +- &GenerateHeaders; +-} +-elsif ($MAINTAIN_ARG) +-{ +- &FindLeftoutFiles; +-} +-elsif ($REPORT_ARG) +-{ +- &GenerateHeaders; +- &GeneratePOTemplate; +- &Console_Write_CoverageReport; +-} +-elsif ((defined $ARGV[0]) && $ARGV[0] =~ /^[a-z]/) +-{ +- my $lang = $ARGV[0]; +- +- ## Report error if the language file supplied +- ## to the command line is non-existent +- &Console_WriteError_NotExisting("$SRCDIR/$lang.po") +- if ! -s "$SRCDIR/$lang.po"; +- +- if (!$DIST_ARG) +- { +- print "Working, please wait..." if $VERBOSE; +- &GenerateHeaders; +- &GeneratePOTemplate; +- } +- &POFile_Update ($lang, $OUTPUT_FILE); +- &Console_Write_TranslationStatus ($lang, $OUTPUT_FILE); +-} +-else +-{ +- &Console_Write_IntltoolHelp; +-} +- +-exit; +- +-######### +- +-sub Console_Write_IntltoolVersion +-{ +- print <<_EOF_; +-${PROGRAM} (${PACKAGE}) $VERSION +-Written by Kenneth Christiansen, Maciej Stachowiak, and Darin Adler. +- +-Copyright (C) 2000-2003 Free Software Foundation, Inc. +-This is free software; see the source for copying conditions. There is NO +-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +-_EOF_ +- exit; +-} +- +-sub Console_Write_IntltoolHelp +-{ +- print <<_EOF_; +-Usage: ${PROGRAM} [OPTION]... LANGCODE +-Updates PO template files and merge them with the translations. +- +-Mode of operation (only one is allowed): +- -p, --pot generate the PO template only +- -s, --headers generate the header files in POTFILES.in +- -m, --maintain search for left out files from POTFILES.in +- -r, --report display a status report for the module +- -d, --dist merge LANGCODE.po with existing PO template +- +-Extra options: +- -g, --gettext-package=NAME override PO template name, useful with --pot +- -o, --output-file=FILE write merged translation to FILE +- -x, --verbose display lots of feedback +- --help display this help and exit +- --version output version information and exit +- +-Examples of use: +-${PROGRAM} --pot just create a new PO template +-${PROGRAM} xy create new PO template and merge xy.po with it +- +-Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE") +-or send email to . +-_EOF_ +- exit; +-} +- +-sub echo_n +-{ +- my $str = shift; +- my $ret = `echo "$str"`; +- +- $ret =~ s/\n$//; # do we need the "s" flag? +- +- return $ret; +-} +- +-sub POFile_DetermineType ($) +-{ +- my $type = $_; +- my $gettext_type; +- +- my $xml_regex = "(?:" . $xml_support . ")"; +- my $ini_regex = "(?:" . $ini_support . ")"; +- my $buildin_regex = "(?:" . $buildin_gettext_support . ")"; +- +- if ($type =~ /\[type: gettext\/([^\]].*)]/) +- { +- $gettext_type=$1; +- } +- elsif ($type =~ /schemas(\.in)+$/) +- { +- $gettext_type="schemas"; +- } +- elsif ($type =~ /glade2?(\.in)*$/) +- { +- $gettext_type="glade"; +- } +- elsif ($type =~ /scm(\.in)*$/) +- { +- $gettext_type="scheme"; +- } +- elsif ($type =~ /keys(\.in)+$/) +- { +- $gettext_type="keys"; +- } +- +- # bucket types +- +- elsif ($type =~ /$xml_regex$/) +- { +- $gettext_type="xml"; +- } +- elsif ($type =~ /$ini_regex$/) +- { +- $gettext_type="ini"; +- } +- elsif ($type =~ /$buildin_regex$/) +- { +- $gettext_type="buildin"; +- } +- else +- { +- $gettext_type="unknown"; +- } +- +- return "gettext\/$gettext_type"; +-} +- +-sub TextFile_DetermineEncoding ($) +-{ +- my $gettext_code="ASCII"; # All files are ASCII by default +- my $filetype=`file $_ | cut -d ' ' -f 2`; +- +- if ($? eq "0") +- { +- if ($filetype =~ /^(ISO|UTF)/) +- { +- chomp ($gettext_code = $filetype); +- } +- elsif ($filetype =~ /^XML/) +- { +- $gettext_code="UTF-8"; # We asume that .glade and other .xml files are UTF-8 +- } +- } +- +- return $gettext_code; +-} +- +-sub isNotValidMissing +-{ +- my ($file) = @_; +- +- return if $file =~ /^\{arch\}\/.*$/; +- return if $file =~ /^$varhash{"PACKAGE"}-$varhash{"VERSION"}\/.*$/; +-} +- +-sub FindLeftoutFiles +-{ +- my (@buf_i18n_plain, +- @buf_i18n_xml, +- @buf_i18n_xml_unmarked, +- @buf_i18n_ini, +- @buf_potfiles, +- @buf_potfiles_ignore, +- @buf_allfiles, +- @buf_allfiles_sorted, +- @buf_potfiles_sorted +- ); +- +- ## Search and find all translatable files +- find sub { +- push @buf_i18n_plain, "$File::Find::name" if /\.($buildin_gettext_support)$/; +- push @buf_i18n_xml, "$File::Find::name" if /\.($xml_support)$/; +- push @buf_i18n_ini, "$File::Find::name" if /\.($ini_support)$/; +- push @buf_i18n_xml_unmarked, "$File::Find::name" if /\.(schemas(\.in)+)$/; +- }, ".."; +- +- +- open POTFILES, $POTFILES_in or die "$PROGRAM: there's no POTFILES.in!\n"; +- @buf_potfiles = grep !/^(#|\s*$)/, ; +- close POTFILES; +- +- foreach (@buf_potfiles) { +- s/^\[.*]\s*//; +- } +- +- print "Searching for missing translatable files...\n" if $VERBOSE; +- +- ## Check if we should ignore some found files, when +- ## comparing with POTFILES.in +- foreach my $ignore ("POTFILES.skip", "POTFILES.ignore") +- { +- (-s $ignore) or next; +- +- if ("$ignore" eq "POTFILES.ignore") +- { +- print "The usage of POTFILES.ignore is deprecated. Please consider moving the\n". +- "content of this file to POTFILES.skip.\n"; +- } +- +- print "Found $ignore: Ignoring files...\n" if $VERBOSE; +- open FILE, "<$ignore" or die "ERROR: Failed to open $ignore!\n"; +- +- while () +- { +- push @buf_potfiles_ignore, $_ unless /^(#|\s*$)/; +- } +- close FILE; +- +- @buf_potfiles = (@buf_potfiles_ignore, @buf_potfiles); +- } +- +- foreach my $file (@buf_i18n_plain) +- { +- my $in_comment = 0; +- my $in_macro = 0; +- +- open FILE, "<$file"; +- while () +- { +- # Handle continued multi-line comment. +- if ($in_comment) +- { +- next unless s-.*\*/--; +- $in_comment = 0; +- } +- +- # Handle continued macro. +- if ($in_macro) +- { +- $in_macro = 0 unless /\\$/; +- next; +- } +- +- # Handle start of macro (or any preprocessor directive). +- if (/^\s*\#/) +- { +- $in_macro = 1 if /^([^\\]|\\.)*\\$/; +- next; +- } +- +- # Handle comments and quoted text. +- while (m-(/\*|//|\'|\")-) # \' and \" keep emacs perl mode happy +- { +- my $match = $1; +- if ($match eq "/*") +- { +- if (!s-/\*.*?\*/--) +- { +- s-/\*.*--; +- $in_comment = 1; +- } +- } +- elsif ($match eq "//") +- { +- s-//.*--; +- } +- else # ' or " +- { +- if (!s-$match([^\\]|\\.)*?$match-QUOTEDTEXT-) +- { +- warn "mismatched quotes at line $. in $file\n"; +- s-$match.*--; +- } +- } +- } +- +- if (/\.GetString ?\(QUOTEDTEXT/) +- { +- if (defined isNotValidMissing (unpack("x3 A*", $file))) { +- ## Remove the first 3 chars and add newline +- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; +- } +- last; +- } +- +- if (/_\(QUOTEDTEXT/) +- { +- if (defined isNotValidMissing (unpack("x3 A*", $file))) { +- ## Remove the first 3 chars and add newline +- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; +- } +- last; +- } +- } +- close FILE; +- } +- +- foreach my $file (@buf_i18n_xml) +- { +- open FILE, "<$file"; +- +- while () +- { +- # FIXME: share the pattern matching code with intltool-extract +- if (/\s_[-A-Za-z0-9._:]+\s*=\s*\"([^"]+)\"/ || /<_[^>]+>/ || /translatable=\"yes\"/) +- { +- if (defined isNotValidMissing (unpack("x3 A*", $file))) { +- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; +- } +- last; +- } +- } +- close FILE; +- } +- +- foreach my $file (@buf_i18n_ini) +- { +- open FILE, "<$file"; +- while () +- { +- if (/_(.*)=/) +- { +- if (defined isNotValidMissing (unpack("x3 A*", $file))) { +- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; +- } +- last; +- } +- } +- close FILE; +- } +- +- foreach my $file (@buf_i18n_xml_unmarked) +- { +- if (defined isNotValidMissing (unpack("x3 A*", $file))) { +- push @buf_allfiles, unpack("x3 A*", $file) . "\n"; +- } +- } +- +- +- @buf_allfiles_sorted = sort (@buf_allfiles); +- @buf_potfiles_sorted = sort (@buf_potfiles); +- +- my %in2; +- foreach (@buf_potfiles_sorted) +- { +- $in2{$_} = 1; +- } +- +- my @result; +- +- foreach (@buf_allfiles_sorted) +- { +- if (!exists($in2{$_})) +- { +- push @result, $_ +- } +- } +- +- my @buf_potfiles_notexist; +- +- foreach (@buf_potfiles_sorted) +- { +- chomp (my $dummy = $_); +- if ("$dummy" ne "" and ! -f "../$dummy") +- { +- push @buf_potfiles_notexist, $_; +- } +- } +- +- ## Save file with information about the files missing +- ## if any, and give information about this procedure. +- if (@result + @buf_potfiles_notexist > 0) +- { +- if (@result) +- { +- print "\n" if $VERBOSE; +- unlink "missing"; +- open OUT, ">missing"; +- print OUT @result; +- close OUT; +- warn "\e[1mThe following files contain translations and are currently not in use. Please\e[0m\n". +- "\e[1mconsider adding these to the POTFILES.in file, located in the po/ directory.\e[0m\n\n"; +- print STDERR @result, "\n"; +- warn "If some of these files are left out on purpose then please add them to\n". +- "POTFILES.skip instead of POTFILES.in. A file \e[1m'missing'\e[0m containing this list\n". +- "of left out files has been written in the current directory.\n"; +- } +- if (@buf_potfiles_notexist) +- { +- unlink "notexist"; +- open OUT, ">notexist"; +- print OUT @buf_potfiles_notexist; +- close OUT; +- warn "\n" if ($VERBOSE or @result); +- warn "\e[1mThe following files do not exist anymore:\e[0m\n\n"; +- warn @buf_potfiles_notexist, "\n"; +- warn "Please remove them from POTFILES.in or POTFILES.skip. A file \e[1m'notexist'\e[0m\n". +- "containing this list of absent files has been written in the current directory.\n"; +- } +- } +- +- ## If there is nothing to complain about, notify the user +- else { +- print "\nAll files containing translations are present in POTFILES.in.\n" if $VERBOSE; +- } +-} +- +-sub Console_WriteError_InvalidOption +-{ +- ## Handle invalid arguments +- print STDERR "Try `${PROGRAM} --help' for more information.\n"; +- exit 1; +-} +- +-sub GenerateHeaders +-{ +- my $EXTRACT = "@INTLTOOL_EXTRACT@"; +- chomp $EXTRACT; +- +- $EXTRACT = $ENV{"INTLTOOL_EXTRACT"} if $ENV{"INTLTOOL_EXTRACT"}; +- +- ## Generate the .h header files, so we can allow glade and +- ## xml translation support +- if (! -x "$EXTRACT") +- { +- print STDERR "\n *** The intltool-extract script wasn't found!" +- ."\n *** Without it, intltool-update can not generate files.\n"; +- exit; +- } +- else +- { +- open (FILE, $POTFILES_in) or die "$PROGRAM: POTFILES.in not found.\n"; +- +- while () +- { +- chomp; +- next if /^\[\s*encoding/; +- +- ## Find xml files in POTFILES.in and generate the +- ## files with help from the extract script +- +- my $gettext_type= &POFile_DetermineType ($1); +- +- if (/\.($xml_support|$ini_support)$/ || /^\[/) +- { +- s/^\[[^\[].*]\s*//; +- +- my $filename = "../$_"; +- +- if ($VERBOSE) +- { +- system ($EXTRACT, "--update", "--srcdir=$SRCDIR", +- "--type=$gettext_type", $filename); +- } +- else +- { +- system ($EXTRACT, "--update", "--type=$gettext_type", +- "--srcdir=$SRCDIR", "--quiet", $filename); +- } +- } +- } +- close FILE; +- } +-} +- +-# +-# Generate .pot file from POTFILES.in +-# +-sub GeneratePOTemplate +-{ +- my $XGETTEXT = $ENV{"XGETTEXT"} || "@INTLTOOL_XGETTEXT@"; +- my $XGETTEXT_ARGS = $ENV{"XGETTEXT_ARGS"} || ''; +- chomp $XGETTEXT; +- +- if (! -x $XGETTEXT) +- { +- print STDERR " *** xgettext is not found on this system!\n". +- " *** Without it, intltool-update can not extract strings.\n"; +- exit; +- } +- +- print "Building $MODULE.pot...\n" if $VERBOSE; +- +- open INFILE, $POTFILES_in; +- unlink "POTFILES.in.temp"; +- open OUTFILE, ">POTFILES.in.temp" or die("Cannot open POTFILES.in.temp for writing"); +- +- my $gettext_support_nonascii = 0; +- +- # checks for GNU gettext >= 0.12 +- my $dummy = `$XGETTEXT --version --from-code=UTF-8 >$devnull 2>$devnull`; +- if ($? == 0) +- { +- $gettext_support_nonascii = 1; +- } +- else +- { +- # urge everybody to upgrade gettext +- print STDERR "WARNING: This version of gettext does not support extracting non-ASCII\n". +- " strings. That means you should install a version of gettext\n". +- " that supports non-ASCII strings (such as GNU gettext >= 0.12),\n". +- " or have to let non-ASCII strings untranslated. (If there is any)\n"; +- } +- +- my $encoding = "ASCII"; +- my $forced_gettext_code; +- my @temp_headers; +- my $encoding_problem_is_reported = 0; +- +- while () +- { +- next if (/^#/ or /^\s*$/); +- +- chomp; +- +- my $gettext_code; +- +- if (/^\[\s*encoding:\s*(.*)\s*\]/) +- { +- $forced_gettext_code=$1; +- } +- elsif (/\.($xml_support|$ini_support)$/ || /^\[/) +- { +- s/^\[.*]\s*//; +- print OUTFILE "../$_.h\n"; +- push @temp_headers, "../$_.h"; +- $gettext_code = &TextFile_DetermineEncoding ("../$_.h") if ($gettext_support_nonascii and not defined $forced_gettext_code); +- } +- else +- { +- if ($SRCDIR eq ".") { +- print OUTFILE "../$_\n"; +- } else { +- print OUTFILE "$SRCDIR/../$_\n"; +- } +- $gettext_code = &TextFile_DetermineEncoding ("../$_") if ($gettext_support_nonascii and not defined $forced_gettext_code); +- } +- +- next if (! $gettext_support_nonascii); +- +- if (defined $forced_gettext_code) +- { +- $encoding=$forced_gettext_code; +- } +- elsif (defined $gettext_code and "$encoding" ne "$gettext_code") +- { +- if ($encoding eq "ASCII") +- { +- $encoding=$gettext_code; +- } +- elsif ($gettext_code ne "ASCII") +- { +- # Only report once because the message is quite long +- if (! $encoding_problem_is_reported) +- { +- print STDERR "WARNING: You should use the same file encoding for all your project files,\n". +- " but $PROGRAM thinks that most of the source files are in\n". +- " $encoding encoding, while \"$_\" is (likely) in\n". +- " $gettext_code encoding. If you are sure that all translatable strings\n". +- " are in same encoding (say UTF-8), please \e[1m*prepend*\e[0m the following\n". +- " line to POTFILES.in:\n\n". +- " [encoding: UTF-8]\n\n". +- " and make sure that configure.in/ac checks for $PACKAGE >= 0.27 .\n". +- "(such warning message will only be reported once.)\n"; +- $encoding_problem_is_reported = 1; +- } +- } +- } +- } +- +- close OUTFILE; +- close INFILE; +- +- unlink "$MODULE.pot"; +- my @xgettext_argument=("$XGETTEXT", +- "--add-comments", +- "--directory\=\.", +- "--output\=$MODULE\.pot", +- "--files-from\=\.\/POTFILES\.in\.temp"); +- my $XGETTEXT_KEYWORDS = &FindPOTKeywords; +- push @xgettext_argument, $XGETTEXT_KEYWORDS; +- my $MSGID_BUGS_ADDRESS = &FindMakevarsBugAddress; +- push @xgettext_argument, "--msgid-bugs-address\=$MSGID_BUGS_ADDRESS" if $MSGID_BUGS_ADDRESS; +- push @xgettext_argument, "--from-code\=$encoding" if ($gettext_support_nonascii); +- push @xgettext_argument, $XGETTEXT_ARGS if $XGETTEXT_ARGS; +- my $xgettext_command = join ' ', @xgettext_argument; +- +- # intercept xgettext error message +- print "Running $xgettext_command\n" if $VERBOSE; +- my $xgettext_error_msg = `$xgettext_command 2>\&1`; +- my $command_failed = $?; +- +- unlink "POTFILES.in.temp"; +- +- print "Removing generated header (.h) files..." if $VERBOSE; +- unlink foreach (@temp_headers); +- print "done.\n" if $VERBOSE; +- +- if (! $command_failed) +- { +- if (! -e "$MODULE.pot") +- { +- print "None of the files in POTFILES.in contain strings marked for translation.\n" if $VERBOSE; +- } +- else +- { +- print "Wrote $MODULE.pot\n" if $VERBOSE; +- } +- } +- else +- { +- if ($xgettext_error_msg =~ /--from-code/) +- { +- # replace non-ASCII error message with a more useful one. +- print STDERR "ERROR: xgettext failed to generate PO template file because there is non-ASCII\n". +- " string marked for translation. Please make sure that all strings marked\n". +- " for translation are in uniform encoding (say UTF-8), then \e[1m*prepend*\e[0m the\n". +- " following line to POTFILES.in and rerun $PROGRAM:\n\n". +- " [encoding: UTF-8]\n\n"; +- } +- else +- { +- print STDERR "$xgettext_error_msg"; +- if (-e "$MODULE.pot") +- { +- # is this possible? +- print STDERR "ERROR: xgettext failed but still managed to generate PO template file.\n". +- " Please consult error message above if there is any.\n"; +- } +- else +- { +- print STDERR "ERROR: xgettext failed to generate PO template file. Please consult\n". +- " error message above if there is any.\n"; +- } +- } +- exit (1); +- } +-} +- +-sub POFile_Update +-{ +- -f "$MODULE.pot" or die "$PROGRAM: $MODULE.pot does not exist.\n"; +- +- my $MSGMERGE = $ENV{"MSGMERGE"} || "@INTLTOOL_MSGMERGE@"; +- my ($lang, $outfile) = @_; +- +- print "Merging $SRCDIR/$lang.po with $MODULE.pot..." if $VERBOSE; +- +- my $infile = "$SRCDIR/$lang.po"; +- $outfile = "$SRCDIR/$lang.po" if ($outfile eq ""); +- +- # I think msgmerge won't overwrite old file if merge is not successful +- system ("$MSGMERGE", "-o", $outfile, $infile, "$MODULE.pot"); +-} +- +-sub Console_WriteError_NotExisting +-{ +- my ($file) = @_; +- +- ## Report error if supplied language file is non-existing +- print STDERR "$PROGRAM: $file does not exist!\n"; +- print STDERR "Try '$PROGRAM --help' for more information.\n"; +- exit; +-} +- +-sub GatherPOFiles +-{ +- my @po_files = glob ("./*.po"); +- +- @languages = map (&POFile_GetLanguage, @po_files); +- +- foreach my $lang (@languages) +- { +- $po_files_by_lang{$lang} = shift (@po_files); +- } +-} +- +-sub POFile_GetLanguage ($) +-{ +- s/^(.*\/)?(.+)\.po$/$2/; +- return $_; +-} +- +-sub Console_Write_TranslationStatus +-{ +- my ($lang, $output_file) = @_; +- my $MSGFMT = $ENV{"MSGFMT"} || "@INTLTOOL_MSGFMT@"; +- +- $output_file = "$SRCDIR/$lang.po" if ($output_file eq ""); +- +- system ("$MSGFMT", "-o", "$devnull", "--verbose", $output_file); +-} +- +-sub Console_Write_CoverageReport +-{ +- my $MSGFMT = $ENV{"MSGFMT"} || "@INTLTOOL_MSGFMT@"; +- +- &GatherPOFiles; +- +- foreach my $lang (@languages) +- { +- print "$lang: "; +- &POFile_Update ($lang, ""); +- } +- +- print "\n\n * Current translation support in $MODULE \n\n"; +- +- foreach my $lang (@languages) +- { +- print "$lang: "; +- system ("$MSGFMT", "-o", "$devnull", "--verbose", "$SRCDIR/$lang.po"); +- } +-} +- +-sub SubstituteVariable +-{ +- my ($str) = @_; +- +- # always need to rewind file whenever it has been accessed +- seek (CONF, 0, 0); +- +- # cache each variable. varhash is global to we can add +- # variables elsewhere. +- while () +- { +- if (/^(\w+)=(.*)$/) +- { +- ($varhash{$1} = $2) =~ s/^["'](.*)["']$/$1/; +- } +- } +- +- if ($str =~ /^(.*)\${?([A-Z_]+)}?(.*)$/) +- { +- my $rest = $3; +- my $untouched = $1; +- my $sub = ""; +- # Ignore recursive definitions of variables +- $sub = $varhash{$2} if defined $varhash{$2} and $varhash{$2} !~ /\${?$2}?/; +- +- return SubstituteVariable ("$untouched$sub$rest"); +- } +- +- # We're using Perl backticks ` and "echo -n" here in order to +- # expand any shell escapes (such as backticks themselves) in every variable +- return echo_n ($str); +-} +- +-sub CONF_Handle_Open +-{ +- my $base_dirname = getcwd(); +- $base_dirname =~ s@.*/@@; +- +- my ($conf_in, $src_dir); +- +- if ($base_dirname =~ /^po(-.+)?$/) +- { +- if (-f "Makevars") +- { +- my $makefile_source; +- +- local (*IN); +- open (IN, ") +- { +- if (/^top_builddir[ \t]*=/) +- { +- $src_dir = $_; +- $src_dir =~ s/^top_builddir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/; +- +- chomp $src_dir; +- if (-f "$src_dir" . "/configure.ac") { +- $conf_in = "$src_dir" . "/configure.ac" . "\n"; +- } else { +- $conf_in = "$src_dir" . "/configure.in" . "\n"; +- } +- last; +- } +- } +- close IN; +- +- $conf_in || die "Cannot find top_builddir in Makevars."; +- } +- elsif (-f "../configure.ac") +- { +- $conf_in = "../configure.ac"; +- } +- elsif (-f "../configure.in") +- { +- $conf_in = "../configure.in"; +- } +- else +- { +- my $makefile_source; +- +- local (*IN); +- open (IN, ") +- { +- if (/^top_srcdir[ \t]*=/) +- { +- $src_dir = $_; +- $src_dir =~ s/^top_srcdir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/; +- +- chomp $src_dir; +- $conf_in = "$src_dir" . "/configure.in" . "\n"; +- +- last; +- } +- } +- close IN; +- +- $conf_in || die "Cannot find top_srcdir in Makefile."; +- } +- +- open (CONF, "<$conf_in"); +- } +- else +- { +- print STDERR "$PROGRAM: Unable to proceed.\n" . +- "Make sure to run this script inside the po directory.\n"; +- exit; +- } +-} +- +-sub FindPackageName +-{ +- my $version; +- my $domain = &FindMakevarsDomain; +- my $name = $domain || "untitled"; +- +- &CONF_Handle_Open; +- +- my $conf_source; { +- local (*IN); +- open (IN, "<&CONF") || return $name; +- seek (IN, 0, 0); +- local $/; # slurp mode +- $conf_source = ; +- close IN; +- } +- +- # priority for getting package name: +- # 1. GETTEXT_PACKAGE +- # 2. first argument of AC_INIT (with >= 2 arguments) +- # 3. first argument of AM_INIT_AUTOMAKE (with >= 2 argument) +- +- # /^AM_INIT_AUTOMAKE\([\s\[]*([^,\)\s\]]+)/m +- # the \s makes this not work, why? +- if ($conf_source =~ /^AM_INIT_AUTOMAKE\(([^,\)]+),([^,\)]+)/m) +- { +- ($name, $version) = ($1, $2); +- $name =~ s/[\[\]\s]//g; +- $version =~ s/[\[\]\s]//g; +- $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/); +- $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/); +- $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/); +- $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/); +- } +- +- if ($conf_source =~ /^AC_INIT\(([^,\)]+),([^,\)]+)/m) +- { +- ($name, $version) = ($1, $2); +- $name =~ s/[\[\]\s]//g; +- $version =~ s/[\[\]\s]//g; +- $varhash{"PACKAGE_NAME"} = $name if (not $name =~ /\${?AC_PACKAGE_NAME}?/); +- $varhash{"PACKAGE"} = $name if (not $name =~ /\${?PACKAGE}?/); +- $varhash{"PACKAGE_VERSION"} = $version if (not $name =~ /\${?AC_PACKAGE_VERSION}?/); +- $varhash{"VERSION"} = $version if (not $name =~ /\${?VERSION}?/); +- } +- +- # \s makes this not work, why? +- $name = $1 if $conf_source =~ /^GETTEXT_PACKAGE=\[?([^\n\]]+)/m; +- +- # m4 macros AC_PACKAGE_NAME, AC_PACKAGE_VERSION etc. have same value +- # as corresponding $PACKAGE_NAME, $PACKAGE_VERSION etc. shell variables. +- $name =~ s/\bAC_PACKAGE_/\$PACKAGE_/g; +- +- $name = $domain if $domain; +- +- $name = SubstituteVariable ($name); +- $name =~ s/^["'](.*)["']$/$1/; +- +- return $name if $name; +-} +- +- +-sub FindPOTKeywords +-{ +- +- my $keywords = "--keyword\=\_ --keyword\=N\_ --keyword\=U\_ --keyword\=Q\_"; +- my $varname = "XGETTEXT_OPTIONS"; +- my $make_source; { +- local (*IN); +- open (IN, "; +- close IN; +- } +- +- $keywords = $1 if $make_source =~ /^$varname[ ]*=\[?([^\n\]]+)/m; +- +- return $keywords; +-} +- +-sub FindMakevarsDomain +-{ +- +- my $domain = ""; +- my $makevars_source; { +- local (*IN); +- open (IN, "; +- close IN; +- } +- +- $domain = $1 if $makevars_source =~ /^DOMAIN[ ]*=\[?([^\n\]\$]+)/m; +- $domain =~ s/^\s+//; +- $domain =~ s/\s+$//; +- +- return $domain; +-} +- +-sub FindMakevarsBugAddress +-{ +- +- my $address = ""; +- my $makevars_source; { +- local (*IN); +- open (IN, "; +- close IN; +- } +- +- $address = $1 if $makevars_source =~ /^MSGID_BUGS_ADDRESS[ ]*=\[?([^\n\]\$]+)/m; +- $address =~ s/^\s+//; +- $address =~ s/\s+$//; +- +- return $address; +-} +diff --git a/intltool-update.in b/intltool-update.in +new file mode 120000 +index 661d8fe..0b1800f +--- /dev/null ++++ b/intltool-update.in +@@ -0,0 +1 @@ ++/usr/share/intltool/intltool-update.in +\ No newline at end of file +diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am +index f5dd164..27aec65 100644 +--- a/pixmaps/Makefile.am ++++ b/pixmaps/Makefile.am +@@ -3,8 +3,14 @@ icon_DATA = \ + intlclock-calendar-icon.png \ + intlclock-face-large.svg \ + intlclock-face-small.svg \ ++ intlclock-face-small-morning.svg \ ++ intlclock-face-small-day.svg \ ++ intlclock-face-small-evening.svg \ ++ intlclock-face-small-night.svg \ + intlclock-map.svg \ +- intlclock-map-location-marker.svg ++ intlclock-map-location-marker.svg \ ++ intlclock-map-location-current.svg \ ++ intlclock-map-location-hilight.svg + + EXTRA_DIST = $(icon_DATA) + +diff --git a/pixmaps/intlclock-face-small-day.svg b/pixmaps/intlclock-face-small-day.svg +new file mode 100644 +index 0000000..bd4b5b2 +--- /dev/null ++++ b/pixmaps/intlclock-face-small-day.svg +@@ -0,0 +1,290 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ image/svg+xml ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/pixmaps/intlclock-face-small-evening.svg b/pixmaps/intlclock-face-small-evening.svg +new file mode 100644 +index 0000000..17a9840 +--- /dev/null ++++ b/pixmaps/intlclock-face-small-evening.svg +@@ -0,0 +1,290 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ image/svg+xml ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/pixmaps/intlclock-face-small-morning.svg b/pixmaps/intlclock-face-small-morning.svg +new file mode 100644 +index 0000000..17a9840 +--- /dev/null ++++ b/pixmaps/intlclock-face-small-morning.svg +@@ -0,0 +1,290 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ image/svg+xml ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/pixmaps/intlclock-face-small-night.svg b/pixmaps/intlclock-face-small-night.svg +new file mode 100644 +index 0000000..d5a7d8e +--- /dev/null ++++ b/pixmaps/intlclock-face-small-night.svg +@@ -0,0 +1,291 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ image/svg+xml ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/pixmaps/intlclock-map-location-current.png b/pixmaps/intlclock-map-location-current.png +new file mode 100644 +index 0000000..5c505d1 +Binary files /dev/null and b/pixmaps/intlclock-map-location-current.png differ +diff --git a/pixmaps/intlclock-map-location-current.svg b/pixmaps/intlclock-map-location-current.svg +new file mode 100644 +index 0000000..93b5188 +--- /dev/null ++++ b/pixmaps/intlclock-map-location-current.svg +@@ -0,0 +1,76 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ image/svg+xml ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/pixmaps/intlclock-map-location-hilight.png b/pixmaps/intlclock-map-location-hilight.png +new file mode 100644 +index 0000000..d7de5b7 +Binary files /dev/null and b/pixmaps/intlclock-map-location-hilight.png differ +diff --git a/pixmaps/intlclock-map-location-hilight.svg b/pixmaps/intlclock-map-location-hilight.svg +new file mode 100644 +index 0000000..4a245e0 +--- /dev/null ++++ b/pixmaps/intlclock-map-location-hilight.svg +@@ -0,0 +1,90 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ image/svg+xml ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/pixmaps/intlclock-map-location-marker.png b/pixmaps/intlclock-map-location-marker.png +new file mode 100644 +index 0000000..48d2184 +Binary files /dev/null and b/pixmaps/intlclock-map-location-marker.png differ +diff --git a/po/Makefile.in.in b/po/Makefile.in.in +deleted file mode 100755 +index d2d4e4c..e4713cf +--- a/po/Makefile.in.in ++++ /dev/null +@@ -1,221 +0,0 @@ +-# Makefile for program source directory in GNU NLS utilities package. +-# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper +-# +-# This file file be copied and used freely without restrictions. It can +-# be used in projects which are not available under the GNU Public License +-# but which still want to provide support for the GNU gettext functionality. +-# Please note that the actual code is *not* freely available. +-# +-# - Modified by Owen Taylor to use GETTEXT_PACKAGE +-# instead of PACKAGE and to look for po2tbl in ./ not in intl/ +-# +-# - Modified by jacob berkman to install +-# Makefile.in.in and po2tbl.sed.in for use with glib-gettextize +-# +-# - Modified by Rodney Dawes for use with intltool +-# +-# We have the following line for use by intltoolize: +-# INTLTOOL_MAKEFILE +- +-GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +-PACKAGE = @PACKAGE@ +-VERSION = @VERSION@ +- +-SHELL = /bin/sh +- +-srcdir = @srcdir@ +-top_srcdir = @top_srcdir@ +-top_builddir = .. +-VPATH = @srcdir@ +- +-prefix = @prefix@ +-exec_prefix = @exec_prefix@ +-datadir = @datadir@ +-datarootdir = @datarootdir@ +-libdir = @libdir@ +-DATADIRNAME = @DATADIRNAME@ +-itlocaledir = $(prefix)/$(DATADIRNAME)/locale +-subdir = po +-install_sh = @install_sh@ +-# Automake >= 1.8 provides @mkdir_p@. +-# Until it can be supposed, use the safe fallback: +-mkdir_p = $(install_sh) -d +- +-INSTALL = @INSTALL@ +-INSTALL_DATA = @INSTALL_DATA@ +- +-GMSGFMT = @GMSGFMT@ +-MSGFMT = @MSGFMT@ +-XGETTEXT = @XGETTEXT@ +-INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +-INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +-MSGMERGE = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist +-GENPOT = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot +- +-ALL_LINGUAS = @ALL_LINGUAS@ +- +-PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; fi) +- +-POFILES=$(shell if test -n "$(PO_LINGUAS)"; then LINGUAS="$(PO_LINGUAS)"; else LINGUAS="$(ALL_LINGUAS)"; fi; for lang in $$LINGUAS; do printf "$$lang.po "; done) +- +-DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(POFILES) +-EXTRA_DISTFILES = POTFILES.skip Makevars LINGUAS +- +-POTFILES = \ +-#This Gets Replace for some reason +- +-CATALOGS=$(shell if test -n "$(PO_LINGUAS)"; then LINGUAS="$(PO_LINGUAS)"; else LINGUAS="$(ALL_LINGUAS)"; fi; for lang in $$LINGUAS; do printf "$$lang.gmo "; done) +- +-.SUFFIXES: +-.SUFFIXES: .po .pox .gmo .mo .msg .cat +- +-.po.pox: +- $(MAKE) $(GETTEXT_PACKAGE).pot +- $(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox +- +-.po.mo: +- $(MSGFMT) -o $@ $< +- +-.po.gmo: +- file=`echo $* | sed 's,.*/,,'`.gmo \ +- && rm -f $$file && $(GMSGFMT) -o $$file $< +- +-.po.cat: +- sed -f ../intl/po2msg.sed < $< > $*.msg \ +- && rm -f $@ && gencat $@ $*.msg +- +- +-all: all-@USE_NLS@ +- +-all-yes: $(CATALOGS) +-all-no: +- +-$(GETTEXT_PACKAGE).pot: $(POTFILES) +- $(GENPOT) +- +-install: install-data +-install-data: install-data-@USE_NLS@ +-install-data-no: all +-install-data-yes: all +- $(mkdir_p) $(DESTDIR)$(itlocaledir) +- if test -n "$(PO_LINGUAS)"; then \ +- linguas="$(PO_LINGUAS)"; \ +- else \ +- linguas="$(ALL_LINGUAS)"; \ +- fi; \ +- for lang in $$linguas; do \ +- dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \ +- $(mkdir_p) $$dir; \ +- if test -r $$lang.gmo; then \ +- $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ +- echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \ +- else \ +- $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ +- echo "installing $(srcdir)/$$lang.gmo as" \ +- "$$dir/$(GETTEXT_PACKAGE).mo"; \ +- fi; \ +- if test -r $$lang.gmo.m; then \ +- $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ +- echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ +- else \ +- if test -r $(srcdir)/$$lang.gmo.m ; then \ +- $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \ +- $$dir/$(GETTEXT_PACKAGE).mo.m; \ +- echo "installing $(srcdir)/$$lang.gmo.m as" \ +- "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ +- else \ +- true; \ +- fi; \ +- fi; \ +- done +- +-# Empty stubs to satisfy archaic automake needs +-dvi info tags TAGS ID: +- +-# Define this as empty until I found a useful application. +-installcheck: +- +-uninstall: +- if test -n "$(PO_LINGUAS)"; then \ +- linguas="$(PO_LINGUAS)"; \ +- else \ +- linguas="$(ALL_LINGUAS)"; \ +- fi; \ +- for lang in $$linguas; do \ +- rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ +- rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ +- done +- +-check: all $(GETTEXT_PACKAGE).pot +- +-mostlyclean: +- rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp +- rm -f .intltool-merge-cache +- +-clean: mostlyclean +- +-distclean: clean +- rm -f Makefile Makefile.in POTFILES stamp-it +- rm -f *.mo *.msg *.cat *.cat.m *.gmo +- +-maintainer-clean: distclean +- @echo "This command is intended for maintainers to use;" +- @echo "it deletes files that may require special tools to rebuild." +- rm -f Makefile.in.in +- +-distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) +-dist distdir: $(DISTFILES) +- dists="$(DISTFILES)"; \ +- extra_dists="$(EXTRA_DISTFILES)"; \ +- for file in $$extra_dists; do \ +- test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ +- done; \ +- for file in $$dists; do \ +- test -f $$file || file="$(srcdir)/$$file"; \ +- ln $$file $(distdir) 2> /dev/null \ +- || cp -p $$file $(distdir); \ +- done +- +-update-po: Makefile +- $(MAKE) $(GETTEXT_PACKAGE).pot +- tmpdir=`pwd`; \ +- if test -n "$(PO_LINGUAS)"; then \ +- linguas="$(PO_LINGUAS)"; \ +- else \ +- linguas="$(ALL_LINGUAS)"; \ +- fi; \ +- for lang in $$linguas; do \ +- echo "$$lang:"; \ +- result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \ +- if $$result; then \ +- if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ +- rm -f $$tmpdir/$$lang.new.po; \ +- else \ +- if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ +- :; \ +- else \ +- echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ +- rm -f $$tmpdir/$$lang.new.po; \ +- exit 1; \ +- fi; \ +- fi; \ +- else \ +- echo "msgmerge for $$lang.gmo failed!"; \ +- rm -f $$tmpdir/$$lang.new.po; \ +- fi; \ +- done +- +-Makefile POTFILES: stamp-it +- @if test ! -f $@; then \ +- rm -f stamp-it; \ +- $(MAKE) stamp-it; \ +- fi +- +-stamp-it: Makefile.in.in ../config.status POTFILES.in +- cd .. \ +- && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ +- $(SHELL) ./config.status +- +-# Tell versions [3.59,3.63) of GNU make not to export all variables. +-# Otherwise a system limit (for SysV at least) may be exceeded. +-.NOEXPORT: +diff --git a/po/Makefile.in.in b/po/Makefile.in.in +new file mode 120000 +index d2d4e4c..e4713cf +--- /dev/null ++++ b/po/Makefile.in.in +@@ -0,0 +1 @@ ++/usr/share/intltool/Makefile.in.in +\ No newline at end of file +diff --git a/src/Makefile.am b/src/Makefile.am +index 80d1419..d681d39 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -3,7 +3,7 @@ + INCLUDES = \ + $(INTLCLOCK_CFLAGS) \ + -DGNOMELOCALEDIR=\"$(prefix)/$(DATADIRNAME)/locale\" \ +- -DEVOLUTION_TEXTDOMAIN=\"evolution-2.6\" \ ++ -DEVOLUTION_TEXTDOMAIN=\"evolution-2.12\" \ + -DINTLCLOCK_TEXTDOMAIN=\"gnome-panel-2.0\" \ + -DINTLCLOCK_ICONDIR=\"$(pkgdatadir)\" \ + -DINTLCLOCK_DATADIR=\"$(pkgdatadir)\" \ +@@ -60,7 +60,11 @@ COMMON_SOURCES = \ + intlclock-zoneinfo.c \ + intlclock-zoneinfo.h \ + intlclock-zonetable.c \ +- intlclock-zonetable.h ++ intlclock-zonetable.h \ ++ set-timezone.c \ ++ set-timezone.h \ ++ gweather-xml.c \ ++ gweather-xml.h + + + intlclock_applet_SOURCES = \ +diff --git a/src/gweather-xml.c b/src/gweather-xml.c +new file mode 100644 +index 0000000..94b275d +--- /dev/null ++++ b/src/gweather-xml.c +@@ -0,0 +1,490 @@ ++/* gweather-xml.c - Locations.xml parsing code ++ * ++ * Copyright (C) 2005 Ryan Lortie, 2004 Gareth Owen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++/* There is very little error checking in the parsing code below, it relies ++ * heavily on the locations file being in the correct format. If you have ++ * elements within a parent element, they must come first and be ++ * grouped together. ++ * The format is as follows: ++ * ++ * ++ * ++ * Name of the region ++ * Translated Name ++ * Another Translated Name ++ * ++ * Name of the country ++ * ++ * Name of the location ++ * IWIN code ++ * Forecast code (North America, Australia, UK only) ++ * Weather.com radar map code (North America only) ++ * Latitude and longitude as DD-MM[-SS][H] pair ++ * ++ * ++ * ++ * .... ++ * ++ * ++ * Name of city with multiple locations ++ * Forecast code ++ * Radar Map code ++ * ++ * ... ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * The thing to note is that each country can either contain different locations ++ * or be split into "states" which in turn contain a list of locations. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "gweather-xml.h" ++ ++static gint ++gweather_xml_location_sort_func( GtkTreeModel *model, GtkTreeIter *a, ++ GtkTreeIter *b, gpointer user_data ) ++{ ++ gint res; ++ gchar *name_a, *name_b; ++ gchar *fold_a, *fold_b; ++ ++ gtk_tree_model_get (model, a, GWEATHER_XML_COL_LOC, &name_a, -1); ++ gtk_tree_model_get (model, b, GWEATHER_XML_COL_LOC, &name_b, -1); ++ ++ fold_a = g_utf8_casefold(name_a, -1); ++ fold_b = g_utf8_casefold(name_b, -1); ++ ++ res = g_utf8_collate(fold_a, fold_b); ++ ++ g_free(name_a); ++ g_free(name_b); ++ g_free(fold_a); ++ g_free(fold_b); ++ ++ return res; ++} ++ ++static char* ++gweather_xml_get_value( xmlTextReaderPtr xml ) ++{ ++ char* value; ++ ++ /* check for null node */ ++ if ( xmlTextReaderIsEmptyElement( xml ) ) ++ return NULL; ++ ++ /* the next "node" is the text node containing the value we want to get */ ++ if( xmlTextReaderRead( xml ) != 1 ) ++ return NULL; ++ ++ value = (char *) xmlTextReaderValue( xml ); ++ ++ /* move on to the end of this node */ ++ while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_END_ELEMENT ) ++ if( xmlTextReaderRead( xml ) != 1 ) ++ { ++ xmlFree( value ); ++ return NULL; ++ } ++ ++ /* consume the end element too */ ++ if( xmlTextReaderRead( xml ) != 1 ) ++ { ++ xmlFree( value ); ++ return NULL; ++ } ++ ++ return value; ++} ++ ++static char * ++gweather_xml_parse_name( xmlTextReaderPtr xml ) ++{ ++ const char * const *locales; ++ const char *this_language; ++ int best_match = INT_MAX; ++ char *lang, *tagname; ++ gboolean keep_going; ++ char *name = NULL; ++ int i; ++ ++ locales = g_get_language_names(); ++ ++ do ++ { ++ /* First let's get the language */ ++ lang = (char *) xmlTextReaderXmlLang( xml ); ++ ++ if( lang == NULL ) ++ this_language = "C"; ++ else ++ this_language = lang; ++ ++ /* the next "node" is text node containing the actual name */ ++ if( xmlTextReaderRead( xml ) != 1 ) ++ { ++ xmlFree( lang ); ++ return NULL; ++ } ++ ++ for( i = 0; locales[i] && i < best_match; i++ ) ++ if( !strcmp( locales[i], this_language ) ) ++ { ++ /* if we've already encounted a less accurate ++ translation, then free it */ ++ xmlFree( name ); ++ ++ name = (char *) xmlTextReaderValue( xml ); ++ best_match = i; ++ ++ break; ++ } ++ ++ xmlFree( lang ); ++ ++ while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_ELEMENT ) ++ if( xmlTextReaderRead( xml ) != 1 ) ++ { ++ xmlFree( name ); ++ return NULL; ++ } ++ ++ /* if the next tag is another then keep going */ ++ tagname = (char *) xmlTextReaderName( xml ); ++ keep_going = !strcmp( tagname, "name" ); ++ xmlFree( tagname ); ++ ++ } while( keep_going ); ++ ++ return name; ++} ++ ++static int ++gweather_xml_parse_node (GtkTreeView *view, GtkTreeIter *parent, ++ xmlTextReaderPtr xml, WeatherLocation *current, ++ const char *dflt_radar, const char *dflt_zone, ++ const char *cityname) ++{ ++ GtkTreeStore *store = GTK_TREE_STORE( gtk_tree_view_get_model( view ) ); ++ char *name, *code, *zone, *radar, *coordinates; ++ char **city, *nocity = NULL; ++ GtkTreeIter iter, *self; ++ gboolean is_location; ++ char *tagname; ++ int ret = -1; ++ int tagtype; ++ ++ if( (tagname = (char *) xmlTextReaderName( xml )) == NULL ) ++ return -1; ++ ++ if( !strcmp( tagname, "city" ) ) ++ city = &name; ++ else ++ city = &nocity; ++ ++ is_location = !strcmp( tagname, "location" ); ++ ++ /* if we're processing the top-level, then don't create a new iter */ ++ if( !strcmp( tagname, "gweather" ) ) ++ self = NULL; ++ else ++ { ++ self = &iter; ++ /* insert this node into the tree */ ++ gtk_tree_store_append( store, self, parent ); ++ } ++ ++ xmlFree( tagname ); ++ ++ coordinates = NULL; ++ radar = NULL; ++ zone = NULL; ++ code = NULL; ++ name = NULL; ++ ++ /* absorb the start tag */ ++ if( xmlTextReaderRead( xml ) != 1 ) ++ goto error_out; ++ ++ /* start parsing the actual contents of the node */ ++ while( (tagtype = xmlTextReaderNodeType( xml )) != ++ XML_READER_TYPE_END_ELEMENT ) ++ { ++ ++ /* skip non-element types */ ++ if( tagtype != XML_READER_TYPE_ELEMENT ) ++ { ++ if( xmlTextReaderRead( xml ) != 1 ) ++ goto error_out; ++ ++ continue; ++ } ++ ++ tagname = (char *) xmlTextReaderName( xml ); ++ ++ if( !strcmp( tagname, "region" ) || !strcmp( tagname, "country" ) || ++ !strcmp( tagname, "state" ) || !strcmp( tagname, "city" ) || ++ !strcmp( tagname, "location" ) ) ++ { ++ /* recursively handle sub-sections */ ++ if( gweather_xml_parse_node( view, self, xml, current, ++ radar, zone, *city ) ) ++ goto error_out; ++ } ++ else if ( !strcmp( tagname, "name" ) ) ++ { ++ xmlFree( name ); ++ if( (name = gweather_xml_parse_name( xml )) == NULL ) ++ goto error_out; ++ } ++ else if ( !strcmp( tagname, "code" ) ) ++ { ++ xmlFree( code ); ++ if( (code = gweather_xml_get_value( xml )) == NULL ) ++ goto error_out; ++ } ++ else if ( !strcmp( tagname, "zone" ) ) ++ { ++ xmlFree( zone ); ++ if( (zone = gweather_xml_get_value( xml )) == NULL ) ++ goto error_out; ++ } ++ else if ( !strcmp( tagname, "radar" ) ) ++ { ++ xmlFree( radar ); ++ if( (radar = gweather_xml_get_value( xml )) == NULL ) ++ goto error_out; ++ } ++ else if ( !strcmp( tagname, "coordinates" ) ) ++ { ++ xmlFree( coordinates ); ++ if( (coordinates = gweather_xml_get_value( xml )) == NULL ) ++ goto error_out; ++ } ++ else /* some strange tag */ ++ { ++ /* skip past it */ ++ if( xmlTextReaderRead( xml ) != 1 ) ++ goto error_out; ++ } ++ ++ xmlFree( tagname ); ++ } ++ ++ if( self ) ++ gtk_tree_store_set( store, self, GWEATHER_XML_COL_LOC, name, -1 ); ++ ++ /* absorb the end tag. in the case of processing a then 'self' ++ is NULL. In this case, we let this fail since we might be at EOF */ ++ if( xmlTextReaderRead( xml ) != 1 && self ) ++ goto error_out; ++ ++ /* if this is an actual location, setup the WeatherLocation for it */ ++ if( is_location ) ++ { ++ WeatherLocation *new_loc; ++ ++ if( cityname == NULL ) ++ cityname = name; ++ ++ if( radar != NULL ) ++ dflt_radar = radar; ++ ++ if( zone != NULL ) ++ dflt_zone = zone; ++ ++ new_loc = weather_location_new( cityname, code, dflt_zone, ++ dflt_radar, coordinates ); ++ ++ gtk_tree_store_set( store, &iter, GWEATHER_XML_COL_POINTER, new_loc, -1 ); ++ ++ /* If this location is actually the currently selected one, select it */ ++ if( current && weather_location_equal( new_loc, current ) ) ++ { ++ GtkTreePath *path; ++ ++ path = gtk_tree_model_get_path( GTK_TREE_MODEL (store), &iter ); ++ gtk_tree_view_expand_to_path( view, path ); ++ gtk_tree_view_set_cursor( view, path, NULL, FALSE ); ++ gtk_tree_view_scroll_to_cell( view, path, NULL, TRUE, 0.5, 0.5 ); ++ gtk_tree_path_free( path ); ++ } ++ } ++ ++ ret = 0; ++ ++error_out: ++ xmlFree( name ); ++ xmlFree( code ); ++ xmlFree( zone ); ++ xmlFree( radar ); ++ xmlFree( coordinates ); ++ ++ return ret; ++} ++ ++/***************************************************************************** ++ * Func: gweather_xml_load_locations() ++ * Desc: Main entry point for loading the locations from the XML file ++ * Parm: ++ * *tree: tree to view locations ++ * *current: currently selected location ++ */ ++int ++gweather_xml_load_locations( GtkTreeView *tree, WeatherLocation *current ) ++{ ++ char *tagname, *format; ++ GtkTreeSortable *sortable; ++ xmlTextReaderPtr xml; ++ int keep_going; ++ int ret = -1; ++ ++ /* Open the xml file containing the different locations */ ++#ifdef GWEATHER_XML_LOCATION ++ xml = xmlNewTextReaderFilename (GWEATHER_XML_LOCATION "Locations.xml"); ++#else ++ xml = xmlNewTextReaderFilename ("/usr/share/gnome-applets/gweather/Locations.xml"); ++#endif ++ if( xml == NULL ) ++ goto error_out; ++ ++ /* fast forward to the first element */ ++ do ++ { ++ /* if we encounter a problem here, exit right away */ ++ if( xmlTextReaderRead( xml ) != 1 ) ++ goto error_out; ++ } while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_ELEMENT ); ++ ++ /* check the name and format */ ++ tagname = (char *) xmlTextReaderName( xml ); ++ keep_going = tagname && !strcmp( tagname, "gweather" ); ++ xmlFree( tagname ); ++ ++ if( !keep_going ) ++ goto error_out; ++ ++ format = (char *) xmlTextReaderGetAttribute( xml, (xmlChar *) "format" ); ++ keep_going = format && !strcmp( format, "1.0" ); ++ xmlFree( format ); ++ ++ if( !keep_going ) ++ goto error_out; ++ ++ ret = gweather_xml_parse_node( tree, NULL, xml, current, NULL, NULL, NULL ); ++ ++ if( ret ) ++ goto error_out; ++ ++ /* Sort the tree */ ++ sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model( tree )); ++ gtk_tree_sortable_set_default_sort_func( sortable, ++ &gweather_xml_location_sort_func, ++ NULL, NULL); ++ gtk_tree_sortable_set_sort_column_id( sortable, ++ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, ++ GTK_SORT_ASCENDING ); ++error_out: ++ xmlFreeTextReader( xml ); ++ ++ return ret; ++} ++ ++typedef struct { ++ const gchar *name; ++ gdouble latitude; ++ gdouble longitude; ++ gdouble distance; ++ WeatherLocation *location; ++} SearchData; ++ ++ ++static gdouble ++distance (gdouble lat1, gdouble lon1, ++ gdouble lat2, gdouble lon2) ++{ ++ gdouble radius = 6372.795; ++ ++ return acos (cos (lat1) * cos (lat2) * cos (lon1 - lon2) + sin (lat1) * sin (lat2)) * radius; ++} ++ ++gboolean ++compare_location (GtkTreeModel *model, ++ GtkTreePath *path, ++ GtkTreeIter *iter, ++ gpointer user_data) ++{ ++ SearchData *data = user_data; ++ WeatherLocation *loc; ++ gdouble d; ++ ++ gtk_tree_model_get (model, iter, GWEATHER_XML_COL_POINTER, &loc, -1); ++ ++ if (!loc) ++ return FALSE; ++ ++ d = distance (data->latitude, data->longitude, loc->latitude, loc->longitude); ++ ++ if (d < data->distance) { ++ data->distance = d; ++ data->location = loc; ++ } ++ ++ return FALSE; ++} ++ ++gchar * ++find_weather_code (GtkTreeModel *model, ++ const gchar *name, ++ gdouble lat, ++ gdouble lon) ++{ ++ SearchData data; ++ gchar *code; ++ ++ data.name = name; ++ data.latitude = lat; ++ data.longitude = lon; ++ data.distance = 1e6; ++ data.location = NULL; ++ ++ gtk_tree_model_foreach (GTK_TREE_MODEL (model), compare_location, &data); ++ ++ if (data.distance < 50) ++ code = g_strdup (data.location->code); ++ else ++ code = g_strdup ("-"); ++ ++ g_debug ("distance: %f\nin: %s\nlat, lon: %f, %f\nout: %s\nDMS: %s\ncode: %s\n", ++ data.distance, name, lat, lon, data.location->name, data.location->coordinates, code); ++ ++ return code; ++} +diff --git a/src/gweather-xml.h b/src/gweather-xml.h +new file mode 100644 +index 0000000..d65b651 +--- /dev/null ++++ b/src/gweather-xml.h +@@ -0,0 +1,37 @@ ++/* gweather-xml.h ++ * ++ * Copyright (C) 2004 Gareth Owen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef __GWEATHER_XML_H__ ++#define __GWEATHER_XML_H__ ++ ++#include ++#include ++ ++enum ++{ ++ GWEATHER_XML_COL_LOC = 0, ++ GWEATHER_XML_COL_POINTER, ++ GWEATHER_XML_NUM_COLUMNS ++}; ++ ++int gweather_xml_load_locations( GtkTreeView *tree, WeatherLocation *current ); ++gchar *find_weather_code (GtkTreeModel *model, const gchar *name, gdouble lat, gdouble lon); ++ ++ ++#endif /* __GWEATHER_XML_H__ */ +diff --git a/src/intlclock-events-popup.c b/src/intlclock-events-popup.c +index 4276f81..a54f6e3 100644 +--- a/src/intlclock-events-popup.c ++++ b/src/intlclock-events-popup.c +@@ -1,6 +1,8 @@ + #include + #include + #include ++#include ++#include + + #ifdef HAVE_CONFIG_H + #include "config.h" +@@ -11,12 +13,18 @@ + #endif + + #include "intlclock-events-popup.h" ++#include "intlclock-ui.h" ++ ++#define KEY_EXPAND_LOCATIONS "expand_locations" ++#define KEY_EXPAND_TASKS "expand_tasks" ++#define KEY_EXPAND_APPOINTMENTS "expand_appointments" + + G_DEFINE_TYPE (IntlClockEventsPopup, intlclock_events_popup, GTK_TYPE_WINDOW) + + typedef struct { + IntlClock *clock; + PanelApplet *panel_applet; ++ IntlClockUI *ui; + + GtkWidget *calendar; + GtkWidget *main_section; +@@ -126,7 +134,7 @@ intlclock_events_popup_size_allocate_cb (GtkWidget *widget, GtkAllocation *alloc + } + + IntlClockEventsPopup * +-intlclock_events_popup_new (IntlClock *clock, PanelApplet *panel_applet) ++intlclock_events_popup_new (IntlClock *clock, PanelApplet *panel_applet, IntlClockUI *ui) + { + IntlClockEventsPopup *this; + IntlClockEventsPopupPrivate *priv; +@@ -138,6 +146,7 @@ intlclock_events_popup_new (IntlClock *clock, PanelApplet *panel_applet) + + priv->clock = g_object_ref (clock); + priv->panel_applet = panel_applet; ++ priv->ui = ui; + + gtk_widget_set_name (GTK_WIDGET (this), "intlclock-events-window"); + gtk_container_set_border_width (GTK_CONTAINER (this), 0); +@@ -275,6 +284,21 @@ intlclock_events_popup_tick (IntlClock *clock, IntlClockEventsPopup *this) + gmtime (&priv->current_time); + } + ++static GtkWidget * create_hig_frame (IntlClockEventsPopup *this, ++ const char *title, ++ const char *button_label, ++ const char *key, ++ GCallback callback); ++ ++ ++static void ++edit_locations (IntlClockEventsPopup *this) ++{ ++ IntlClockEventsPopupPrivate *priv = PRIVATE (this); ++ ++ intlclock_ui_edit_locations (priv->ui); ++} ++ + static void + intlclock_events_popup_fill (IntlClockEventsPopup *this) + { +@@ -296,7 +320,10 @@ intlclock_events_popup_fill (IntlClockEventsPopup *this) + + orient = panel_applet_get_orient (priv->panel_applet); + +- priv->clock_container = gtk_vbox_new (FALSE, 0); ++ priv->clock_container = create_hig_frame (this, ++ _("Locations"), _("Edit"), ++ KEY_EXPAND_LOCATIONS, ++ G_CALLBACK (edit_locations)); + + switch (orient) { + case PANEL_APPLET_ORIENT_UP: +@@ -642,28 +669,167 @@ modify_task_text_attributes (GtkTreeModel *model, + g_value_take_boxed (value, attr_list); + } + ++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 ++expander_activated (GtkExpander *expander, ++ gpointer data) ++{ ++ IntlClockEventsPopup *this = data; ++ IntlClockEventsPopupPrivate *priv = PRIVATE (this); ++ const gchar *key; ++ gboolean expanded; ++ ++ key = (const gchar*)g_object_get_data (G_OBJECT (expander), "gconf-key"); ++ expanded = gtk_expander_get_expanded (expander); ++ ++ panel_applet_gconf_set_bool (priv->panel_applet, key, expanded, NULL); ++} ++ ++static void ++expanded_changed (GConfClient *client, ++ guint cnxn_id, ++ GConfEntry *entry, ++ GtkExpander *expander) ++{ ++ if (!entry->value || entry->value->type != GCONF_VALUE_BOOL) ++ return; ++ ++ gtk_expander_set_expanded (expander, ++ gconf_value_get_bool (entry->value)); ++} ++ ++static void ++remove_listener (gpointer data) ++{ ++ GConfClient *client; ++ ++ client = gconf_client_get_default (); ++ gconf_client_notify_remove (client, GPOINTER_TO_UINT (data)); ++ g_object_unref (client); ++} ++ ++static void ++connect_expander_with_gconf (IntlClockEventsPopup *this, ++ GtkWidget *expander, ++ const gchar *key) ++{ ++ IntlClockEventsPopupPrivate *priv = PRIVATE (this); ++ GConfClient *client; ++ gboolean expanded; ++ guint listener; ++ gchar *full_key; ++ ++ g_object_set_data (G_OBJECT (expander), "gconf-key", (gpointer)key); ++ ++ expanded = panel_applet_gconf_get_bool (priv->panel_applet, key, NULL); ++ gtk_expander_set_expanded (GTK_EXPANDER (expander), expanded); ++ ++ g_signal_connect_after (expander, "activate", ++ G_CALLBACK (expander_activated), ++ this); ++ ++ client = gconf_client_get_default (); ++ full_key = panel_applet_gconf_get_full_key (priv->panel_applet, key); ++ listener = gconf_client_notify_add (client, full_key, ++ (GConfClientNotifyFunc)expanded_changed, ++ expander, NULL, NULL); ++ g_object_set_data_full (G_OBJECT (expander), "listener-id", ++ GUINT_TO_POINTER (listener), remove_listener); ++ g_object_unref (client); ++} ++ ++static void add_child (GtkContainer *container, ++ GtkWidget *child, ++ GtkExpander *expander) ++{ ++ gboolean expanded; ++ ++ expanded = gtk_expander_get_expanded (expander); ++ g_object_set (child, "visible", expanded, NULL); ++} ++ + static GtkWidget * +-create_hig_frame (const char *title) ++create_hig_frame (IntlClockEventsPopup *this, ++ 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); +- +- alignment = gtk_alignment_new (0, 0.5, 0, 0); +- gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0); +- gtk_widget_show (alignment); +- +- label = gtk_label_new (bold_title); +- gtk_label_set_use_markup (GTK_LABEL (label), TRUE); +- gtk_container_add (GTK_CONTAINER (alignment), label); +- gtk_widget_show (label); +- ++ expander = gtk_expander_new (""); ++ gtk_expander_set_label (GTK_EXPANDER (expander), 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, this); ++ } ++ ++ connect_expander_with_gconf (this, expander, key); + + return vbox; + } +@@ -791,6 +957,12 @@ compare_tasks (GtkTreeModel *model, + } + } + ++static void ++edit_tasks (IntlClockEventsPopup *this) ++{ ++ clock_launch_evolution (this, "--component=tasks"); ++} ++ + static GtkWidget * + create_task_list (IntlClockEventsPopup *this, + GtkWidget **tree_view, +@@ -804,7 +976,9 @@ create_task_list (IntlClockEventsPopup *this, + GtkCellRenderer *cell; + GtkTreeViewColumn *column; + +- vbox = create_hig_frame (_("Tasks")); ++ vbox = create_hig_frame (this, _("Tasks"), _("Edit"), ++ KEY_EXPAND_TASKS, ++ G_CALLBACK (edit_tasks)); + + *scrolled_window = scrolled = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), +@@ -812,8 +986,8 @@ create_task_list (IntlClockEventsPopup *this, + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); +- gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0); + gtk_widget_show (scrolled); ++ gtk_container_add (GTK_CONTAINER (vbox), scrolled); + + if (!priv->tasks_model) { + GType column_types [N_TASK_COLUMNS] = { +@@ -984,6 +1158,12 @@ handle_appointments_changed (IntlClockEventsPopup *this) + update_frame_visibility (priv->appointment_list, GTK_TREE_MODEL (priv->appointments_model)); + } + ++static void ++edit_appointments (IntlClockEventsPopup *this) ++{ ++ clock_launch_evolution (this, "--component=calendar"); ++} ++ + static GtkWidget * + create_appointment_list (IntlClockEventsPopup *this, + GtkWidget **tree_view, +@@ -997,7 +1177,9 @@ create_appointment_list (IntlClockEventsPopup *this, + GtkCellRenderer *cell; + GtkTreeViewColumn *column; + +- vbox = create_hig_frame ( _("Appointments")); ++ vbox = create_hig_frame (this, _("Appointments"), _("Edit"), ++ KEY_EXPAND_APPOINTMENTS, ++ G_CALLBACK (edit_appointments)); + + *scrolled_window = scrolled = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), +@@ -1005,8 +1187,8 @@ create_appointment_list (IntlClockEventsPopup *this, + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); +- gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0); + gtk_widget_show (scrolled); ++ gtk_container_add (GTK_CONTAINER (vbox), scrolled); + + if (!priv->appointments_model) { + priv->appointments_model = +diff --git a/src/intlclock-events-popup.h b/src/intlclock-events-popup.h +index 84a5183..b88e4c7 100644 +--- a/src/intlclock-events-popup.h ++++ b/src/intlclock-events-popup.h +@@ -2,6 +2,7 @@ + #define __INTLCLOCK_EVENTS_POPUP_H__ + + #include "intlclock.h" ++#include "intlclock-ui.h" + + #include + #include +@@ -29,7 +30,8 @@ typedef struct + GType intlclock_events_popup_get_type (void); + + IntlClockEventsPopup *intlclock_events_popup_new (IntlClock *clock, +- PanelApplet *panel_applet); ++ PanelApplet *panel_applet, ++ IntlClockUI *ui); + void intlclock_events_popup_set_date (IntlClockEventsPopup *this, + guint year, guint month, guint mday); + GtkWidget *intlclock_events_popup_get_clock_container (IntlClockEventsPopup *this); +diff --git a/src/intlclock-face.c b/src/intlclock-face.c +index 537e8e7..b2e1eb0 100644 +--- a/src/intlclock-face.c ++++ b/src/intlclock-face.c +@@ -33,6 +33,13 @@ static void intlclock_face_load_face (IntlClockFace *this, + gint width, gint height); + typedef struct _IntlClockFacePrivate IntlClockFacePrivate; + ++typedef enum { ++ INTLCLOCK_FACE_MORNING, ++ INTLCLOCK_FACE_DAY, ++ INTLCLOCK_FACE_EVENING, ++ INTLCLOCK_FACE_NIGHT ++} IntlClockFaceTimeOfDay; ++ + struct _IntlClockFacePrivate + { + struct tm time; /* the time on the clock face */ +@@ -40,8 +47,8 @@ struct _IntlClockFacePrivate + + gboolean running; + IntlClockFaceSize size; ++ IntlClockFaceTimeOfDay timeofday; + IntlClockLocation *location; +- RsvgHandle *face; + GdkPixbuf *face_pixbuf; + GtkWidget *size_widget; + }; +@@ -80,6 +87,7 @@ intlclock_face_init (IntlClockFace *this) + IntlClockFacePrivate *priv = INTLCLOCK_FACE_GET_PRIVATE (this); + + priv->size = INTLCLOCK_FACE_SMALL; ++ priv->timeofday = INTLCLOCK_FACE_DAY; + priv->location = NULL; + priv->size_widget = NULL; + +@@ -281,6 +289,48 @@ static void intlclock_face_size_request (GtkWidget *this, + requisition->height = h; + } + ++static void ++update_timeofday (IntlClockFace *this) ++{ ++ IntlClockFacePrivate *priv; ++ IntlClockFaceTimeOfDay timeofday; ++ ++ priv = INTLCLOCK_FACE_GET_PRIVATE (this); ++ ++ /* FIXME this should be a gconf setting ++ * currently we hardcode ++ * morning 7-9 ++ * day 9-17 ++ * evening 17-22 ++ * night 22-7 ++ */ ++ if (priv->time.tm_hour < 7) ++ timeofday = INTLCLOCK_FACE_NIGHT; ++ else if (priv->time.tm_hour < 9) ++ timeofday = INTLCLOCK_FACE_MORNING; ++ else if (priv->time.tm_hour < 17) ++ timeofday = INTLCLOCK_FACE_DAY; ++ else if (priv->time.tm_hour < 22) ++ timeofday = INTLCLOCK_FACE_EVENING; ++ else ++ timeofday = INTLCLOCK_FACE_NIGHT; ++ ++ if (priv->timeofday != timeofday) { ++ priv->timeofday = timeofday; ++ gint width, height; ++ ++ width = GTK_WIDGET (this)->requisition.width; ++ height = GTK_WIDGET (this)->requisition.height; ++ ++ if (width == 0) ++ width = -1; ++ if (height == 0) ++ height = -1; ++ ++ intlclock_face_load_face (this, width, height); ++ } ++} ++ + gboolean + intlclock_face_refresh (IntlClockFace *this) + { +@@ -301,6 +351,8 @@ intlclock_face_refresh (IntlClockFace *this) + localtime_r (&timet, &priv->time); + } + ++ update_timeofday (this); ++ + intlclock_face_redraw_canvas (this); + + return TRUE; /* keep running this event */ +@@ -343,11 +395,6 @@ intlclock_face_finalize (GObject *obj) + priv->location = NULL; + } + +- if (priv->face) { +- rsvg_handle_close (priv->face, NULL); +- priv->face = NULL; +- } +- + if (priv->face_pixbuf) { + gdk_pixbuf_unref (priv->face_pixbuf); + priv->face_pixbuf = NULL; +@@ -375,16 +422,24 @@ static void + intlclock_face_load_face (IntlClockFace *this, gint width, gint height) + { + IntlClockFacePrivate *priv = INTLCLOCK_FACE_GET_PRIVATE (this); ++ const gchar *size_string[2] = { "small", "large" }; ++ const gchar *daytime_string[4] = { "morning", "day", "evening", "night" }; ++ gchar *name; + + if (priv->face_pixbuf != NULL) { + gdk_pixbuf_unref (priv->face_pixbuf); + priv->face_pixbuf = NULL; + } + +- if (priv->size == INTLCLOCK_FACE_SMALL) { +- priv->face_pixbuf = rsvg_pixbuf_from_file_at_size (INTLCLOCK_ICONDIR "/intlclock-face-small.svg", width, height, NULL); +- } else { +- priv->face_pixbuf = rsvg_pixbuf_from_file_at_size (INTLCLOCK_ICONDIR "/intlclock-face-large.svg", width, height, NULL); +- } ++ name = g_strconcat (INTLCLOCK_ICONDIR, "/intlclock-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) ++ return; + ++ name = g_strconcat (INTLCLOCK_ICONDIR, "/intlclock-face-", size_string[priv->size], ".svg", NULL); ++ priv->face_pixbuf = rsvg_pixbuf_from_file_at_size (name, width, height, NULL); ++ g_free (name); + } +diff --git a/src/intlclock-location-tile.c b/src/intlclock-location-tile.c +index 40d96e3..3535d8d 100644 +--- a/src/intlclock-location-tile.c ++++ b/src/intlclock-location-tile.c +@@ -23,9 +23,18 @@ typedef struct { + + IntlClockFaceSize size; + ++ GtkWidget *box; + GtkWidget *clock_face; + GtkWidget *city_label; + GtkWidget *time_label; ++ ++ GtkWidget *current_button; ++ GtkWidget *current_label; ++ GtkWidget *current_marker; ++ GtkSizeGroup *button_group; ++ ++ GtkWidget *weather_icon; ++ + } IntlClockLocationTilePrivate; + + static void intlclock_location_tile_finalize (GObject *); +@@ -36,6 +45,12 @@ static void intlclock_location_tile_refresh (IntlClockLocationTile *this); + #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INTLCLOCK_LOCATION_TILE_TYPE, IntlClockLocationTilePrivate)) + + static void intlclock_location_tile_fill (IntlClockLocationTile *this); ++static void update_weather_icon (IntlClockLocation *loc, WeatherInfo *info, gpointer data); ++static gboolean weather_tooltip (GtkWidget *widget, ++ gint x, gint y, ++ gboolean keyboard_mode, ++ GtkTooltip *tooltip, ++ gpointer data); + + IntlClockLocationTile * + intlclock_location_tile_new (IntlClock *clock, IntlClockUI *ui, +@@ -56,13 +71,17 @@ intlclock_location_tile_new (IntlClock *clock, IntlClockUI *ui, + priv->location = g_object_ref (loc); + priv->size = size; + +- gtk_alignment_set (GTK_ALIGNMENT (this), 0.0, 0.0, 0.0, 0.0); +- gtk_alignment_set_padding (GTK_ALIGNMENT (this), 3, 3, 3, 3); +- + intlclock_location_tile_fill (this); + +- g_signal_connect (G_OBJECT (priv->clock), "tick", +- G_CALLBACK (intlclock_location_tile_tick), this); ++ update_weather_icon (loc, intlclock_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); ++ g_signal_connect (G_OBJECT (loc), "weather-updated", ++ G_CALLBACK (update_weather_icon), this); ++ g_signal_connect (G_OBJECT (priv->clock), "tick", ++ G_CALLBACK (intlclock_location_tile_tick), this); + + return this; + } +@@ -133,13 +152,99 @@ intlclock_location_tile_finalize (GObject *g_obj) + priv->location = NULL; + } + ++ if (priv->button_group) { ++ g_object_unref (priv->button_group); ++ priv->button_group = NULL; ++ } ++ + G_OBJECT_CLASS (intlclock_location_tile_parent_class)->finalize (g_obj); + } + ++static gboolean ++press_on_tile (GtkWidget *widget, ++ GdkEventButton *event, ++ IntlClockLocationTile *tile) ++{ ++ IntlClockLocationTilePrivate *priv = PRIVATE (tile); ++ ++ intlclock_blink_location (priv->clock, priv->location); ++ ++ return TRUE; ++} ++ ++static void ++make_current (GtkWidget *widget, IntlClockLocationTile *tile) ++{ ++ IntlClockLocationTilePrivate *priv = PRIVATE (tile); ++ GError *error = NULL; ++ GtkWidget *dialog; ++ ++ if (intlclock_location_make_current (priv->location, &error)) { ++ g_signal_emit_by_name (priv->clock, "current-timezone-changed", 0); ++ } ++ else if (error) { ++ dialog = gtk_message_dialog_new (NULL, ++ 0, ++ GTK_MESSAGE_ERROR, ++ GTK_BUTTONS_OK, ++ _("Failed to set the system timezone")); ++ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), error->message); ++ g_signal_connect (dialog, "response", ++ G_CALLBACK (gtk_widget_destroy), NULL); ++ gtk_window_present (GTK_WINDOW (dialog)); ++ ++ g_error_free (error); ++ } ++} ++ ++static gboolean ++enter_or_leave_tile (GtkWidget *widget, ++ GdkEventCrossing *event, ++ IntlClockLocationTile *tile) ++{ ++ IntlClockLocationTilePrivate *priv = PRIVATE (tile); ++ ++ if (event->type == GDK_ENTER_NOTIFY) { ++ gint can_set; ++ ++ can_set = can_set_system_timezone (); ++ if (!intlclock_location_is_current (priv->location) && ++ can_set != 0) { ++ gtk_label_set_markup (GTK_LABEL (priv->current_label), ++ can_set == 1 ? ++ _("Set...") : ++ _("Set")); ++ gtk_widget_show (priv->current_button); ++ } ++ } ++ else { ++ if (event->detail != GDK_NOTIFY_INFERIOR) ++ gtk_widget_hide (priv->current_button); ++ } ++ ++ return TRUE; ++} ++ + static void + intlclock_location_tile_fill (IntlClockLocationTile *this) + { + IntlClockLocationTilePrivate *priv = PRIVATE (this); ++ GtkWidget *align; ++ GtkWidget *strut; ++ GtkWidget *box; ++ ++ 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); ++ ++ GtkWidget *alignment = gtk_alignment_new (0, 0, 1, 0); ++ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 3, 3, 3, 0); + + GtkWidget *tile = gtk_hbox_new (FALSE, 6); + GtkWidget *head_section = gtk_vbox_new (FALSE, 0); +@@ -147,21 +252,55 @@ intlclock_location_tile_fill (IntlClockLocationTile *this) + 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); + +- gtk_box_pack_start (GTK_BOX (head_section), priv->city_label, +- FALSE, FALSE, 0); +- gtk_box_pack_start (GTK_BOX (head_section), priv->time_label, +- FALSE, FALSE, 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 (); ++ 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 as current timezone for this computer")); ++ ++ priv->current_marker = gtk_image_new_from_icon_name ("go-home", GTK_ICON_SIZE_BUTTON); ++ gtk_widget_set_no_show_all (priv->current_marker, TRUE); ++ ++ align = gtk_alignment_new (1, 1, 0, 0); ++ 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); ++ 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); ++ ++ g_signal_connect (priv->current_button, "clicked", ++ G_CALLBACK (make_current), this); + + priv->clock_face = intlclock_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, FALSE, FALSE, 0); ++ gtk_box_pack_start (GTK_BOX (tile), head_section, TRUE, TRUE, 0); + +- gtk_container_add (GTK_CONTAINER (this), tile); ++ gtk_container_add (GTK_CONTAINER (alignment), tile); ++ gtk_container_add (GTK_CONTAINER (priv->box), alignment); ++ gtk_container_add (GTK_CONTAINER (this), priv->box); + + intlclock_location_tile_refresh (this); + } +@@ -226,10 +365,25 @@ static void + intlclock_location_tile_refresh (IntlClockLocationTile *this) + { + IntlClockLocationTilePrivate *priv = PRIVATE (this); +- +- gchar *tmp, *tzname; ++ gchar *tmp, *tmp2, *tzname; + char buf[256]; + struct tm now; ++ long offset, hours, minutes; ++ ++ if (intlclock_location_is_current (priv->location)) { ++ if (!GTK_WIDGET_VISIBLE (priv->current_marker)) { ++ GdkPixbuf *pixbuf; ++ ++ pixbuf = gtk_image_get_pixbuf (GTK_IMAGE (priv->weather_icon)); ++ intlclock_ui_update_weather_icon (priv->ui, pixbuf); ++ } ++ ++ gtk_widget_hide (priv->current_button); ++ gtk_widget_show (priv->current_marker); ++ } ++ else { ++ gtk_widget_hide (priv->current_marker); ++ } + + if (intlclock_needs_face_refresh (this)) { + intlclock_face_refresh (INTLCLOCK_FACE (priv->clock_face)); +@@ -259,8 +413,22 @@ intlclock_location_tile_refresh (IntlClockLocationTile *this) + FALSE, TRUE, TRUE, tzname, TRUE); + } + +- gtk_label_set_markup (GTK_LABEL (priv->time_label), tmp); ++ offset = - intlclock_location_get_offset (priv->location); ++ hours = offset / 3600; ++ minutes = (offset % 3600) / 60; ++ ++ if (hours != 0 && minutes != 0) ++ tmp2 = g_strdup_printf ("%s %+d:%d", tmp, hours, minutes); ++ else if (hours != 0) ++ tmp2 = g_strdup_printf ("%s %+d", tmp, hours); ++ else { ++ tmp2 = tmp; ++ tmp = NULL; ++ } ++ ++ gtk_label_set_markup (GTK_LABEL (priv->time_label), tmp2); + g_free (tmp); ++ g_free (tmp2); + } + + static void +@@ -271,3 +439,87 @@ intlclock_location_tile_tick (IntlClock *clock, + + intlclock_location_tile_refresh (this); + } ++ ++static gboolean ++weather_tooltip (GtkWidget *widget, ++ gint x, ++ gint y, ++ gboolean keyboard_mode, ++ GtkTooltip *tooltip, ++ gpointer data) ++{ ++ IntlClockLocationTile *tile = data; ++ IntlClockLocationTilePrivate *priv = PRIVATE (tile); ++ WeatherInfo *info; ++ GdkPixbuf *pixbuf = NULL; ++ gchar *conditions, *temp, *apparent, *wind; ++ gchar *line1, *line2, *line3, *line4, *tip; ++ ++ info = intlclock_location_get_weather_info (priv->location); ++ ++ if (!info || !weather_info_is_valid (info)) ++ return FALSE; ++ ++ weather_info_get_pixbuf (info, &pixbuf); ++ 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)); ++ ++ temp = weather_info_get_temp (info); ++ apparent = weather_info_get_apparent (info); ++ if (strcmp (apparent, temp) != 0 && ++ /* FIXME libgweather needs some real api */ ++ strcmp (apparent, dgettext ("gnome-applets-2.0", "Unknown")) != 0) ++ line2 = g_strdup_printf (_("%s, feels like %s"), temp, apparent); ++ else ++ line2 = g_strdup (temp); ++ ++ wind = weather_info_get_wind (info); ++ if (strcmp (apparent, dgettext ("gnome-applets-2.0", "Unknown")) != 0) ++ line3 = g_strdup_printf ("%s\n", wind); ++ else ++ line3 = g_strdup (""); ++ ++ line4 = g_strdup_printf (_("Sunrise: %s / Sunset: %s"), ++ weather_info_get_sunrise (info), ++ weather_info_get_sunset (info)); ++ ++ 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); ++ ++ return TRUE; ++} ++ ++ ++static void ++update_weather_icon (IntlClockLocation *loc, WeatherInfo *info, gpointer data) ++{ ++ IntlClockLocationTile *tile = data; ++ IntlClockLocationTilePrivate *priv = PRIVATE (tile); ++ GdkPixbuf *pixbuf = NULL; ++ ++ if (!info || !weather_info_is_valid (info)) ++ return; ++ ++ weather_info_get_pixbuf_mini (info, &pixbuf); ++ ++ 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); ++ if (intlclock_location_is_current (loc)) ++ intlclock_ui_update_weather_icon (priv->ui, pixbuf); ++ } ++} ++ +diff --git a/src/intlclock-location.c b/src/intlclock-location.c +index 384b2aa..dbb8f75 100644 +--- a/src/intlclock-location.c ++++ b/src/intlclock-location.c +@@ -1,4 +1,3 @@ +-#include "intlclock-location.h" + + #ifdef HAVE_CONFIG_H + #include +@@ -13,9 +12,21 @@ + #include + #include + #include ++#include + + #include + #include ++#include ++ ++#include ++#include ++#include ++ ++ ++#include "intlclock-location.h" ++#include "intlclock-marshallers.h" ++#include "set-timezone.h" ++#include "gweather-xml.h" + + G_DEFINE_TYPE (IntlClockLocation, intlclock_location, G_TYPE_OBJECT) + +@@ -29,17 +40,33 @@ typedef struct { + + gfloat latitude; + gfloat longitude; ++ ++ gchar *weather_code; ++ WeatherInfo *weather_info; ++ guint weather_timeout; ++ + } IntlClockLocationPrivate; + ++enum { ++ WEATHER_UPDATED, ++ LAST_SIGNAL ++}; ++ ++static guint location_signals[LAST_SIGNAL] = { 0 }; ++ + static void intlclock_location_finalize (GObject *); + static void intlclock_location_set_tz (IntlClockLocation *this); + static void intlclock_location_unset_tz (IntlClockLocation *this); ++static void setup_weather_updates (IntlClockLocation *loc); ++static void add_to_network_monitor (IntlClockLocation *loc); ++static void remove_from_network_monitor (IntlClockLocation *loc); + + #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INTLCLOCK_LOCATION_TYPE, IntlClockLocationPrivate)) + + IntlClockLocation * + intlclock_location_new (const gchar *name, const gchar *timezone, +- gfloat latitude, gfloat longitude) ++ gfloat latitude, gfloat longitude, ++ const gchar *code) + { + IntlClockLocation *this; + IntlClockLocationPrivate *priv; +@@ -62,6 +89,9 @@ intlclock_location_new (const gchar *name, const gchar *timezone, + priv->latitude = latitude; + priv->longitude = longitude; + ++ priv->weather_code = g_strdup (code); ++ setup_weather_updates (this); ++ + return this; + } + +@@ -193,6 +223,77 @@ guess_zone_from_tree (const gchar *localtime, IntlClockZoneTable *zones) + return ret; + } + ++static const gchar *current_zone = NULL; ++static GnomeVFSMonitorHandle *monitor = NULL; ++ ++static void ++parse_etc_sysconfig_clock (void) ++{ ++ gchar *data; ++ gsize len; ++ gchar **lines; ++ gchar *res; ++ gint i; ++ gchar *p, *q; ++ ++ lines = NULL; ++ res = NULL; ++ if (g_file_test ("/etc/sysconfig/clock", ++ G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { ++ if (!g_file_get_contents ("/etc/sysconfig/clock", ++ &data, &len, NULL)) ++ goto out; ++ ++ lines = g_strsplit (data, "\n", 0); ++ g_free (data); ++ ++ for (i = 0; lines[i] && !res; i++) { ++ if (g_str_has_prefix (lines[i], "ZONE=")) { ++ p = lines[i] + strlen ("ZONE="); ++ if (p[0] != '\"') ++ goto out; ++ p++; ++ q = strchr (p, '\"'); ++ q[0] = '\0'; ++ res = g_strdup (p); ++ } ++ } ++ } ++ ++out: ++ if (lines) ++ g_strfreev (lines); ++ ++ g_free (current_zone); ++ current_zone = res; ++} ++ ++static void ++monitor_etc_sysconfig_clock (GnomeVFSMonitorHandle *handle, ++ const gchar *monitor_uri, ++ const gchar *info_uri, ++ GnomeVFSMonitorEventType event_type, ++ gpointer user_data) ++{ ++ parse_etc_sysconfig_clock (); ++} ++ ++static const gchar * ++zone_from_etc_sysconfig_clock (void) ++{ ++ if (monitor == NULL) { ++ parse_etc_sysconfig_clock (); ++ ++ gnome_vfs_monitor_add (&monitor, ++ "/etc/sysconfig/clock", ++ GNOME_VFS_MONITOR_FILE, ++ monitor_etc_sysconfig_clock, ++ NULL); ++ } ++ ++ return current_zone; ++} ++ + static gchar * + intlclock_location_guess_zone (IntlClockZoneTable *zones) + { +@@ -200,6 +301,12 @@ intlclock_location_guess_zone (IntlClockZoneTable *zones) + const char *localtime = "/etc/localtime"; + gchar *linkfile = NULL; + GError *err = NULL; ++ gchar *zone; ++ ++ /* look for /etc/sysconfig/clock */ ++ if ((zone = zone_from_etc_sysconfig_clock ())) { ++ return g_strdup (zone); ++ } + + /* guess the current time zone by readlink() on /etc/localtime */ + linkfile = g_file_read_link (localtime, &err); +@@ -235,14 +342,14 @@ intlclock_location_new_from_env (IntlClockZoneTable *zones) + + if (zone == NULL) { + /* make a fake location with a null TZ */ +- return intlclock_location_new (_("Unknown Location"), NULL, 0.0, 0.0); ++ return intlclock_location_new (_("Unknown Location"), NULL, 0.0, 0.0, NULL); + } + + info = intlclock_zonetable_get_zone (zones, zone); + + if (info == NULL) { + /* make a fake location with the current TZ */ +- return intlclock_location_new (_("Unknown Location"), zone, 0.0, 0.0); ++ return intlclock_location_new (_("Unknown Location"), zone, 0.0, 0.0, NULL); + } + + g_free (zone); +@@ -260,7 +367,7 @@ intlclock_location_new_from_env (IntlClockZoneTable *zones) + } + + ret = intlclock_location_new (name, intlclock_zoneinfo_get_name (info), +- lat, lon); ++ lat, lon, NULL); + + g_free (name); + +@@ -274,6 +381,15 @@ intlclock_location_class_init (IntlClockLocationClass *this_class) + + g_obj_class->finalize = intlclock_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 (IntlClockLocationClass, weather_updated), ++ NULL, NULL, ++ _intlclock_marshal_VOID__POINTER, ++ G_TYPE_NONE, 1, G_TYPE_POINTER); ++ + g_type_class_add_private (this_class, sizeof (IntlClockLocationPrivate)); + } + +@@ -297,6 +413,8 @@ static void + intlclock_location_finalize (GObject *g_obj) + { + IntlClockLocationPrivate *priv = PRIVATE (g_obj); ++ ++ remove_from_network_monitor (INTLCLOCK_LOCATION (g_obj)); + + if (priv->name) { + g_free (priv->name); +@@ -318,6 +436,21 @@ intlclock_location_finalize (GObject *g_obj) + 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 (intlclock_location_parent_class)->finalize (g_obj); + } + +@@ -467,3 +600,266 @@ intlclock_location_localtime (IntlClockLocation *loc, struct tm *tm) + + intlclock_location_unset_tz (loc); + } ++ ++gboolean ++intlclock_location_is_current (IntlClockLocation *loc) ++{ ++ IntlClockLocationPrivate *priv = PRIVATE (loc); ++ const char *zone; ++ ++ if ((zone = zone_from_etc_sysconfig_clock ())) ++ return strcmp (zone, priv->timezone) == 0; ++ ++ return intlclock_location_get_offset (loc) == 0; ++} ++ ++ ++glong ++intlclock_location_get_offset (IntlClockLocation *loc) ++{ ++ IntlClockLocationPrivate *priv = PRIVATE (loc); ++ glong sys_timezone; ++ glong offset; ++ ++ unsetenv ("TZ"); ++ tzset (); ++ sys_timezone = timezone; ++ ++ setenv ("TZ", priv->timezone, 1); ++ tzset(); ++ ++ offset = timezone - sys_timezone; ++ ++ if (priv->sys_timezone) { ++ setenv ("TZ", priv->sys_timezone, 1); ++ } else { ++ unsetenv ("TZ"); ++ } ++ tzset(); ++ ++ return offset; ++} ++ ++gboolean ++intlclock_location_make_current (IntlClockLocation *loc, GError **error) ++{ ++ IntlClockLocationPrivate *priv = PRIVATE (loc); ++ gchar *filename; ++ gboolean ret; ++ ++ filename = g_build_filename (SYSTEM_ZONEINFODIR, priv->timezone, NULL); ++ ret = set_system_timezone (filename, error); ++ g_free (filename); ++ ++ if (ret) { ++ /* FIXME this ugly shortcut is necessary until we move the ++ * current timezone tracking to intlclock.c and emit the ++ * signal from there ++ */ ++ g_free (current_zone); ++ current_zone = g_strdup (priv->timezone); ++ } ++ ++ return ret; ++} ++ ++const gchar * ++intlclock_location_get_weather_code (IntlClockLocation *loc) ++{ ++ IntlClockLocationPrivate *priv = PRIVATE (loc); ++ ++ return priv->weather_code; ++} ++ ++void ++intlclock_location_set_weather_code (IntlClockLocation *loc, const gchar *code) ++{ ++ IntlClockLocationPrivate *priv = PRIVATE (loc); ++ ++ g_free (priv->weather_code); ++ priv->weather_code = g_strdup (code); ++ ++ setup_weather_updates (loc); ++} ++ ++WeatherInfo * ++intlclock_location_get_weather_info (IntlClockLocation *loc) ++{ ++ IntlClockLocationPrivate *priv = PRIVATE (loc); ++ ++ return priv->weather_info; ++} ++ ++static void ++weather_info_updated (WeatherInfo *info, gpointer data) ++{ ++ IntlClockLocation *loc = data; ++ IntlClockLocationPrivate *priv = PRIVATE (loc); ++ ++ g_signal_emit (loc, location_signals[WEATHER_UPDATED], ++ 0, priv->weather_info); ++} ++ ++static gboolean ++update_weather_info (gpointer data) ++{ ++ IntlClockLocation *loc = data; ++ IntlClockLocationPrivate *priv = PRIVATE (loc); ++ WeatherPrefs prefs = { ++ FORECAST_STATE, ++ FALSE, ++ NULL, ++ TEMP_UNIT_CENTIGRADE, ++ SPEED_UNIT_MS, ++ PRESSURE_UNIT_MB, ++ DISTANCE_UNIT_KM ++ }; ++ ++ 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) { ++ update_weather_info (l->data); ++ } ++} ++ ++static DBusHandlerResult ++filter_func (DBusConnection *connection, ++ DBusMessage *message, ++ void *user_data) ++{ ++ guint32 state = NM_DEVICE_STATE_UNKNOWN; ++ ++ if (dbus_message_is_signal (message, ++ NM_DBUS_INTERFACE_DEVICE, "StateChanged")) { ++ dbus_message_get_args (message, NULL, ++ DBUS_TYPE_UINT32, &state, ++ DBUS_TYPE_INVALID); ++ if (state == NM_DEVICE_STATE_ACTIVATED) { ++ update_weather_infos (); ++ } ++ ++ return DBUS_HANDLER_RESULT_HANDLED; ++ } ++ ++ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; ++} ++ ++static void ++setup_network_monitor (void) ++{ ++ GError *error; ++ 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 = 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_DEVICE "'", ++ NULL); ++ } ++} ++ ++static void ++add_to_network_monitor (IntlClockLocation *loc) ++{ ++ setup_network_monitor (); ++ ++ if (!g_list_find (locations, loc)) ++ locations = g_list_prepend (locations, loc); ++} ++ ++static void ++remove_from_network_monitor (IntlClockLocation *loc) ++{ ++ locations = g_list_remove (locations, loc); ++} ++ ++static void ++setup_weather_updates (IntlClockLocation *loc) ++{ ++ IntlClockLocationPrivate *priv = PRIVATE (loc); ++ const gchar *code; ++ WeatherLocation *wl; ++ WeatherPrefs prefs = { ++ FORECAST_STATE, ++ FALSE, ++ NULL, ++ TEMP_UNIT_CENTIGRADE, ++ SPEED_UNIT_MS, ++ PRESSURE_UNIT_MB, ++ DISTANCE_UNIT_KM ++ }; ++ gfloat lat, lon; ++ gchar *dms; ++ ++ 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, "-") == 0) ++ return; ++ ++ dms = rad2dms (priv->latitude, priv->longitude); ++ wl = weather_location_new (priv->name, priv->weather_code, ++ NULL, NULL, dms); ++ ++ priv->weather_info = ++ weather_info_new (wl, &prefs, weather_info_updated, loc); ++ ++ priv->weather_timeout = ++ g_timeout_add_seconds (1800, update_weather_info, loc); ++ ++ weather_location_free (wl); ++ g_free (dms); ++ ++ add_to_network_monitor (loc); ++} ++ +diff --git a/src/intlclock-location.h b/src/intlclock-location.h +index 824ee3c..a711ac5 100644 +--- a/src/intlclock-location.h ++++ b/src/intlclock-location.h +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + + #include "intlclock-zonetable.h" + +@@ -24,12 +25,16 @@ typedef struct + typedef struct + { + GObjectClass g_object_class; ++ ++ void (* weather_updated) (IntlClockLocation *location, WeatherInfo *info); ++ + } IntlClockLocationClass; + + GType intlclock_location_get_type (void); + + IntlClockLocation *intlclock_location_new (const gchar *name, const gchar *timezone, +- gfloat latitude, gfloat longitude); ++ gfloat latitude, gfloat longitude, ++ const gchar *code); + + IntlClockLocation *intlclock_location_new_from_env (IntlClockZoneTable *zones); + +@@ -46,5 +51,14 @@ void intlclock_location_set_coords (IntlClockLocation *loc, gfloat latitude, gfl + + void intlclock_location_localtime (IntlClockLocation *loc, struct tm *tm); + ++gboolean intlclock_location_is_current (IntlClockLocation *loc); ++gboolean intlclock_location_make_current (IntlClockLocation *loc, GError **error); ++ ++const gchar *intlclock_location_get_weather_code (IntlClockLocation *loc); ++void intlclock_location_set_weather_code (IntlClockLocation *loc, const gchar *code); ++WeatherInfo *intlclock_location_get_weather_info (IntlClockLocation *loc); ++ ++glong intlclock_location_get_offset (IntlClockLocation *loc); ++ + G_END_DECLS + #endif /* __INTLCLOCK_LOCATION_H__ */ +diff --git a/src/intlclock-map.c b/src/intlclock-map.c +index 2d72975..9ded127 100644 +--- a/src/intlclock-map.c ++++ b/src/intlclock-map.c +@@ -25,7 +25,7 @@ typedef struct { + gint height; + + GdkPixbuf *stock_map_pixbuf; +- GdkPixbuf *location_marker_pixbuf; ++ GdkPixbuf *location_marker_pixbuf[3]; + + GdkPixbuf *location_map_pixbuf; + +@@ -54,6 +54,7 @@ static void intlclock_map_display (IntlClockMap *this); + + + static void intlclock_map_locations_changed (IntlClock *clock, IntlClockMap *this); ++static void intlclock_map_blink_location (IntlClock *clock, IntlClockLocation *loc, IntlClockMap *this); + static void intlclock_map_tick (IntlClock *clock, IntlClockMap *this); + + #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), INTLCLOCK_MAP_TYPE, IntlClockMapPrivate)) +@@ -69,8 +70,12 @@ intlclock_map_new (IntlClock *clock) + + priv->clock = g_object_ref (clock); + +- priv->location_marker_pixbuf = rsvg_pixbuf_from_file +- (INTLCLOCK_ICONDIR "/intlclock-map-location-marker.svg", NULL); ++ priv->location_marker_pixbuf[0] = gdk_pixbuf_new_from_file ++ (INTLCLOCK_ICONDIR "/intlclock-map-location-marker.png", NULL); ++ priv->location_marker_pixbuf[1] = gdk_pixbuf_new_from_file ++ (INTLCLOCK_ICONDIR "/intlclock-map-location-hilight.png", NULL); ++ priv->location_marker_pixbuf[2] = gdk_pixbuf_new_from_file ++ (INTLCLOCK_ICONDIR "/intlclock-map-location-current.png", NULL); + + g_signal_connect (G_OBJECT (priv->clock), "tick", + G_CALLBACK (intlclock_map_tick), this); +@@ -78,6 +83,12 @@ intlclock_map_new (IntlClock *clock) + g_signal_connect (G_OBJECT (priv->clock), "locations_changed", + G_CALLBACK (intlclock_map_locations_changed), this); + ++ g_signal_connect (G_OBJECT (priv->clock), "current_timezone_changed", ++ G_CALLBACK (intlclock_map_locations_changed), this); ++ ++ g_signal_connect (G_OBJECT (priv->clock), "blink_location", ++ G_CALLBACK (intlclock_map_blink_location), this); ++ + intlclock_map_refresh (this); + + return this; +@@ -109,13 +120,16 @@ intlclock_map_init (IntlClockMap *this) + priv->clock = NULL; + + priv->stock_map_pixbuf = NULL; +- priv->location_marker_pixbuf = NULL; ++ priv->location_marker_pixbuf[0] = NULL; ++ priv->location_marker_pixbuf[1] = NULL; ++ priv->location_marker_pixbuf[2] = NULL; + } + + static void + intlclock_map_finalize (GObject *g_obj) + { + IntlClockMapPrivate *priv = PRIVATE (g_obj); ++ int i; + + g_signal_handlers_disconnect_by_func + (priv->clock, G_CALLBACK (intlclock_map_tick), g_obj); +@@ -130,10 +144,12 @@ intlclock_map_finalize (GObject *g_obj) + priv->stock_map_pixbuf = NULL; + } + +- if (priv->location_marker_pixbuf) { +- gdk_pixbuf_unref (priv->location_marker_pixbuf); +- priv->location_marker_pixbuf = NULL; +- } ++ for (i = 0; i < 3; i++) { ++ if (priv->location_marker_pixbuf[i]) { ++ gdk_pixbuf_unref (priv->location_marker_pixbuf[i]); ++ priv->location_marker_pixbuf[i] = NULL; ++ } ++ } + + if (priv->location_map_pixbuf) { + gdk_pixbuf_unref (priv->location_map_pixbuf); +@@ -164,12 +180,13 @@ intlclock_map_refresh (IntlClockMap *this) + IntlClockMapPrivate *priv = PRIVATE (this); + GtkWidget *widget = GTK_WIDGET (this); + GtkWidget *parent = gtk_widget_get_parent (widget); ++ GtkRequisition req; + gint width; + gint height; + +- gtk_widget_size_request (widget, &(widget->requisition)); +- width = widget->requisition.width; +- height = widget->requisition.height; ++ gtk_widget_size_request (widget, &req); ++ width = req.width; ++ height = req.height; + + if (parent) { + if (widget->allocation.width != 1) { +@@ -276,10 +293,10 @@ intlclock_map_size_allocate (GtkWidget *this, GtkAllocation *allocation) + } + + static void +-intlclock_map_mark (IntlClockMap *this, gfloat latitude, gfloat longitude) ++intlclock_map_mark (IntlClockMap *this, gfloat latitude, gfloat longitude, gint mark) + { + IntlClockMapPrivate *priv = PRIVATE (this); +- GdkPixbuf *marker = priv->location_marker_pixbuf; ++ GdkPixbuf *marker = priv->location_marker_pixbuf[mark]; + GdkPixbuf *partial = NULL; + + int x, y; +@@ -395,14 +412,22 @@ intlclock_map_mark (IntlClockMap *this, gfloat latitude, gfloat longitude) + } + + static void +-intlclock_map_place_location (IntlClockMap *this, IntlClockLocation *loc) ++intlclock_map_place_location (IntlClockMap *this, IntlClockLocation *loc, gboolean hilight) + { + IntlClockMapPrivate *priv = PRIVATE (this); + gfloat latitude, longitude; ++ gint marker; + + intlclock_location_get_coords (loc, &latitude, &longitude); + +- intlclock_map_mark (this, latitude, longitude); ++ if (hilight) ++ marker = 1; ++ else if (intlclock_location_is_current (loc)) ++ marker = 2; ++ else ++ marker = 0; ++ ++ intlclock_map_mark (this, latitude, longitude, marker); + } + + static void +@@ -428,7 +453,7 @@ intlclock_map_place_locations (IntlClockMap *this) + while (locs) { + loc = INTLCLOCK_LOCATION (locs->data); + +- intlclock_map_place_location (this, loc); ++ intlclock_map_place_location (this, loc, FALSE); + + locs = locs->next; + } +@@ -633,16 +658,12 @@ intlclock_map_rotate (IntlClockMap *this) + static void + intlclock_map_display (IntlClockMap *this) + { +- IntlClockMapPrivate *priv = PRIVATE (this); +- + gtk_widget_queue_draw (GTK_WIDGET (this)); + } + + static void + intlclock_map_locations_changed (IntlClock *clock, IntlClockMap *this) + { +- IntlClockMapPrivate *priv = PRIVATE (this); +- + intlclock_map_place_locations (this); + + intlclock_map_render_shadow (this); +@@ -651,6 +672,49 @@ intlclock_map_locations_changed (IntlClock *clock, IntlClockMap *this) + intlclock_map_display (this); + } + ++typedef struct { ++ IntlClockMap *map; ++ IntlClockLocation *location; ++ int count; ++} BlinkData; ++ ++static gboolean ++highlight (gpointer user_data) ++{ ++ BlinkData *data = user_data; ++ ++ if (data->count == 6) { ++ g_free (data); ++ return FALSE; ++ } ++ ++ if (data->count % 2 == 0) ++ intlclock_map_place_location (data->map, data->location, TRUE); ++ else ++ intlclock_map_place_locations (data->map); ++ intlclock_map_render_shadow (data->map); ++ intlclock_map_rotate (data->map); ++ intlclock_map_display (data->map); ++ ++ data->count++; ++ ++ return TRUE; ++} ++ ++static void ++intlclock_map_blink_location (IntlClock *clock, IntlClockLocation *loc, IntlClockMap *this) ++{ ++ BlinkData *data; ++ ++ data = g_new0 (BlinkData, 1); ++ data->map = this; ++ data->location = loc; ++ ++ highlight (data); ++ ++ g_timeout_add (300, highlight, data); ++} ++ + static gboolean + intlclock_map_needs_refresh (IntlClockMap *this) + { +diff --git a/src/intlclock-marshallers.c b/src/intlclock-marshallers.c +deleted file mode 100644 +index 8f01ab8..0000000 +--- a/src/intlclock-marshallers.c ++++ /dev/null +@@ -1,51 +0,0 @@ +- +-#include +- +- +-#ifdef G_ENABLE_DEBUG +-#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) +-#define g_marshal_value_peek_char(v) g_value_get_char (v) +-#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) +-#define g_marshal_value_peek_int(v) g_value_get_int (v) +-#define g_marshal_value_peek_uint(v) g_value_get_uint (v) +-#define g_marshal_value_peek_long(v) g_value_get_long (v) +-#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) +-#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) +-#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) +-#define g_marshal_value_peek_enum(v) g_value_get_enum (v) +-#define g_marshal_value_peek_flags(v) g_value_get_flags (v) +-#define g_marshal_value_peek_float(v) g_value_get_float (v) +-#define g_marshal_value_peek_double(v) g_value_get_double (v) +-#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) +-#define g_marshal_value_peek_param(v) g_value_get_param (v) +-#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) +-#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) +-#define g_marshal_value_peek_object(v) g_value_get_object (v) +-#else /* !G_ENABLE_DEBUG */ +-/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. +- * Do not access GValues directly in your code. Instead, use the +- * g_value_get_*() functions +- */ +-#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int +-#define g_marshal_value_peek_char(v) (v)->data[0].v_int +-#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint +-#define g_marshal_value_peek_int(v) (v)->data[0].v_int +-#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint +-#define g_marshal_value_peek_long(v) (v)->data[0].v_long +-#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong +-#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 +-#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 +-#define g_marshal_value_peek_enum(v) (v)->data[0].v_long +-#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong +-#define g_marshal_value_peek_float(v) (v)->data[0].v_float +-#define g_marshal_value_peek_double(v) (v)->data[0].v_double +-#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer +-#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer +-#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer +-#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer +-#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer +-#endif /* !G_ENABLE_DEBUG */ +- +- +-/* VOID:VOID (intlclock-marshallers.list:1) */ +- +diff --git a/src/intlclock-marshallers.h b/src/intlclock-marshallers.h +deleted file mode 100644 +index c022a3e..0000000 +--- a/src/intlclock-marshallers.h ++++ /dev/null +@@ -1,15 +0,0 @@ +- +-#ifndef ___intlclock_marshal_MARSHAL_H__ +-#define ___intlclock_marshal_MARSHAL_H__ +- +-#include +- +-G_BEGIN_DECLS +- +-/* VOID:VOID (intlclock-marshallers.list:1) */ +-#define _intlclock_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID +- +-G_END_DECLS +- +-#endif /* ___intlclock_marshal_MARSHAL_H__ */ +- +diff --git a/src/intlclock-marshallers.list b/src/intlclock-marshallers.list +index 5b76282..e737cac 100644 +--- a/src/intlclock-marshallers.list ++++ b/src/intlclock-marshallers.list +@@ -1 +1,3 @@ + VOID:VOID ++VOID:OBJECT ++VOID:POINTER +diff --git a/src/intlclock-sunpos.c b/src/intlclock-sunpos.c +index 942617b..89d4cc1 100644 +--- a/src/intlclock-sunpos.c ++++ b/src/intlclock-sunpos.c +@@ -1,348 +1,196 @@ + /* +- * sunpos.c +- * kirk johnson +- * july 1993 ++ * Copyright (C) 2007 Red Hat, Inc. + * +- * includes revisions from Frank T. Solensky, february 1999 ++ * 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. + * +- * code for calculating the position on the earth's surface for which +- * the sun is directly overhead (adapted from _practical astronomy +- * with your calculator, third edition_, peter duffett-smith, +- * cambridge university press, 1988.) ++ * 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. + * +- * Copyright (C) 1989, 1990, 1993-1995, 1999 Kirk Lauritz Johnson ++ * 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. + * +- * Parts of the source code (as marked) are: +- * Copyright (C) 1989, 1990, 1991 by Jim Frost +- * Copyright (C) 1992 by Jamie Zawinski +- * +- * Permission to use, copy, modify and freely distribute xearth for +- * non-commercial and not-for-profit purposes is hereby granted +- * without fee, provided that both the above copyright notice and this +- * permission notice appear in all copies and in supporting +- * documentation. +- * +- * Unisys Corporation holds worldwide patent rights on the Lempel Zev +- * Welch (LZW) compression technique employed in the CompuServe GIF +- * image file format as well as in other formats. Unisys has made it +- * clear, however, that it does not require licensing or fees to be +- * paid for freely distributed, non-commercial applications (such as +- * xearth) that employ LZW/GIF technology. Those wishing further +- * information about licensing the LZW patent should contact Unisys +- * directly at (lzw_info@unisys.com) or by writing to +- * +- * Unisys Corporation +- * Welch Licensing Department +- * M/S-C1SW19 +- * P.O. Box 500 +- * Blue Bell, PA 19424 +- * +- * The author makes no representations about the suitability of this +- * software for any purpose. It is provided "as is" without express or +- * implied warranty. +- * +- * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT +- * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ * Authors: ++ * Jonathan Blandford ++ * Matthias Clasen + */ +- +-#include +-#include ++ + #include ++#include ++#include + +-#include "intlclock-sunpos.h" +- +-#define TWOPI (2*M_PI) +-#define DegsToRads(x) ((x)*(TWOPI/360)) +- +-/* +- * the epoch upon which these astronomical calculations are based is +- * 1990 january 0.0, 631065600 seconds since the beginning of the +- * "unix epoch" (00:00:00 GMT, Jan. 1, 1970) +- * +- * given a number of seconds since the start of the unix epoch, +- * DaysSinceEpoch() computes the number of days since the start of the +- * astronomical epoch (1990 january 0.0) +- */ +- +-#define EpochStart (631065600) +-#define DaysSinceEpoch(secs) (((secs)-EpochStart)*(1.0/(24*3600))) +- +-/* +- * assuming the apparent orbit of the sun about the earth is circular, +- * the rate at which the orbit progresses is given by RadsPerDay -- +- * TWOPI radians per orbit divided by 365.242191 days per year: +- */ +- +-#define RadsPerDay (TWOPI/365.242191) +- +-/* +- * details of sun's apparent orbit at epoch 1990.0 (after +- * duffett-smith, table 6, section 46) +- * +- * Epsilon_g (ecliptic longitude at epoch 1990.0) 279.403303 degrees +- * OmegaBar_g (ecliptic longitude of perigee) 282.768422 degrees +- * Eccentricity (eccentricity of orbit) 0.016713 ++/* 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 orbit at epoch 1990.0 */ + +-#define Epsilon_g (DegsToRads(279.403303)) +-#define OmegaBar_g (DegsToRads(282.768422)) +-#define Eccentricity (0.016713) ++#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 perigree */ ++#define ECCENTRICITY 0.016713 /* eccentricity of orbit */ ++#define R_0 149598500 /* km */ /* semi-major access */ ++#define THETA_0 0.533128 /* degrees */ /* angular diameter at r = r_0 */ ++#define MEAN_OBLIQUITY 23.440592 /* degrees */ /* mean obliquity of earths axis at epoch 1990.0 */ + +-/* +- * MeanObliquity gives the mean obliquity of the earth's axis at epoch +- * 1990.0 (computed as 23.440592 degrees according to the method given +- * in duffett-smith, section 27) +- */ +-#define MeanObliquity (23.440592*(TWOPI/360)) ++#define NORMALIZE(x) \ ++ while (x>360) x-=360; while (x<0) x+= 360; + +-/* +- * Lunar parameters, epoch January 0, 1990.0 +- */ +-#define MoonMeanLongitude DegsToRads(318.351648) +-#define MoonMeanLongitudePerigee DegsToRads( 36.340410) +-#define MoonMeanLongitudeNode DegsToRads(318.510107) +-#define MoonInclination DegsToRads( 5.145396) ++#define DEG_TO_RADS(x) \ ++ (x * G_PI/180.0) + +-#define SideralMonth (27.3217) ++#define RADS_TO_DEG(x) \ ++ (x * 180.0/G_PI) + +-/* +- * Force an angular value into the range [-PI, +PI] ++/* Calculate number of days since 4713BC. + */ +-#define Normalize(x) \ +- do { \ +- if ((x) < -M_PI) \ +- do (x) += TWOPI; while ((x) < -M_PI); \ +- else if ((x) > M_PI) \ +- do (x) -= TWOPI; while ((x) > M_PI); \ +- } while (0) +- +-static double solve_keplers_equation (double); +-static double mean_sun (double); +-static double sun_ecliptic_longitude (time_t); +-static void ecliptic_to_equatorial (double, double, double *, double *); +-static double julian_date (int, int, int); +-static double GST (time_t); +- +-/* +- * solve Kepler's equation via Newton's method +- * (after duffett-smith, section 47) +- */ +-static double solve_keplers_equation(M) +- double M; ++static gdouble ++unix_time_to_julian_date (gint unix_time) + { +- double E; +- double delta; +- +- E = M; +- while (1) +- { +- delta = E - Eccentricity*sin(E) - M; +- if (fabs(delta) <= 1e-10) break; +- E -= delta / (1 - Eccentricity*cos(E)); +- } +- +- return E; ++ 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 */ + +-/* +- * Calculate the position of the mean sun: where the sun would +- * be if the earth's orbit were circular instead of ellipictal. +- */ ++#define ERROR_ACCURACY 1e-6 /* radians */ + +-static double mean_sun (D) +- double D; /* days since ephemeris epoch */ ++static gdouble ++solve_keplers_equation (gdouble e, ++ gdouble M) + { +- double N, M; ++ gdouble d, E; + +- N = RadsPerDay * D; +- N = fmod(N, TWOPI); +- if (N < 0) N += TWOPI; ++ /* 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; ++ } + +- M = N + Epsilon_g - OmegaBar_g; +- if (M < 0) M += TWOPI; +- return M; ++ return E; + } + +-/* +- * compute ecliptic longitude of sun (in radians) +- * (after duffett-smith, section 47) +- */ +-static double sun_ecliptic_longitude(ssue) +- time_t ssue; /* seconds since unix epoch */ ++ /* convert the ecliptic longitude to right ascension and declination. Section 27. */ ++static void ++ecliptic_to_equatorial (gdouble lambda, ++ gdouble beta, ++ gdouble *ra, ++ gdouble *dec) + { +- double D; +- double M_sun, E; +- double v; ++ gdouble cos_mo; ++ gdouble sin_mo; + +- D = DaysSinceEpoch(ssue); +- M_sun = mean_sun(D); ++ g_assert (ra != NULL); ++ g_assert (dec != NULL); + +- E = solve_keplers_equation(M_sun); +- v = 2 * atan(sqrt((1+Eccentricity)/(1-Eccentricity)) * tan(E/2)); ++ sin_mo = sin (DEG_TO_RADS (MEAN_OBLIQUITY)); ++ cos_mo = cos (DEG_TO_RADS (MEAN_OBLIQUITY)); + +- return (v + OmegaBar_g); ++ *ra = atan2 (sin (lambda) * cos_mo - tan (beta) * sin_mo, cos (lambda)); ++ *dec = asin (sin (beta) * cos_mo + cos (beta) * sin_mo * sin (lambda)); + } + +- +-/* +- * convert from ecliptic to equatorial coordinates +- * (after duffett-smith, section 27) +- */ +-static void ecliptic_to_equatorial(lambda, beta, alpha, delta) +- double lambda; /* ecliptic longitude */ +- double beta; /* ecliptic latitude */ +- double *alpha; /* (return) right ascension */ +- double *delta; /* (return) declination */ ++/* calculate GST. Section 12 */ ++static gdouble ++greenwich_sidereal_time (gdouble unix_time) + { +- double sin_e, cos_e; ++ gdouble u, JD, T, T0, UT; + +- sin_e = sin(MeanObliquity); +- cos_e = cos(MeanObliquity); ++ 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); + +- *alpha = atan2(sin(lambda)*cos_e - tan(beta)*sin_e, cos(lambda)); +- *delta = asin(sin(beta)*cos_e + cos(beta)*sin_e*sin(lambda)); ++ return T0; + } + +- +-/* +- * computing julian dates (assuming gregorian calendar, thus this is +- * only valid for dates of 1582 oct 15 or later) +- * (after duffett-smith, section 4) +- */ +-static double julian_date(y, m, d) +- int y; /* year (e.g. 19xx) */ +- int m; /* month (jan=1, feb=2, ...) */ +- int d; /* day of month */ ++/* Calculate the position of the sun at a given time. pages 89-91 */ ++void ++sun_position (gint unix_time, gdouble *lat, gdouble *lon) + { +- int A, B, C, D; +- double JD; ++ gdouble jd, D, N, M, E, x, v, lambda; ++ gdouble ra, dec; ++ jd = unix_time_to_julian_date (unix_time); + +- /* lazy test to ensure gregorian calendar */ +- assert(y >= 1583); ++ /* Calculate number of days since the epoch */ ++ D = jd - EPOCH; + +- if ((m == 1) || (m == 2)) +- { +- y -= 1; +- m += 12; +- } ++ N = D*360/365.242191; + +- A = y / 100; +- B = 2 - A + (A / 4); +- C = 365.25 * y; +- D = 30.6001 * (m + 1); ++ /* normalize to 0 - 360 degrees */ ++ NORMALIZE (N); + +- JD = B + C + D + d + 1720994.5; ++ /* Step 4: */ ++ M = N + EPSILON_G - MU_G; ++ NORMALIZE (M); + +- return JD; +-} +- +- +-/* +- * compute greenwich mean sidereal time (GST) corresponding to a given +- * number of seconds since the unix epoch +- * (after duffett-smith, section 12) +- */ +-static double GST(ssue) +- time_t ssue; /* seconds since unix epoch */ +-{ +- double JD; +- double T, T0; +- double UT; +- struct tm *tm; ++ /* Step 5: convert to radians */ ++ M = DEG_TO_RADS (M); + +- tm = gmtime(&ssue); ++ /* Step 6: */ ++ E = solve_keplers_equation (ECCENTRICITY, M); + +- JD = julian_date(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday); +- T = (JD - 2451545) / 36525; ++ /* Step 7: */ ++ x = sqrt ((1 + ECCENTRICITY)/(1 - ECCENTRICITY)) * tan (E/2); + +- T0 = ((T + 2.5862e-5) * T + 2400.051336) * T + 6.697374558; ++ /* Step 8, 9 */ ++ v = 2 * RADS_TO_DEG (atan (x)); ++ NORMALIZE (v); + +- T0 = fmod(T0, 24.0); +- if (T0 < 0) T0 += 24; ++ /* Step 10 */ ++ lambda = v + MU_G; ++ NORMALIZE (lambda); + +- UT = tm->tm_hour + (tm->tm_min + tm->tm_sec / 60.0) / 60.0; ++ /* convert the ecliptic longitude to right ascension and declination */ ++ ecliptic_to_equatorial (DEG_TO_RADS (lambda), 0.0, &ra, &dec); + +- T0 += UT * 1.002737909; +- T0 = fmod(T0, 24.0); +- if (T0 < 0) T0 += 24; ++ ra = ra - (G_PI/12) * greenwich_sidereal_time (unix_time); ++ ra = RADS_TO_DEG (ra); ++ dec = RADS_TO_DEG (dec); ++ NORMALIZE (ra); ++ NORMALIZE (dec); + +- return T0; ++ *lat = dec; ++ *lon = ra; + } + + +-/* +- * given a particular time (expressed in seconds since the unix +- * epoch), compute position on the earth (lat, lon) such that sun is +- * directly overhead. +- */ +-void sun_position(ssue, lat, lon) +- time_t ssue; /* seconds since unix epoch */ +- double *lat; /* (return) latitude */ +- double *lon; /* (return) longitude */ ++#if 0 ++int ++main (int argc, char *argv[]) + { +- double lambda; +- double alpha, delta; +- double tmp; ++ gint i; ++ gint now; ++ GTimeVal timeval; ++ gdouble lat, lon; + +- lambda = sun_ecliptic_longitude(ssue); +- ecliptic_to_equatorial(lambda, 0.0, &alpha, &delta); ++ gtk_init (&argc, &argv); + +- tmp = alpha - (TWOPI/24)*GST(ssue); +- Normalize(tmp); +- *lon = tmp * (360/TWOPI); +- *lat = delta * (360/TWOPI); +-} ++ 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); ++ } + +-/* +- * given a particular time (expressed in seconds since the unix +- * epoch), compute position on the earth (lat, lon) such that the +- * moon is directly overhead. +- * +- * Based on duffett-smith **2nd ed** section 61; combines some steps +- * into single expressions to reduce the number of extra variables. +- */ +-void moon_position(ssue, lat, lon) +- time_t ssue; /* seconds since unix epoch */ +- double *lat; /* (return) latitude */ +- double *lon; /* (return) longitude */ +-{ +- double lambda, beta; +- double D, L, Ms, Mm, N, Ev, Ae, Ec, alpha, delta; +- +- D = DaysSinceEpoch(ssue); +- lambda = sun_ecliptic_longitude(ssue); +- Ms = mean_sun(D); +- +- L = fmod(D/SideralMonth, 1.0)*TWOPI + MoonMeanLongitude; +- Normalize(L); +- Mm = L - DegsToRads(0.1114041*D) - MoonMeanLongitudePerigee; +- Normalize(Mm); +- N = MoonMeanLongitudeNode - DegsToRads(0.0529539*D); +- Normalize(N); +- Ev = DegsToRads(1.2739) * sin(2.0*(L-lambda)-Mm); +- Ae = DegsToRads(0.1858) * sin(Ms); +- Mm += Ev - Ae - DegsToRads(0.37)*sin(Ms); +- Ec = DegsToRads(6.2886) * sin(Mm); +- L += Ev + Ec - Ae + DegsToRads(0.214) * sin(2.0*Mm); +- L += DegsToRads(0.6583) * sin(2.0*(L-lambda)); +- N -= DegsToRads(0.16) * sin(Ms); +- +- L -= N; +- lambda =(fabs(cos(L)) < 1e-12) ? +- (N + sin(L) * cos(MoonInclination) * M_PI/2) : +- (N + atan2(sin(L) * cos(MoonInclination), cos(L))); +- Normalize(lambda); +- beta = asin(sin(L) * sin(MoonInclination)); +- ecliptic_to_equatorial(lambda, beta, &alpha, &delta); +- alpha -= (TWOPI/24)*GST(ssue); +- Normalize(alpha); +- *lon = alpha * (360/TWOPI); +- *lat = delta * (360/TWOPI); ++ return 0; + } ++ ++#endif +diff --git a/src/intlclock-ui.c b/src/intlclock-ui.c +index f51e4de..f0d70bd 100644 +--- a/src/intlclock-ui.c ++++ b/src/intlclock-ui.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -26,18 +27,18 @@ + #include "intlclock-map.h" + #include "intlclock-zoneinfo.h" + #include "intlclock-zonetable.h" ++#include "set-timezone.h" ++#include "gweather-xml.h" + + G_DEFINE_TYPE (IntlClockUI, intlclock_ui, G_TYPE_OBJECT) + + /* GConf keys for compatibility with the older GNOME clock */ +-#define N_GCONF_PREFS 7 ++#define N_GCONF_PREFS 5 + static const char *KEY_CITIES = "cities"; + static const char *KEY_FORMAT = "format"; + static const char *KEY_SHOW_SECONDS = "show_seconds"; + static const char *KEY_SHOW_DATE = "show_date"; + static const char *KEY_SHOW_WEEK = "show_week_numbers"; +-static const char *KEY_SHOW_LOCATIONS = "show_locations"; +-static const char *KEY_SHOW_MAP = "show_map"; + + /* Needs to match the indices in the combo */ + typedef enum { +@@ -78,12 +79,14 @@ typedef struct { + GtkWidget *panel_box; + GtkWidget *panel_button; + GtkWidget *panel_label; ++ GtkWidget *panel_weather_icon; + + GtkTooltips *panel_tips; + + GtkWidget *panel_button_popup; + + GtkWidget *clock_vbox; ++ GtkSizeGroup *clock_group; + + GtkWidget *main_section; + GtkWidget *clock_calendar; +@@ -97,17 +100,34 @@ typedef struct { + + GtkListStore *cities_store; + +- gboolean show_locations; +- gboolean show_map; +- + GtkWidget *prefs_window; + GtkTreeView *prefs_locations; + ++ GtkWidget *prefs_location_add_button; ++ GtkWidget *prefs_location_edit_button; ++ GtkWidget *prefs_location_remove_button; ++ ++ GtkWidget *location_tree; ++ GtkWidget *find_next_location_button; ++ GtkWidget *find_location_entry; ++ GtkWidget *find_location_ok_button; ++ ++ GtkWidget *set_time_window; ++ GtkWidget *hours_spin; ++ GtkWidget *minutes_spin; ++ GtkWidget *seconds_spin; ++ GtkWidget *calendar; ++ GtkWidget *current_time_label; ++ GtkWidget *set_time_button; ++ GtkWidget *time_settings_button; ++ + gboolean format_12hr; + gboolean format_show_seconds; + gboolean format_show_date; + gboolean format_show_week; + ++ gulong zone_combo_changed; ++ + guint listeners [N_GCONF_PREFS]; + } IntlClockUIPrivate; + +@@ -118,51 +138,51 @@ static gboolean update_panel_label (gpointer this); + static void setup_gconf (IntlClockUI *this); + static void load_gconf_settings (IntlClockUI *this); + +-static void bonobo_run_time_configuration (BonoboUIComponent *uic, +- IntlClockUI *this, +- const gchar *verbname); + static void bonobo_display_properties_dialog (BonoboUIComponent *uic, + IntlClockUI *this, + const gchar *verbname); +-static void display_help_dialog (BonoboUIComponent *uic, +- IntlClockUI *this, +- const gchar *verbname); +-static void display_about_dialog (BonoboUIComponent *uic, +- IntlClockUI *this, +- const gchar *verbname); +- +-static void config_date (BonoboUIComponent *uic, +- IntlClockUI *this, +- const gchar *verbname); + + static void intlclock_reposition_events_window (IntlClockUI *this); +- + static void position_popup_window (IntlClockUI *this, + GtkWindow *window, + GtkWidget *origin); + +-static void display_prefs_window_cb (GtkButton *button, gpointer this); +-static void run_time_configuration (IntlClockUI *this); +-static void run_time_configuration_cb (GtkButton *button, gpointer this); ++static void display_prefs_window (IntlClockUI *this, gboolean locations); + static void run_prefs_locations_add (GtkButton *button, gpointer this); + static void run_prefs_locations_edit (GtkButton *button, gpointer this); + static void run_prefs_locations_remove (GtkButton *button, gpointer this); + static void run_prefs_edit_save (GtkButton *button, gpointer this); +- ++static void run_find_location (GtkButton *button, gpointer this); ++static void run_find_location_save (GtkButton *button, gpointer this); ++static void intlclock_edit_hide (GtkWidget *widget, IntlClockUI *this); ++static void intlclock_find_hide (GtkWidget *widget, IntlClockUI *this); + static void intlclock_ui_save_cities_store (IntlClockUI *this); + + static void intlclock_ui_locations_changed (IntlClock *clock, IntlClockUI *this); + + static void create_cities_section (IntlClockUI *this); + static void create_events_window (IntlClockUI *this); +-static void create_main_section (IntlClockUI *this); + static void create_map_section (IntlClockUI *this); + + static void zone_combo_changed (GtkComboBox *widget, gpointer this); ++static void update_coords (IntlClockUI *this, gboolean valid, gfloat lat, gfloat lon); ++static void fill_location_tree (IntlClockUI *this); ++static void copy_time (BonoboUIComponent *uic, ++ IntlClockUI *this, ++ const gchar *verbname); ++static void copy_date (BonoboUIComponent *uic, ++ IntlClockUI *this, ++ const gchar *verbname); ++static void config_date (BonoboUIComponent *uic, ++ IntlClockUI *this, ++ const gchar *verbname); ++ + + static const BonoboUIVerb intlclock_menu_verbs [] = { + BONOBO_UI_UNSAFE_VERB ("IntlClockPreferences", bonobo_display_properties_dialog), +- BONOBO_UI_UNSAFE_VERB ("IntlClockConfig", bonobo_run_time_configuration), ++ BONOBO_UI_UNSAFE_VERB ("ClockCopyTime", copy_time), ++ BONOBO_UI_UNSAFE_VERB ("ClockCopyDate", copy_date), ++ BONOBO_UI_UNSAFE_VERB ("ClockConfig", config_date), + BONOBO_UI_VERB_END + }; + +@@ -190,11 +210,6 @@ intlclock_ui_is_12hr (IntlClockUI *this) + static gboolean + panel_button_press_cb (GtkWidget *button, GdkEventButton *event, gpointer data) + { +- IntlClockUI *this = INTLCLOCK_UI (data); +- IntlClockUIPrivate *priv = PRIVATE (this); +- +- GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (button); +- + if (event->button != 1) + g_signal_stop_emission_by_name (button, "button_press_event"); + +@@ -206,7 +221,9 @@ intlclock_ui_reset_timeout (IntlClockUI *this) + { + IntlClockUIPrivate *priv = PRIVATE (this); + +- if (GTK_WIDGET_VISIBLE (priv->events_window) || priv->format_show_seconds) { ++ if (GTK_WIDGET_VISIBLE (priv->events_window) || ++ (priv->set_time_window && GTK_WIDGET_VISIBLE (priv->set_time_window)) || ++ priv->format_show_seconds) { + intlclock_set_tick_timeout (INTLCLOCK (priv->clock), 1); + } else { + intlclock_set_tick_timeout (INTLCLOCK (priv->clock), 60); +@@ -244,20 +261,6 @@ panel_button_clicked_cb (GtkButton *button, gpointer data) + intlclock_ui_reset_timeout (this); + } + +-static gboolean +-panel_events_button_press_cb (GtkWidget *button, GdkEventButton *event, gpointer data) +-{ +- IntlClockUI *this = INTLCLOCK_UI (data); +- IntlClockUIPrivate *priv = PRIVATE (this); +- +- GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (button); +- +- if (event->button != 1) +- g_signal_stop_emission_by_name (button, "button_press_event"); +- +- return FALSE; +-} +- + static void + position_popup_window (IntlClockUI *this, + GtkWindow *window, +@@ -375,147 +378,6 @@ intlclock_events_window_size_allocate_cb (GtkWidget *widget, GtkAllocation *allo + intlclock_reposition_events_window (this); + } + +-static gboolean +-intlclock_window_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) +-{ +- IntlClockUIPrivate *priv = PRIVATE (user_data); +- +- cairo_t *cr; +- +- cr = gdk_cairo_create (widget->window); +- +- cairo_rectangle ( +- cr, +- event->area.x, event->area.y, +- event->area.width, event->area.height); +- +- cairo_clip (cr); +- +-/* draw window background */ +- +- cairo_rectangle ( +- cr, +- widget->allocation.x + 0.5, widget->allocation.y + 0.5, +- widget->allocation.width - 1, widget->allocation.height - 1); +- +- cairo_set_source_rgb ( +- cr, +- widget->style->bg [GTK_STATE_ACTIVE].red / 65535.0, +- widget->style->bg [GTK_STATE_ACTIVE].green / 65535.0, +- widget->style->bg [GTK_STATE_ACTIVE].blue / 65535.0); +- +- cairo_fill_preserve (cr); +- +-/* draw window outline */ +- +- cairo_set_source_rgb ( +- cr, +- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, +- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, +- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); +- +- cairo_set_line_width (cr, 1.0); +- cairo_stroke (cr); +- +-/* draw main pane background */ +- +- cairo_rectangle ( +- cr, +- priv->main_section->allocation.x + 0.5, priv->main_section->allocation +-.y + 0.5, +- priv->main_section->allocation.width - 1, priv->main_section->allocation.height - 1); +- +- cairo_set_source_rgb ( +- cr, +- widget->style->bg [GTK_STATE_NORMAL].red / 65535.0, +- widget->style->bg [GTK_STATE_NORMAL].green / 65535.0, +- widget->style->bg [GTK_STATE_NORMAL].blue / 65535.0); +- +- cairo_fill (cr); +- +-/* draw map pane background */ +- +- if (priv->show_map) { +- cairo_rectangle ( +- cr, +- priv->map_section->allocation.x + 0.5, +- priv->map_section->allocation.y + 0.5, +- priv->map_section->allocation.width - 1, +- priv->map_section->allocation.height - 1); +- +- cairo_set_source_rgb ( +- cr, +- widget->style->bg [GTK_STATE_NORMAL].red / 65535.0, +- widget->style->bg [GTK_STATE_NORMAL].green / 65535.0, +- widget->style->bg [GTK_STATE_NORMAL].blue / 65535.0); +- +- cairo_fill (cr); +- } +- +-/* draw internal window outline */ +- +- cairo_rectangle ( +- cr, +- priv->clock_vbox->allocation.x + 0.5, priv->clock_vbox->allocation.y + 0.5, +- priv->clock_vbox->allocation.width - 1, priv->clock_vbox->allocation.height - 1); +- +- cairo_set_source_rgb ( +- cr, +- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, +- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, +- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); +- +- cairo_stroke (cr); +- +-/* draw map/cities pane separator */ +- +- if (priv->show_map) { +- cairo_move_to ( +- cr, +- priv->map_section->allocation.x + 0.5, +- priv->map_section->allocation.y + priv->map_section->allocation.height - 0.5); +- +- cairo_line_to ( +- cr, +- priv->map_section->allocation.x + priv->map_section->allocation.width - 0.5, +- priv->map_section->allocation.y + priv->map_section->allocation.height - 0.5); +- +- cairo_set_source_rgb ( +- cr, +- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, +- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, +- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); +- +- cairo_stroke (cr); +- } +- +-/* draw cities/main pane separator */ +- +- if (priv->show_locations) { +- cairo_move_to ( +- cr, +- priv->cities_section->allocation.x + 0.5, +- priv->cities_section->allocation.y + priv->cities_section->allocation.height - 0.5); +- +- cairo_line_to ( +- cr, +- priv->cities_section->allocation.x + priv->cities_section->allocation.width - 0.5, +- priv->cities_section->allocation.y + priv->cities_section->allocation.height - 0.5); +- +- cairo_set_source_rgb ( +- cr, +- widget->style->dark [GTK_STATE_ACTIVE].red / 65535.0, +- widget->style->dark [GTK_STATE_ACTIVE].green / 65535.0, +- widget->style->dark [GTK_STATE_ACTIVE].blue / 65535.0); +- +- cairo_stroke (cr); +- } +- +- cairo_destroy (cr); +- +- return FALSE; +-} +- + static void + intlclock_ui_tick (IntlClock *clock, IntlClockUI *this) + { +@@ -529,10 +391,7 @@ intlclock_ui_tick (IntlClock *clock, IntlClockUI *this) + static void + intlclock_ui_locations_changed (IntlClock *clock, IntlClockUI *this) + { +- IntlClockUIPrivate *priv = PRIVATE (this); +- +- create_cities_section (this); +- intlclock_map_refresh (INTLCLOCK_MAP (priv->map_widget)); ++ create_cities_section (this); + } + + static gboolean +@@ -550,12 +409,20 @@ update_panel_label (gpointer this) + time (&now_t); + localtime_r (&now_t, &now); + ++ if (priv->current_time_label && ++ GTK_WIDGET_VISIBLE (priv->current_time_label)) { ++ date = intlclock_format_time (priv->clock, &now, ++ FALSE, FALSE, TRUE, ++ FALSE, FALSE, NULL, TRUE); ++ gtk_label_set_markup (GTK_LABEL (priv->current_time_label), date); ++ g_free (date); ++ } ++ + date = intlclock_format_time (priv->clock, &now, + priv->format_show_date, + priv->format_12hr, + priv->format_show_seconds, + FALSE, priv->format_show_date, NULL, TRUE); +- + gtk_label_set_markup (GTK_LABEL (priv->panel_label), date); + g_free (date); + +@@ -583,6 +450,7 @@ create_panel_buttons (IntlClockUI *this) + { + IntlClockUIPrivate *priv = PRIVATE (this); + PanelAppletOrient orient; ++ GtkWidget *box; + + orient = panel_applet_get_orient (priv->panel_applet); + +@@ -590,13 +458,18 @@ create_panel_buttons (IntlClockUI *this) + case PANEL_APPLET_ORIENT_UP: + case PANEL_APPLET_ORIENT_DOWN: + priv->panel_box = gtk_hbox_new (FALSE, 0); ++ box = gtk_hbox_new (FALSE, 6); + break; + case PANEL_APPLET_ORIENT_RIGHT: + case PANEL_APPLET_ORIENT_LEFT: + priv->panel_box = gtk_vbox_new (FALSE, 0); ++ box = gtk_vbox_new (FALSE, 6); + break; ++ default: ++ g_assert_not_reached (); + } + priv->panel_label = gtk_label_new (NULL); ++ priv->panel_weather_icon = gtk_image_new (); + priv->panel_button = gtk_toggle_button_new (); + priv->panel_tips = gtk_tooltips_new (); + +@@ -626,8 +499,9 @@ create_panel_buttons (IntlClockUI *this) + gtk_button_set_relief (GTK_BUTTON (priv->panel_button), + GTK_RELIEF_NONE); + +- gtk_container_add (GTK_CONTAINER (priv->panel_button), +- priv->panel_label); ++ gtk_container_add (GTK_CONTAINER (priv->panel_button), box); ++ gtk_container_add (GTK_CONTAINER (box), priv->panel_weather_icon); ++ gtk_container_add (GTK_CONTAINER (box), priv->panel_label); + + g_signal_connect ( + G_OBJECT (priv->panel_button), "clicked", +@@ -655,12 +529,13 @@ create_panel_buttons (IntlClockUI *this) + ); + + gtk_widget_show (priv->panel_label); ++ gtk_widget_show (priv->panel_weather_icon); ++ gtk_widget_show (box); + + gtk_box_pack_start (GTK_BOX (priv->panel_box), priv->panel_button, + FALSE, FALSE, 0); + +- gtk_container_add (GTK_CONTAINER (priv->panel_applet), +- priv->panel_box); ++ gtk_container_add (GTK_CONTAINER (priv->panel_applet), priv->panel_box); + + gtk_widget_show_all (priv->panel_box); + } +@@ -671,10 +546,16 @@ intlclock_ui_change_orient (PanelApplet *applet, + IntlClockUI *this) + { + IntlClockUIPrivate *priv = PRIVATE (this); +- +- if (GTK_IS_WIDGET (priv->panel_box)) +- gtk_widget_destroy (priv->panel_box); ++ GdkPixbuf *pixbuf = NULL; ++ ++ if (GTK_IS_WIDGET (priv->panel_box)) { ++ pixbuf = g_object_ref (gtk_image_get_pixbuf (GTK_IMAGE (priv->panel_weather_icon))); ++ gtk_widget_destroy (priv->panel_box); ++ } + create_panel_buttons (this); ++ intlclock_ui_update_weather_icon (this, pixbuf); ++ if (pixbuf) ++ g_object_unref (pixbuf); + } + + static void +@@ -706,6 +587,16 @@ create_panel_button_popup (IntlClockUI *this) + "hidden", "1", + NULL); + } ++ ++ if (!can_set_system_time ()) { ++ popup_component = panel_applet_get_popup_component ++ (PANEL_APPLET (priv->panel_applet)); ++ ++ bonobo_ui_component_set_prop (popup_component, ++ "/commands/IntlClockConfig", ++ "sensitive", "0", ++ NULL); ++ } + } + + static void +@@ -714,7 +605,7 @@ create_events_window (IntlClockUI *this) + IntlClockUIPrivate *priv = PRIVATE (this); + + priv->events_window = +- GTK_WIDGET (intlclock_events_popup_new (priv->clock, priv->panel_applet)); ++ GTK_WIDGET (intlclock_events_popup_new (priv->clock, priv->panel_applet, this)); + + g_signal_connect (G_OBJECT (priv->events_window), "size-allocate", + G_CALLBACK (intlclock_events_window_size_allocate_cb), this); +@@ -723,41 +614,32 @@ create_events_window (IntlClockUI *this) + } + + static void +-create_clock_window (IntlClockUI *this) ++add_to_group (GtkWidget *child, gpointer data) + { +- IntlClockUIPrivate *priv = PRIVATE (this); +- GtkSettings *settings; +- GtkStyle *style; ++ GtkSizeGroup *group = data; + +- priv->clock_vbox = intlclock_events_popup_get_clock_container +- (INTLCLOCK_EVENTS_POPUP (priv->events_window)); +- gtk_widget_show (priv->clock_vbox); ++ gtk_size_group_add_widget (group, child); + } + + static void +-create_main_section (IntlClockUI *this) ++create_clock_window (IntlClockUI *this) + { + IntlClockUIPrivate *priv = PRIVATE (this); +- IntlClockLocation *loc; +- GtkWidget *header, *subheader; +- GtkWidget *prefs_button; +- GtkWidget *prefs_button_box; +- +- if (!priv->main_section) { +- priv->main_section = gtk_vbox_new (FALSE, 6); +- gtk_container_set_border_width +- (GTK_CONTAINER (priv->main_section), +- MAIN_SECTION_PADDING); +- gtk_box_pack_end (GTK_BOX (priv->clock_vbox), +- priv->main_section, FALSE, FALSE, 0); ++ GtkWidget *clock_container; + +- } else { +- gtk_container_foreach (GTK_CONTAINER (priv->main_section), +- (GtkCallback)gtk_widget_destroy, +- NULL); +- } ++ clock_container = intlclock_events_popup_get_clock_container ++ (INTLCLOCK_EVENTS_POPUP (priv->events_window)); ++ gtk_widget_show (clock_container); ++ ++ priv->clock_vbox = gtk_vbox_new (FALSE, 6); ++ gtk_container_add (GTK_CONTAINER (clock_container), priv->clock_vbox); + +- gtk_widget_show_all (priv->main_section); ++ priv->clock_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); ++ gtk_size_group_set_ignore_hidden (priv->clock_group, FALSE); ++ ++ gtk_container_foreach (GTK_CONTAINER (clock_container), ++ (GtkCallback)add_to_group, ++ priv->clock_group); + } + + static gint +@@ -824,7 +706,6 @@ create_cities_section (IntlClockUI *this) + IntlClockUIPrivate *priv = PRIVATE (this); + GList *node; + IntlClockLocationTile *city; +- GtkWidget *header, *subheader, *image;; + GList *cities; + + if (priv->cities_section) { +@@ -832,12 +713,8 @@ create_cities_section (IntlClockUI *this) + priv->cities_section = NULL; + } + +- if (!priv->show_locations) { +- return; +- } +- + priv->cities_section = gtk_vbox_new (FALSE, 6); +- gtk_container_set_border_width (GTK_CONTAINER (priv->cities_section), 8); ++ gtk_container_set_border_width (GTK_CONTAINER (priv->cities_section), 0); + + cities = intlclock_get_locations (priv->clock); + if (g_list_length (cities) == 0) { +@@ -884,10 +761,6 @@ create_map_section (IntlClockUI *this) + priv->map_widget = NULL; + } + +- if (!priv->show_map) { +- return; +- } +- + map = intlclock_map_new (priv->clock); + + priv->map_section = gtk_alignment_new (0, 0, 1, 1); +@@ -895,11 +768,10 @@ create_map_section (IntlClockUI *this) + + gtk_container_add (GTK_CONTAINER (priv->map_section), priv->map_widget); + +- gtk_box_pack_start (GTK_BOX (priv->clock_vbox), +- priv->map_section, FALSE, FALSE, 0); +- + gtk_alignment_set_padding (GTK_ALIGNMENT (priv->map_section), + 1, 1, 1, 1); ++ gtk_box_pack_start (GTK_BOX (priv->clock_vbox), ++ priv->map_section, FALSE, FALSE, 0); + + gtk_widget_show (priv->map_widget); + gtk_widget_show (priv->map_section); +@@ -927,7 +799,6 @@ create_cities_store (IntlClockUI *this) + + while (list) { + IntlClockLocation *loc = INTLCLOCK_LOCATION (list->data); +- gfloat latitude, longitude; + + gtk_list_store_append (priv->cities_store, &iter); + gtk_list_store_set (priv->cities_store, &iter, +@@ -953,12 +824,16 @@ intlclock_prefs_hide (GtkWidget *widget, IntlClockUI *this) + IntlClockUIPrivate *priv = PRIVATE (this); + GtkWidget *tree; + ++ intlclock_edit_hide (widget, this); ++ + gtk_widget_hide (priv->prefs_window); + + tree = glade_xml_get_widget (priv->glade_xml, "cities_list"); + + gtk_tree_selection_unselect_all + (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree))); ++ ++ intlclock_ui_reset_timeout (this); + } + + static gboolean +@@ -974,8 +849,6 @@ intlclock_edit_clear (GtkWidget *widget, IntlClockUI *this) + { + IntlClockUIPrivate *priv = PRIVATE (this); + +- GtkWidget *edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); +- + GtkWidget *zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); + GtkWidget *name_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-name-entry"); + +@@ -1003,6 +876,8 @@ intlclock_edit_hide (GtkWidget *widget, IntlClockUI *this) + + GtkWidget *edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); + ++ intlclock_find_hide (widget, this); ++ + gtk_widget_hide (edit_window); + + intlclock_edit_clear (widget, this); +@@ -1016,6 +891,23 @@ intlclock_edit_hide_event (GtkWidget *widget, GdkEvent *event, IntlClockUI *this + return TRUE; + } + ++static void ++intlclock_find_hide (GtkWidget *widget, IntlClockUI *this) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (this); ++ ++ GtkWidget *find_window = glade_xml_get_widget (priv->glade_xml, "find-location-window"); ++ ++ gtk_widget_hide (find_window); ++} ++ ++static gboolean ++intlclock_find_hide_event (GtkWidget *widget, GdkEvent *event, IntlClockUI *this) ++{ ++ intlclock_find_hide (widget, this); ++ ++ return TRUE; ++} + + static void + set_12hr_format_radio_cb (GtkWidget *widget, IntlClockUI *this) +@@ -1057,28 +949,6 @@ set_seconds_check_cb (GtkWidget *widget, IntlClockUI *this) + } + + static void +-set_locations_check_cb (GtkWidget *widget, IntlClockUI *this) +-{ +- IntlClockUIPrivate *priv = PRIVATE (this); +- +- panel_applet_gconf_set_bool (PANEL_APPLET (priv->panel_applet), +- KEY_SHOW_LOCATIONS, +- GTK_TOGGLE_BUTTON (widget)->active, +- NULL); +-} +- +-static void +-set_map_check_cb (GtkWidget *widget, IntlClockUI *this) +-{ +- IntlClockUIPrivate *priv = PRIVATE (this); +- +- panel_applet_gconf_set_bool (PANEL_APPLET (priv->panel_applet), +- KEY_SHOW_MAP, +- GTK_TOGGLE_BUTTON (widget)->active, +- NULL); +-} +- +-static void + fill_prefs_window (IntlClockUI *this) + { + IntlClockUIPrivate *priv = PRIVATE (this); +@@ -1087,6 +957,9 @@ fill_prefs_window (IntlClockUI *this) + GtkCellRenderer *renderer; + GtkTreeViewColumn *col; + ++ time_t now_t; ++ struct tm now; ++ + /* Set the 12 hour / 24 hour widget */ + widget = glade_xml_get_widget (priv->glade_xml, "12hr_radio"); + g_signal_connect (widget, "toggled", +@@ -1109,18 +982,6 @@ fill_prefs_window (IntlClockUI *this) + g_signal_connect (widget, "toggled", G_CALLBACK (set_seconds_check_cb), + this); + +- /* Set the "Show Locations" checkbox */ +- widget = glade_xml_get_widget (priv->glade_xml, "show_locations_check"); +- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), priv->show_locations); +- g_signal_connect (widget, "toggled", G_CALLBACK (set_locations_check_cb), +- this); +- +- /* Set the "Show Map" checkbox */ +- widget = glade_xml_get_widget (priv->glade_xml, "show_map_check"); +- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), priv->show_map); +- g_signal_connect (widget, "toggled", G_CALLBACK (set_map_check_cb), +- this); +- + /* Fill the Cities list */ + widget = glade_xml_get_widget (priv->glade_xml, "cities_list"); + +@@ -1136,6 +997,15 @@ fill_prefs_window (IntlClockUI *this) + + gtk_tree_view_set_model (GTK_TREE_VIEW (widget), + GTK_TREE_MODEL (priv->cities_store)); ++ ++ /* Fill the time settings */ ++ tzset (); ++ time (&now_t); ++ localtime_r (&now_t, &now); ++ ++ gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->seconds_spin), now.tm_sec); ++ gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->minutes_spin), now.tm_min); ++ gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->hours_spin), now.tm_hour); + } + + static gint +@@ -1150,19 +1020,334 @@ sort_zoneinfo_by_l10n_name (gconstpointer a, gconstpointer b) + return strcmp (name_a, name_b); + } + ++static void ++intlclock_prefs_locations_changed (GtkTreeSelection *selection, ++ IntlClockUI *this) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (this); ++ gint n; ++ ++ n = gtk_tree_selection_count_selected_rows (selection); ++ gtk_widget_set_sensitive (priv->prefs_location_edit_button, n > 0); ++ gtk_widget_set_sensitive (priv->prefs_location_remove_button, n > 0); ++} ++ + static void +-display_prefs_window (IntlClockUI *this) ++location_tree_selection_changed (GtkTreeSelection *selection, ++ IntlClockUI *this) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (this); ++ GtkTreeModel *model; ++ GtkTreeIter iter; ++ WeatherLocation *loc = NULL; ++ gboolean can_save = FALSE; ++ ++ if (gtk_tree_selection_get_selected (selection, &model, &iter)) { ++ gtk_tree_model_get (model, &iter, GWEATHER_XML_COL_POINTER, &loc, -1); ++ if (loc != NULL) ++ can_save = TRUE; ++ } ++ ++ gtk_widget_set_sensitive (priv->find_location_ok_button, can_save); ++} ++ ++static void ++wrap_cb (GtkSpinButton *spin, ++ IntlClockUI *this) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (this); ++ 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 *)priv->seconds_spin) ++ gtk_spin_button_spin (GTK_SPIN_BUTTON (priv->minutes_spin), ++ direction, 1.0); ++ else if (spin == (GtkSpinButton *)priv->minutes_spin) ++ gtk_spin_button_spin (GTK_SPIN_BUTTON (priv->hours_spin), ++ direction, 1.0); ++ else { ++ guint year, month, day; ++ GDate *date; ++ ++ gtk_calendar_get_date (GTK_CALENDAR (priv->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 (priv->calendar), ++ month, year); ++ gtk_calendar_select_day (GTK_CALENDAR (priv->calendar), ++ day); ++ ++ g_date_free (date); ++ } ++} ++ ++static void ++update_set_time_button (IntlClockUI *this) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (this); ++ gint can_set; ++ ++ can_set = can_set_system_time (); ++ ++ if (priv->time_settings_button) ++ gtk_widget_set_sensitive (priv->time_settings_button, can_set != 0); ++ if (priv->set_time_button) ++ gtk_button_set_label (GTK_BUTTON (priv->set_time_button), ++ can_set == 1 ? ++ _("Set System Time...") : ++ _("Set System Time")); ++} ++ ++static void ++set_time_callback (IntlClockUI *this, GError *error) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (this); ++ GtkWidget *window; ++ GtkWidget *dialog; ++ ++ if (error) { ++ dialog = gtk_message_dialog_new (NULL, ++ 0, ++ GTK_MESSAGE_ERROR, ++ GTK_BUTTONS_OK, ++ _("Failed to set the system time")); ++ ++ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), 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 (this); ++ ++ window = glade_xml_get_widget (priv->glade_xml, "set-time-window"); ++ gtk_widget_hide (window); ++} ++ ++static void ++set_time (GtkWidget *widget, IntlClockUI *this) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (this); ++ struct tm t; ++ gint64 time; ++ guint year, month, day; ++ ++ t.tm_sec = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->seconds_spin)); ++ t.tm_min = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->minutes_spin)); ++ t.tm_hour = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->hours_spin)); ++ gtk_calendar_get_date (GTK_CALENDAR (priv->calendar), &year, &month, &day); ++ t.tm_year = year - 1900; ++ t.tm_mon = month; ++ t.tm_mday = day; ++ ++ time = mktime (&t); ++ ++ set_system_time_async (time, (GFunc)set_time_callback, this, NULL); ++} ++ ++static gboolean ++find_location (GtkTreeModel *model, ++ GtkTreeIter *iter, ++ const gchar *location, ++ gboolean go_parent) ++{ ++ GtkTreeIter iter_child; ++ GtkTreeIter iter_parent; ++ gchar *aux_loc; ++ gboolean valid; ++ int len; ++ ++ len = strlen (location); ++ ++ if (len <= 0) { ++ return FALSE; ++ } ++ ++ do { ++ gtk_tree_model_get (model, iter, GWEATHER_XML_COL_LOC, &aux_loc, -1); ++ ++ if (g_ascii_strncasecmp (aux_loc, location, len) == 0) { ++ g_free (aux_loc); ++ return TRUE; ++ } ++ ++ if (gtk_tree_model_iter_has_child (model, iter)) { ++ gtk_tree_model_iter_nth_child (model, &iter_child, iter, 0); ++ if (find_location (model, &iter_child, location, FALSE)) { ++ /* Manual copying of the iter */ ++ iter->stamp = iter_child.stamp; ++ iter->user_data = iter_child.user_data; ++ iter->user_data2 = iter_child.user_data2; ++ iter->user_data3 = iter_child.user_data3; ++ ++ g_free (aux_loc); ++ ++ return TRUE; ++ } ++ } ++ ++ g_free (aux_loc); ++ ++ valid = gtk_tree_model_iter_next (model, iter); ++ } while (valid); ++ ++ if (go_parent) { ++ iter_parent = *iter; ++ while (gtk_tree_model_iter_parent (model, iter, &iter_parent)) { ++ if (gtk_tree_model_iter_next (model, iter)) ++ return find_location (model, iter, location, TRUE); ++ iter_parent = *iter; ++ } ++ } ++ ++ return FALSE; ++} ++ ++static void ++find_next_location (GtkButton *button, IntlClockUI *this) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (this); ++ GtkTreeView *tree; ++ GtkTreeModel *model; ++ GtkEntry *entry; ++ GtkTreeSelection *selection; ++ GtkTreeIter iter; ++ GtkTreeIter iter_parent; ++ GtkTreePath *path; ++ const gchar *location; ++ ++ tree = GTK_TREE_VIEW (priv->location_tree); ++ model = gtk_tree_view_get_model (tree); ++ entry = GTK_ENTRY (priv->find_location_entry); ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree)); ++ ++ if (gtk_tree_selection_count_selected_rows (selection) >= 1) { ++ gtk_tree_selection_get_selected (selection, &model, &iter); ++ /* Select next or select parent */ ++ if (!gtk_tree_model_iter_next (model, &iter)) { ++ iter_parent = iter; ++ if (!gtk_tree_model_iter_parent (model, &iter, &iter_parent) || ++ !gtk_tree_model_iter_next (model, &iter)) ++ gtk_tree_model_get_iter_first (model, &iter); ++ } ++ } ++ else { ++ gtk_tree_model_get_iter_first (model, &iter); ++ } ++ location = gtk_entry_get_text (entry); ++ ++ if (find_location (model, &iter, location, TRUE)) { ++ gtk_widget_set_sensitive (priv->find_next_location_button, TRUE); ++ path = gtk_tree_model_get_path (model, &iter); ++ gtk_tree_view_expand_to_path (tree, path); ++ gtk_tree_selection_select_path (selection, path); ++ gtk_tree_view_scroll_to_cell (tree, path, NULL, TRUE, 0.5, 0); ++ ++ gtk_tree_path_free (path); ++ } ++ else { ++ gtk_widget_set_sensitive (priv->find_next_location_button, FALSE); ++ } ++} ++ ++static void ++find_entry_changed (GtkEditable *entry, IntlClockUI *this) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (this); ++ GtkTreeView *tree; ++ GtkTreeModel *model; ++ GtkTreeSelection *selection; ++ GtkTreeIter iter; ++ GtkTreePath *path; ++ const gchar *location; ++ ++ tree = GTK_TREE_VIEW (priv->location_tree); ++ model = gtk_tree_view_get_model (tree); ++ ++ selection = gtk_tree_view_get_selection (tree); ++ gtk_tree_model_get_iter_first (model, &iter); ++ ++ location = gtk_entry_get_text (GTK_ENTRY (entry)); ++ if (find_location (model, &iter, location, TRUE)) { ++ gtk_widget_set_sensitive (priv->find_next_location_button, TRUE); ++ path = gtk_tree_model_get_path (model, &iter); ++ gtk_tree_view_expand_to_path (tree, path); ++ gtk_tree_selection_select_iter (selection, &iter); ++ gtk_tree_view_scroll_to_cell (tree, path, NULL, TRUE, 0.5, 0); ++ gtk_tree_path_free (path); ++ } ++ else { ++ gtk_widget_set_sensitive (priv->find_next_location_button, FALSE); ++ } ++} ++ ++static void ++cancel_time_settings (GtkWidget *button, IntlClockUI *this) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (this); ++ ++ gtk_widget_hide (priv->set_time_window); ++ ++ intlclock_ui_reset_timeout (this); ++} ++ ++static void ++run_time_settings (GtkWidget *button, IntlClockUI *this) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (this); ++ GtkWidget *cancel_set_time_button; ++ ++ if (!priv->set_time_button) { ++ priv->set_time_button = glade_xml_get_widget (priv->glade_xml, "set-time-button"); ++ g_signal_connect (priv->set_time_button, "clicked", G_CALLBACK (set_time), this); ++ ++ cancel_set_time_button = glade_xml_get_widget (priv->glade_xml, "cancel-set-time-button"); ++ g_signal_connect (cancel_set_time_button, "clicked", G_CALLBACK (cancel_time_settings), this); ++ ++ priv->current_time_label = glade_xml_get_widget (priv->glade_xml, "current_time_label"); ++ } ++ ++ priv->set_time_window = glade_xml_get_widget (priv->glade_xml, "set-time-window"); ++ gtk_window_present (GTK_WINDOW (priv->set_time_window)); ++ ++ intlclock_ui_reset_timeout (this); ++} ++ ++static void ++display_prefs_window (IntlClockUI *this, gboolean locations) + { + IntlClockUIPrivate *priv = PRIVATE (this); + GtkWidget *edit_window; +- GtkWidget *prefs_window; + GtkWidget *prefs_close_button; +- GtkWidget *prefs_settings_button; + GtkWidget *edit_cancel_button; + GtkWidget *edit_ok_button; + GtkWidget *zone_combo; +- +- GtkWidget *tmp_button; ++ GtkWidget *find_window; ++ GtkWidget *find_location_button; ++ GtkWidget *find_location_cancel_button; ++ GtkTreeSelection *selection; + + if (!priv->prefs_window) { + priv->prefs_window = +@@ -1170,43 +1355,42 @@ display_prefs_window (IntlClockUI *this) + + prefs_close_button = + glade_xml_get_widget (priv->glade_xml, "prefs-close-button"); +- +- prefs_settings_button = +- glade_xml_get_widget (priv->glade_xml, "prefs-time-settings-button"); +- + priv->prefs_locations = + GTK_TREE_VIEW (glade_xml_get_widget (priv->glade_xml, "cities_list")); + ++ selection = gtk_tree_view_get_selection (priv->prefs_locations); ++ g_signal_connect (G_OBJECT (selection), "changed", ++ G_CALLBACK (intlclock_prefs_locations_changed), this); ++ + g_signal_connect (G_OBJECT (priv->prefs_window), "delete_event", + G_CALLBACK (intlclock_prefs_hide_event), this); + + g_signal_connect (G_OBJECT (prefs_close_button), "clicked", + G_CALLBACK (intlclock_prefs_hide), this); + +- g_signal_connect (G_OBJECT (prefs_settings_button), "clicked", +- G_CALLBACK (run_time_configuration_cb), this); +- +- tmp_button = ++ priv->prefs_location_remove_button = + glade_xml_get_widget (priv->glade_xml, "prefs-locations-remove-button"); + +- g_signal_connect (G_OBJECT (tmp_button), "clicked", ++ g_signal_connect (G_OBJECT (priv->prefs_location_remove_button), "clicked", + G_CALLBACK (run_prefs_locations_remove), this); +- +- tmp_button = ++ ++ priv->prefs_location_add_button = + glade_xml_get_widget (priv->glade_xml, "prefs-locations-add-button"); + +- g_signal_connect (G_OBJECT (tmp_button), "clicked", ++ g_signal_connect (G_OBJECT (priv->prefs_location_add_button), "clicked", + G_CALLBACK (run_prefs_locations_add), this); + +- tmp_button = ++ priv->prefs_location_edit_button = + glade_xml_get_widget (priv->glade_xml, "prefs-locations-edit-button"); + +- g_signal_connect (G_OBJECT (tmp_button), "clicked", ++ g_signal_connect (G_OBJECT (priv->prefs_location_edit_button), "clicked", + G_CALLBACK (run_prefs_locations_edit), this); + + edit_window = glade_xml_get_widget (priv->glade_xml, + "edit-location-window"); + ++ gtk_window_set_transient_for (GTK_WINDOW (edit_window), ++ GTK_WINDOW (priv->prefs_window)); + + g_signal_connect (G_OBJECT (edit_window), "delete_event", + G_CALLBACK (intlclock_edit_hide_event), this); +@@ -1219,7 +1403,35 @@ display_prefs_window (IntlClockUI *this) + + zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); + +- g_signal_connect (G_OBJECT (zone_combo), "changed", ++ find_window = glade_xml_get_widget (priv->glade_xml, ++ "find-location-window"); ++ ++ gtk_window_set_transient_for (GTK_WINDOW (find_window), ++ GTK_WINDOW (edit_window)); ++ ++ g_signal_connect (G_OBJECT (find_window), "delete_event", ++ G_CALLBACK (intlclock_find_hide_event), this); ++ ++ find_location_button = ++ glade_xml_get_widget (priv->glade_xml, "find-location-button"); ++ ++ priv->find_location_ok_button = ++ glade_xml_get_widget (priv->glade_xml, "find-location-ok-button"); ++ ++ find_location_cancel_button = ++ glade_xml_get_widget (priv->glade_xml, "find-location-cancel-button"); ++ ++ priv->find_next_location_button = ++ glade_xml_get_widget (priv->glade_xml, "find-next-location-button"); ++ ++ priv->find_location_entry = ++ glade_xml_get_widget (priv->glade_xml, "find-location-entry"); ++ ++ priv->location_tree = ++ glade_xml_get_widget (priv->glade_xml, "find-location-tree"); ++ ++ priv->zone_combo_changed = ++ g_signal_connect (G_OBJECT (zone_combo), "changed", + G_CALLBACK (zone_combo_changed), this); + + +@@ -1229,16 +1441,72 @@ display_prefs_window (IntlClockUI *this) + g_signal_connect (G_OBJECT (edit_ok_button), "clicked", + G_CALLBACK (run_prefs_edit_save), this); + ++ g_signal_connect (find_location_button, "clicked", ++ G_CALLBACK (run_find_location), this); ++ ++ g_signal_connect (G_OBJECT (find_location_cancel_button), "clicked", ++ G_CALLBACK (intlclock_find_hide), this); ++ ++ g_signal_connect (G_OBJECT (priv->find_location_ok_button), "clicked", ++ G_CALLBACK (run_find_location_save), this); ++ ++ g_signal_connect (G_OBJECT (priv->find_next_location_button), "clicked", ++ G_CALLBACK (find_next_location), this); ++ ++ g_signal_connect (G_OBJECT (priv->find_location_entry), "changed", ++ G_CALLBACK (find_entry_changed), this); ++ ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->location_tree)); ++ g_signal_connect (selection, "changed", ++ G_CALLBACK (location_tree_selection_changed), this); ++ + /* We have to put an item in the combo box in the glade file + to get the simpler, string-only store. Here we remove that + item. */ + gtk_combo_box_remove_text (GTK_COMBO_BOX (zone_combo), 0); + ++ /* Set up the time setting section */ ++ ++ priv->time_settings_button = glade_xml_get_widget (priv->glade_xml, "time-settings-button"); ++ g_signal_connect (priv->time_settings_button, "clicked", G_CALLBACK (run_time_settings), this); ++ ++ priv->calendar = glade_xml_get_widget (priv->glade_xml, "calendar"); ++ priv->hours_spin = glade_xml_get_widget (priv->glade_xml, "hours_spin"); ++ priv->minutes_spin = glade_xml_get_widget (priv->glade_xml, "minutes_spin"); ++ priv->seconds_spin = glade_xml_get_widget (priv->glade_xml, "seconds_spin"); ++ ++ gtk_entry_set_width_chars (GTK_ENTRY (priv->hours_spin), 2); ++ gtk_entry_set_width_chars (GTK_ENTRY (priv->minutes_spin), 2); ++ gtk_entry_set_width_chars (GTK_ENTRY (priv->seconds_spin), 2); ++ ++ gtk_entry_set_alignment (GTK_ENTRY (priv->hours_spin), 1.0); ++ gtk_entry_set_alignment (GTK_ENTRY (priv->minutes_spin), 1.0); ++ gtk_entry_set_alignment (GTK_ENTRY (priv->seconds_spin), 1.0); ++ g_signal_connect (priv->seconds_spin, "wrapped", G_CALLBACK (wrap_cb), this); ++ g_signal_connect (priv->minutes_spin, "wrapped", G_CALLBACK (wrap_cb), this); ++ g_signal_connect (priv->hours_spin, "wrapped", G_CALLBACK (wrap_cb), this); ++ + /* fill it with the current preferences */ + fill_prefs_window (this); + } + ++ if (locations) { ++ GtkWidget *notebook = ++ glade_xml_get_widget (priv->glade_xml, "notebook"); ++ gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 1); ++ } ++ ++ update_set_time_button (this); ++ + gtk_window_present (GTK_WINDOW (priv->prefs_window)); ++ ++ intlclock_ui_reset_timeout (this); ++} ++ ++void ++intlclock_ui_edit_locations (IntlClockUI *ui) ++{ ++ display_prefs_window (ui, TRUE); + } + + static void +@@ -1306,16 +1574,11 @@ intlclock_ui_new (IntlClock *clock, PanelApplet *applet) + create_events_window (this); + create_clock_window (this); + create_cities_store (this); +- +- if (priv->show_locations) { +- create_cities_section (this); +- } +- +- if (priv->show_map) { +- create_map_section (this); +- intlclock_map_refresh (INTLCLOCK_MAP (priv->map_widget)); +- } +- ++ create_cities_section (this); ++ create_map_section (this); ++ ++ intlclock_map_refresh (INTLCLOCK_MAP (priv->map_widget)); ++ + intlclock_ui_reset_timeout (this); + + return this; +@@ -1365,9 +1628,6 @@ intlclock_ui_init (IntlClockUI *this) + + priv->cities_store = NULL; + +- priv->show_locations = TRUE; +- priv->show_map = TRUE; +- + priv->prefs_window = NULL; + + priv->format_12hr = TRUE; +@@ -1547,56 +1807,6 @@ gconf_show_week_changed (GConfClient *client, + } + + static void +-gconf_show_locations_changed (GConfClient *client, +- guint cnxn_id, +- GConfEntry *entry, +- IntlClockUI *this) +-{ +- IntlClockUIPrivate *priv = PRIVATE (this); +- GtkWidget *widget; +- +- gboolean value; +- +- if (!entry->value || entry->value->type != GCONF_VALUE_BOOL) +- return; +- +- value = gconf_value_get_bool (entry->value); +- +- priv->show_locations = (value != 0); +- +- widget = glade_xml_get_widget (priv->glade_xml, "show_locations_check"); +- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), +- priv->show_locations); +- +- create_cities_section (this); +-} +- +-static void +-gconf_show_map_changed (GConfClient *client, +- guint cnxn_id, +- GConfEntry *entry, +- IntlClockUI *this) +-{ +- IntlClockUIPrivate *priv = PRIVATE (this); +- GtkWidget *widget; +- +- gboolean value; +- +- if (!entry->value || entry->value->type != GCONF_VALUE_BOOL) +- return; +- +- value = gconf_value_get_bool (entry->value); +- +- priv->show_map = (value != 0); +- +- widget = glade_xml_get_widget (priv->glade_xml, "show_map_check"); +- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), +- priv->show_map); +- +- create_map_section (this); +-} +- +-static void + location_start_element (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, +@@ -1614,6 +1824,7 @@ location_start_element (GMarkupParseContext *context, + gchar *timezone = NULL; + gfloat latitude = 0.0; + gfloat longitude = 0.0; ++ gchar *code = NULL; + + int index = 0; + +@@ -1633,6 +1844,8 @@ location_start_element (GMarkupParseContext *context, + 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]; + } + } + +@@ -1642,7 +1855,7 @@ location_start_element (GMarkupParseContext *context, + return; + } + +- loc = intlclock_location_new (name, timezone, latitude, longitude); ++ loc = intlclock_location_new (name, timezone, latitude, longitude, code); + + *(GList **)user_data = g_list_append (ret, loc); + } +@@ -1713,10 +1926,11 @@ gconf_loc_to_string (IntlClockLocation *loc) + prev_locale = setlocale (LC_NUMERIC, "POSIX"); + + ret = g_markup_printf_escaped +- ("", ++ ("", + intlclock_location_get_name (loc), + intlclock_location_get_timezone (loc), +- latitude, longitude); ++ latitude, longitude, ++ intlclock_location_get_weather_code (loc)); + + setlocale (LC_NUMERIC, ""); + +@@ -1727,7 +1941,7 @@ static void + intlclock_ui_save_cities_store (IntlClockUI *this) + { + IntlClockUIPrivate *priv = PRIVATE (this); +- IntlClockLocation *loc, *cur; ++ IntlClockLocation *loc; + GList *node = intlclock_get_locations (priv->clock); + + GSList *root = NULL; +@@ -1803,24 +2017,6 @@ setup_gconf (IntlClockUI *this) + g_free (key); + + key = panel_applet_gconf_get_full_key +- (PANEL_APPLET (priv->panel_applet), KEY_SHOW_LOCATIONS); +- priv->listeners [index++] = +- gconf_client_notify_add ( +- client, key, +- (GConfClientNotifyFunc) gconf_show_locations_changed, +- this, NULL, NULL); +- g_free (key); +- +- key = panel_applet_gconf_get_full_key +- (PANEL_APPLET (priv->panel_applet), KEY_SHOW_MAP); +- priv->listeners [index++] = +- gconf_client_notify_add ( +- client, key, +- (GConfClientNotifyFunc) gconf_show_map_changed, +- this, NULL, NULL); +- g_free (key); +- +- key = panel_applet_gconf_get_full_key + (PANEL_APPLET (priv->panel_applet), KEY_CITIES); + priv->listeners [index++] = + gconf_client_notify_add ( +@@ -1868,14 +2064,6 @@ load_gconf_settings (IntlClockUI *this) + panel_applet_gconf_get_bool (priv->panel_applet, + KEY_SHOW_WEEK, NULL); + +- priv->show_locations = +- panel_applet_gconf_get_bool (priv->panel_applet, +- KEY_SHOW_LOCATIONS, NULL); +- +- priv->show_map = +- panel_applet_gconf_get_bool (priv->panel_applet, +- KEY_SHOW_MAP, NULL); +- + values = panel_applet_gconf_get_list (priv->panel_applet, KEY_CITIES, + GCONF_VALUE_STRING, NULL); + +@@ -1892,92 +2080,72 @@ static void bonobo_display_properties_dialog (BonoboUIComponent *uic, + IntlClockUI *this, + const gchar *verbname) + { +- IntlClockUIPrivate *priv = PRIVATE (this); +- +- display_prefs_window (this); ++ display_prefs_window (this, FALSE); + } + +-static void bonobo_run_time_configuration (BonoboUIComponent *uic, +- IntlClockUI *this, +- const gchar *verbname) +-{ +- IntlClockUIPrivate *priv = PRIVATE (this); +- +- run_time_configuration (this); +-} +- +-static void display_prefs_window_cb (GtkButton *button, gpointer this) ++static void ++copy_time (BonoboUIComponent *uic, ++ IntlClockUI *this, ++ const gchar *verbname) + { + IntlClockUIPrivate *priv = PRIVATE (this); ++ gchar *utf8; ++ time_t now_t; ++ struct tm now; + +- display_prefs_window (this); +-} ++ tzset (); ++ time (&now_t); ++ localtime_r (&now_t, &now); + +-static void +-run_time_configuration_cb (GtkButton *button, gpointer this) +-{ +- IntlClockUIPrivate *priv = PRIVATE (this); ++ utf8 = intlclock_format_time (priv->clock, &now, FALSE, ++ priv->format_12hr, ++ priv->format_show_seconds, ++ FALSE, FALSE, NULL, FALSE); ++ ++ gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY), ++ utf8, -1); ++ gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), ++ utf8, -1); + +- run_time_configuration (this); ++ g_free (utf8); + } + + static void +-run_time_configuration (IntlClockUI *this) ++copy_date (BonoboUIComponent *uic, ++ IntlClockUI *this, ++ const gchar *verbname) + { +- IntlClockUIPrivate *priv = PRIVATE (this); +- +- GtkWidget *dialog; +- GError *err; +- char **argv; +- char *path; ++ char string[256]; ++ char *utf8, *loc; + +- GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (priv->events_window)); +- gchar *tool = "/opt/gnome/bin/gnomesu /sbin/yast2 timezone"; +- +- if (!tool || tool[0] == '\0') +- return; +- +- if (!g_shell_parse_argv (tool, NULL, &argv, NULL)) +- return; +- +- if (!(path = g_find_program_in_path (argv [0]))) { +- g_strfreev (argv); +- return; +- } +- +- g_free (path); +- +- err = NULL; +- if (gdk_spawn_on_screen (screen, +- NULL, +- argv, +- NULL, +- G_SPAWN_SEARCH_PATH, +- NULL, +- NULL, +- NULL, +- &err)) { +- g_strfreev (argv); +- return; +- } +- +- g_strfreev (argv); ++ time_t now_t; ++ struct tm now; + +- dialog = gtk_message_dialog_new (NULL, +- GTK_DIALOG_DESTROY_WITH_PARENT, +- GTK_MESSAGE_ERROR, +- GTK_BUTTONS_OK, +- _("Failed to launch time configuration tool: %s"), +- err->message); +- g_error_free (err); ++ tzset (); ++ time (&now_t); ++ localtime_r (&now_t, &now); + +- g_signal_connect (dialog, "response", +- G_CALLBACK (gtk_widget_destroy), NULL); ++ loc = g_locale_from_utf8 (_("%A, %B %d %Y"), -1, NULL, NULL, NULL); ++ if (!loc) ++ strcpy (string, "???"); ++ else if (strftime (string, sizeof (string), loc, &now) <= 0) ++ strcpy (string, "???"); ++ g_free (loc); + +- gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); +- gtk_window_set_screen (GTK_WINDOW (dialog), screen); ++ 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); ++} + +- gtk_widget_show_all (dialog); ++static void ++config_date (BonoboUIComponent *uic, ++ IntlClockUI *this, ++ const char *verbname) ++{ ++ run_time_settings (NULL, this); + } + + static void +@@ -2000,6 +2168,46 @@ remove_tree_row (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + } + + static void ++update_coords (IntlClockUI *this, gboolean valid, gfloat lat, gfloat lon) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); ++ GtkWidget *lat_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-latitude-entry"); ++ GtkWidget *lon_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-entry"); ++ GtkWidget *lat_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-latitude-combo"); ++ GtkWidget *lon_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-combo"); ++ gchar *tmp; ++ ++ 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; ++ } ++ ++ 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); ++ } ++} ++ ++static void + zone_combo_changed (GtkComboBox *widget, gpointer this) + { + IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); +@@ -2009,17 +2217,12 @@ zone_combo_changed (GtkComboBox *widget, gpointer this) + gchar *city = NULL; + gfloat lat = 0; + gfloat lon = 0; +- gchar *tmp; ++ GtkTreeModel *model; ++ gchar *name; + + GtkWidget *name_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-name-entry"); +- +- GtkWidget *lat_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-latitude-entry"); +- +- GtkWidget *lon_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-entry"); +- +- GtkWidget *lat_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-latitude-combo"); +- +- GtkWidget *lon_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-combo"); ++ GtkWidget *edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); ++ gchar *weather_code; + + IntlClockCountry *country; + IntlClockZoneInfo *info; +@@ -2028,6 +2231,14 @@ zone_combo_changed (GtkComboBox *widget, gpointer this) + return; + } + ++ /* only fill in other field if name is not set yet, to ++ * allow correcting a guessed timezone ++ */ ++ name = gtk_entry_get_text (name_entry); ++ if (name && name[0]) { ++ return; ++ } ++ + info = intlclock_zonetable_get_l10n_zone (zones, timezone); + g_free (timezone); + +@@ -2049,26 +2260,13 @@ zone_combo_changed (GtkComboBox *widget, gpointer this) + g_free (city); + + intlclock_zoneinfo_get_coords (info, &lat, &lon); ++ update_coords (this, TRUE, lat, lon); + +- 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); +- } ++ fill_location_tree (this); ++ model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->location_tree)); ++ weather_code = find_weather_code (model, city, lat * M_PI/180.0, lon * M_PI/180.0); ++ g_object_set_data_full (G_OBJECT (edit_window), "weather-code", ++ weather_code, g_free); + } + + static void +@@ -2144,12 +2342,8 @@ edit_tree_row (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); + + IntlClockLocation *loc; +- int i; +- int timezone_idx = -1; + gchar *tmp; + gfloat lat, lon; +- GList *list; +- GList *cur; + + /* fill the dialog with this location's data, show it */ + GtkWidget *edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); +@@ -2205,13 +2399,165 @@ static void + run_prefs_locations_remove (GtkButton *button, gpointer this) + { + IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); +- GtkTreeModel *model = gtk_tree_view_get_model (priv->prefs_locations);; + GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->prefs_locations)); + + gtk_tree_selection_selected_foreach (sel, remove_tree_row, this); + } + + static void ++run_find_location (GtkButton *button, gpointer this) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); ++ ++ GtkWidget *window = glade_xml_get_widget (priv->glade_xml, "find-location-window"); ++ ++ gtk_tree_view_collapse_all (priv->location_tree); ++ gtk_widget_grab_focus (priv->find_location_entry); ++ gtk_window_present (GTK_WINDOW (window)); ++} ++ ++static gdouble ++distance (gdouble lat1, gdouble lon1, ++ gdouble lat2, gdouble lon2) ++{ ++ gdouble radius = 6372.795; ++ ++ return acos (cos (lat1) * cos (lat2) * cos (lon1 - lon2) + sin (lat1) * sin (lat2)) * radius; ++} ++ ++static gchar * ++find_timezone (IntlClockUI *this, ++ const char *name, ++ gfloat lat, ++ gfloat lon) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); ++ IntlClockZoneTable *zonetab = intlclock_get_zonetable (priv->clock); ++ GList *zones, *l; ++ double dist, d; ++ gfloat zlat, zlon; ++ IntlClockZoneInfo *best; ++ ++ g_print ("find zone for %s (%f %f)\n", name, lat, lon); ++ dist = 1e6; ++ best = NULL; ++ zones = intlclock_zonetable_get_zones (zonetab); ++ for (l = zones; l; l = l->next) { ++ IntlClockZoneInfo *info = l->data; ++ intlclock_zoneinfo_get_coords (info, &zlat, &zlon); ++ ++ d = distance (lat, lon, zlat*M_PI/180.0, zlon*M_PI/180.0); ++ ++ if (d < dist) { ++ best = info; ++ dist = d; ++ } ++ } ++ ++ intlclock_zoneinfo_get_coords (best, &zlat, &zlon); ++ g_print ("best: %s (%f, %f), distance: %f\n", ++ intlclock_zoneinfo_get_name (best), zlat, zlon, dist); ++ ++ return g_strdup (intlclock_zoneinfo_get_name (best)); ++} ++ ++static void ++update_timezone (IntlClockUI *this, ++ const char *name, ++ gfloat lat, ++ gfloat lon) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); ++ GtkWidget *zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); ++ GtkTreeModel *model; ++ gchar *timezone; ++ IntlClockLocation *loc; ++ ++ timezone = find_timezone (this, name, lat, lon); ++ loc = intlclock_location_new (name, timezone, lat*180.0/M_PI, lon*180.0/M_PI, NULL); ++ ++ g_signal_handler_block (zone_combo, priv->zone_combo_changed); ++ ++ fill_timezone_combo_from_location (this, zone_combo, loc); ++ ++ g_signal_handler_unblock (zone_combo, priv->zone_combo_changed); ++ ++ g_object_unref (loc); ++ g_free (timezone); ++} ++ ++static void ++run_find_location_save (GtkButton *button, gpointer this) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); ++ GtkTreeSelection *selection; ++ GtkTreeModel *model; ++ GtkTreeIter iter; ++ WeatherLocation *loc = NULL; ++ GtkWidget *name_entry; ++ GtkWidget *edit_window; ++ ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->location_tree)); ++ if (!gtk_tree_selection_get_selected (selection, &model, &iter)) ++ return; ++ ++ gtk_tree_model_get (model, &iter, GWEATHER_XML_COL_POINTER, &loc, -1); ++ ++ if (!loc) ++ return; ++ ++ edit_window = glade_xml_get_widget (priv->glade_xml, "edit-location-window"); ++ name_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-name-entry"); ++ gtk_entry_set_text (GTK_ENTRY (name_entry), loc->name); ++ g_object_set_data_full (G_OBJECT (edit_window), "weather-code", ++ g_strdup (loc->code), g_free); ++ ++ update_coords (this, loc->latlon_valid, loc->latitude*180.0/M_PI, loc->longitude*180.0/M_PI); ++ ++ update_timezone (this, loc->name, loc->latitude, loc->longitude); ++ ++ intlclock_find_hide (button, this); ++} ++ ++static void ++location_row_activated (GtkTreeView *tree_view, ++ GtkTreePath *path, ++ GtkTreeViewColumn *column, ++ IntlClockUI *this) ++{ ++ run_find_location_save (tree_view, this); ++} ++ ++static void ++fill_location_tree (IntlClockUI *this) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); ++ GtkTreeView *tree; ++ GtkTreeModel *model; ++ GtkTreeViewColumn *column; ++ GtkCellRenderer *cell; ++ ++ tree = (GtkTreeView*)priv->location_tree; ++ ++ if (gtk_tree_view_get_model (tree) != NULL) ++ return; ++ ++ model = (GtkTreeModel*)gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); ++ gtk_tree_view_set_model (tree, model); ++ ++ cell = gtk_cell_renderer_text_new (); ++ column = gtk_tree_view_column_new_with_attributes ("not used", cell, ++ "text", GWEATHER_XML_COL_LOC, NULL); ++ gtk_tree_view_append_column (tree, column); ++ gtk_tree_view_set_expander_column (tree, column); ++ ++ g_signal_connect (tree, "row-activated", ++ G_CALLBACK (location_row_activated), this); ++ ++ gweather_xml_load_locations (tree, NULL); ++} ++ ++static void + run_prefs_locations_add (GtkButton *button, gpointer this) + { + IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); +@@ -2220,7 +2566,8 @@ run_prefs_locations_add (GtkButton *button, gpointer this) + GtkWidget *zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); + + fill_timezone_combo_from_location (this, zone_combo, NULL); +- ++ fill_location_tree (this); ++ + g_object_set_data (G_OBJECT (edit_window), "intlclock-location", NULL); + gtk_window_present (GTK_WINDOW (edit_window)); + } +@@ -2230,7 +2577,6 @@ run_prefs_locations_edit (GtkButton *button, gpointer this) + { + IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (this)); + +- GtkTreeModel *model = gtk_tree_view_get_model (priv->prefs_locations);; + GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->prefs_locations)); + + gtk_tree_selection_selected_foreach (sel, edit_tree_row, this); +@@ -2245,7 +2591,6 @@ run_prefs_edit_save (GtkButton *button, gpointer this) + IntlClockZoneTable *zones = intlclock_get_zonetable (priv->clock); + + IntlClockLocation *loc = g_object_get_data (G_OBJECT (edit_window), "intlclock-location"); +- + GtkWidget *zone_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-timezone-combo"); + GtkWidget *name_entry = glade_xml_get_widget (priv->glade_xml, "edit-location-name-entry"); + +@@ -2255,6 +2600,8 @@ run_prefs_edit_save (GtkButton *button, gpointer this) + GtkWidget *lon_combo = glade_xml_get_widget (priv->glade_xml, "edit-location-longitude-combo"); + + gchar *timezone_l10n = gtk_combo_box_get_active_text (GTK_COMBO_BOX (zone_combo)); ++ gchar *weather_code = g_object_get_data (G_OBJECT (edit_window), "weather-code"); ++ + IntlClockZoneInfo *info = intlclock_zonetable_get_l10n_zone (zones, timezone_l10n); + + if (!info) { +@@ -2281,9 +2628,11 @@ run_prefs_edit_save (GtkButton *button, gpointer this) + intlclock_location_set_timezone (loc, intlclock_zoneinfo_get_name (info)); + intlclock_location_set_name (loc, name); + intlclock_location_set_coords (loc, lat, lon); ++ intlclock_location_set_weather_code (loc, weather_code); + } else { + GList *locs; +- loc = intlclock_location_new (name, intlclock_zoneinfo_get_name (info), lat, lon); ++ ++ loc = intlclock_location_new (name, intlclock_zoneinfo_get_name (info), lat, lon, weather_code); + + locs = g_list_copy (intlclock_get_locations (priv->clock)); + locs = g_list_append (locs, loc); +@@ -2294,3 +2643,11 @@ run_prefs_edit_save (GtkButton *button, gpointer this) + + intlclock_edit_hide (edit_window, this); + } ++ ++void ++intlclock_ui_update_weather_icon (IntlClockUI *ui, GdkPixbuf *pixbuf) ++{ ++ IntlClockUIPrivate *priv = PRIVATE (INTLCLOCK_UI (ui)); ++ ++ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->panel_weather_icon), pixbuf); ++} +diff --git a/src/intlclock-ui.h b/src/intlclock-ui.h +index ecbee03..a10099a 100644 +--- a/src/intlclock-ui.h ++++ b/src/intlclock-ui.h +@@ -29,6 +29,8 @@ GType intlclock_ui_get_type (void); + + IntlClockUI *intlclock_ui_new (IntlClock *clock, PanelApplet *applet); + gboolean intlclock_ui_is_12hr (IntlClockUI *ui); ++void intlclock_ui_edit_locations (IntlClockUI *ui); ++void intlclock_ui_update_weather_icon (IntlClockUI *ui, GdkPixbuf *pixbuf); + + G_END_DECLS + #endif /* __INTLCLOCK_UI_H__ */ +diff --git a/src/intlclock-zonetable.c b/src/intlclock-zonetable.c +index a2a0b6f..e6e27cb 100644 +--- a/src/intlclock-zonetable.c ++++ b/src/intlclock-zonetable.c +@@ -27,8 +27,6 @@ typedef struct { + GHashTable *country_table; + } IntlClockZoneTablePrivate; + +-#define USE_CRIPPLED_ZONELIST 1 +- + /* Seeded with the list from Nat's Blackberry */ + char *available_zones[] = { + /* Eniwetok (-12) */ +diff --git a/src/intlclock.c b/src/intlclock.c +index 02f5b0a..552c45c 100644 +--- a/src/intlclock.c ++++ b/src/intlclock.c +@@ -32,6 +32,8 @@ typedef struct { + enum { + TICK, + LOCATIONS_CHANGED, ++ BLINK_LOCATION, ++ CURRENT_TIMEZONE_CHANGED, + LAST_SIGNAL + }; + +@@ -87,7 +89,25 @@ intlclock_class_init (IntlClockClass *this_class) + _intlclock_marshal_VOID__VOID, + G_TYPE_NONE, 0); + +- g_type_class_add_private (this_class, sizeof (IntlClockPrivate)); ++ intlclock_signals[BLINK_LOCATION] = g_signal_new ++ ("blink-location", ++ G_OBJECT_CLASS_TYPE (obj_class), ++ G_SIGNAL_RUN_FIRST, ++ G_STRUCT_OFFSET (IntlClockClass, blink_location), ++ NULL, NULL, ++ _intlclock_marshal_VOID__OBJECT, ++ G_TYPE_NONE, 1, INTLCLOCK_LOCATION_TYPE); ++ ++ intlclock_signals[CURRENT_TIMEZONE_CHANGED] = g_signal_new ++ ("current-timezone-changed", ++ G_OBJECT_CLASS_TYPE (obj_class), ++ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, ++ G_STRUCT_OFFSET (IntlClockClass, current_timezone_changed), ++ NULL, NULL, ++ _intlclock_marshal_VOID__VOID, ++ G_TYPE_NONE, 0); ++ ++ g_type_class_add_private (this_class, sizeof (IntlClockPrivate)); + } + + static void +@@ -133,7 +153,7 @@ intlclock_set_locations (IntlClock *this, GList *locations) + + priv->locations = locations; + +- g_signal_emit_by_name (this, "locations-changed"); ++ g_signal_emit (this, intlclock_signals[LOCATIONS_CHANGED], 0); + } + + GList * +@@ -202,7 +222,7 @@ intlclock_emit_tick (gpointer data) + IntlClock *this = INTLCLOCK (data); + IntlClockPrivate *priv = PRIVATE (this); + +- g_signal_emit_by_name (this, "tick"); ++ g_signal_emit (this, intlclock_signals[TICK], 0); + + if (priv->in_partial_timeout) { + intlclock_reset_timeout (this); +@@ -353,3 +373,9 @@ intlclock_free_locations (IntlClock *this) + g_list_free (priv->locations); + priv->locations = NULL; + } ++ ++void ++intlclock_blink_location (IntlClock *this, IntlClockLocation *loc) ++{ ++ g_signal_emit (this, intlclock_signals[BLINK_LOCATION], 0, loc); ++} +diff --git a/src/intlclock.h b/src/intlclock.h +index 3b0012c..20c681d 100644 +--- a/src/intlclock.h ++++ b/src/intlclock.h +@@ -27,6 +27,9 @@ typedef struct + + void (* tick) (IntlClock *clock); + void (* locations_changed) (IntlClock *clock); ++ void (* blink_location) (IntlClock *clock, IntlClockLocation *loc); ++ void (* current_timezone_changed) (IntlClock *clock); ++ + } IntlClockClass; + + GType intlclock_get_type (void); +@@ -35,6 +38,7 @@ IntlClock *intlclock_new (void); + + void intlclock_set_locations (IntlClock *this, GList *list); + GList *intlclock_get_locations (IntlClock *this); ++void intlclock_blink_location (IntlClock *this, IntlClockLocation *loc); + + IntlClockZoneTable *intlclock_get_zonetable (IntlClock *this); + gchar *intlclock_format_time (IntlClock *this, struct tm *now, +diff --git a/src/set-timezone.c b/src/set-timezone.c +new file mode 100644 +index 0000000..5c96149 +--- /dev/null ++++ b/src/set-timezone.c +@@ -0,0 +1,426 @@ ++/* -*- 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 ++#include ++ ++static DBusGConnection * ++get_session_bus (void) ++{ ++ GError *error; ++ static DBusGConnection *bus = NULL; ++ ++ if (bus == NULL) { ++ error = NULL; ++ bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); ++ if (bus == NULL) { ++ g_warning ("Couldn't connect to session bus: %s", ++ error->message); ++ g_error_free (error); ++ } ++ } ++ ++ return bus; ++} ++ ++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; ++} ++ ++static PolKitContext * ++get_pk_context (void) ++{ ++ static PolKitContext *pk_context = NULL; ++ ++ if (pk_context == NULL) { ++ pk_context = polkit_context_new (); ++ if (!polkit_context_init (pk_context, NULL)) { ++ polkit_context_unref (pk_context); ++ pk_context = NULL; ++ } ++ } ++ ++ return pk_context; ++} ++ ++gboolean ++set_system_timezone (const char *filename, GError **err) ++{ ++ DBusGConnection *session_bus; ++ DBusGConnection *system_bus; ++ DBusGProxy *mechanism_proxy; ++ DBusGProxy *polkit_gnome_proxy; ++ gboolean ret = FALSE; ++ ++ session_bus = get_session_bus (); ++ if (session_bus == NULL) ++ goto out; ++ ++ system_bus = get_system_bus (); ++ if (system_bus == NULL) ++ goto out; ++ ++ mechanism_proxy = dbus_g_proxy_new_for_name (system_bus, ++ "org.gnome.ClockApplet.Mechanism", ++ "/", ++ "org.gnome.ClockApplet.Mechanism"); ++ ++ polkit_gnome_proxy = dbus_g_proxy_new_for_name (session_bus, ++ "org.gnome.PolicyKit", ++ "/org/gnome/PolicyKit/Manager", ++ "org.gnome.PolicyKit.Manager"); ++ ++ if (filename != NULL) { ++ GError *error; ++ ++ g_debug ("Trying to set timezone '%s'", filename); ++ try_again: ++ error = NULL; ++ /* first, try to call into the mechanism */ ++ if (!dbus_g_proxy_call_with_timeout (mechanism_proxy, ++ "SetTimezone", ++ INT_MAX, ++ &error, ++ /* parameters: */ ++ G_TYPE_STRING, filename, ++ G_TYPE_INVALID, ++ /* return values: */ ++ G_TYPE_INVALID)) { ++ if (dbus_g_error_has_name (error, "org.gnome.ClockApplet.Mechanism.NotPrivileged")) { ++ char **tokens; ++ char *polkit_result_textual; ++ char *polkit_action; ++ gboolean gained_privilege; ++ ++ tokens = g_strsplit (error->message, " ", 2); ++ g_error_free (error); ++ if (g_strv_length (tokens) != 2) { ++ g_warning ("helper return string malformed"); ++ g_strfreev (tokens); ++ goto out; ++ } ++ polkit_action = tokens[0]; ++ polkit_result_textual = tokens[1]; ++ ++ g_debug ("helper refused; returned polkit_result='%s' and polkit_action='%s'", ++ polkit_result_textual, polkit_action); ++ ++ /* Now ask the user for auth... */ ++ if (!dbus_g_proxy_call_with_timeout (polkit_gnome_proxy, ++ "ShowDialog", ++ INT_MAX, ++ &error, ++ /* parameters: */ ++ G_TYPE_STRING, polkit_action, ++ G_TYPE_UINT, 0, /* X11 window ID; none */ ++ G_TYPE_INVALID, ++ /* return values: */ ++ G_TYPE_BOOLEAN, &gained_privilege, ++ G_TYPE_INVALID)) { ++ g_propagate_error (err, error); ++ g_strfreev (tokens); ++ goto out; ++ } ++ g_strfreev (tokens); ++ ++ if (gained_privilege) { ++ g_debug ("Gained privilege; trying to set timezone again"); ++ goto try_again; ++ } ++ ++ } else { ++ g_propagate_error (err, error); ++ } ++ goto out; ++ } ++ ++ g_debug ("Successfully set time zone to '%s'", filename); ++ } ++ ++ ret = TRUE; ++out: ++ g_object_unref (mechanism_proxy); ++ g_object_unref (polkit_gnome_proxy); ++ ++ return ret; ++} ++ ++static gint ++can_do (const gchar *pk_action_id) ++{ ++ DBusConnection *system_bus; ++ PolKitCaller *pk_caller; ++ PolKitAction *pk_action; ++ PolKitResult pk_result; ++ PolKitContext *pk_context; ++ DBusError dbus_error; ++ gint res = 0; ++ ++ system_bus = dbus_g_connection_get_connection (get_system_bus ()); ++ if (system_bus == NULL) ++ goto out; ++ ++ pk_context = get_pk_context (); ++ if (pk_context == NULL) ++ goto out; ++ ++ pk_caller = NULL; ++ pk_action = NULL; ++ ++ pk_action = polkit_action_new (); ++ polkit_action_set_action_id (pk_action, pk_action_id); ++ ++ dbus_error_init (&dbus_error); ++ pk_caller = polkit_caller_new_from_pid (system_bus, getpid (), &dbus_error); ++ if (pk_caller == NULL) { ++ fprintf (stderr, "cannot get caller from dbus name\n"); ++ goto out; ++ } ++ ++ pk_result = polkit_context_can_caller_do_action (pk_context, pk_action, pk_caller); ++ ++ switch (pk_result) { ++ default: ++ case POLKIT_RESULT_UNKNOWN: ++ case POLKIT_RESULT_NO: ++ res = 0; ++ break; ++ case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH: ++ case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_SESSION: ++ case POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_ALWAYS: ++ case POLKIT_RESULT_ONLY_VIA_SELF_AUTH: ++ case POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_SESSION: ++ case POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_ALWAYS: ++ res = 1; ++ break; ++ case POLKIT_RESULT_YES: ++ res = 2; ++ break; ++ } ++ ++out: ++ if (pk_action != NULL) ++ polkit_action_unref (pk_action); ++ if (pk_caller != NULL) ++ polkit_caller_unref (pk_caller); ++ ++ return res; ++} ++ ++gint ++can_set_system_timezone (void) ++{ ++ return can_do ("org.gnome.clockapplet.mechanism.settimezone"); ++} ++ ++gint ++can_set_system_time (void) ++{ ++ return can_do ("org.gnome.clockapplet.mechanism.settime"); ++} ++ ++typedef struct { ++ gint ref_count; ++ gint64 time; ++ 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); ++ } ++} ++ ++static void set_time_async (SetTimeCallbackData *data); ++ ++static void ++auth_notify (DBusGProxy *proxy, ++ DBusGProxyCall *call, ++ void *user_data) ++{ ++ SetTimeCallbackData *data = user_data; ++ GError *error = NULL; ++ gboolean gained_privilege; ++ ++ if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_BOOLEAN, &gained_privilege, G_TYPE_INVALID)) { ++ if (gained_privilege) ++ set_time_async (data); ++ } ++ else { ++ if (data->callback) ++ data->callback (data->data, error); ++ else ++ g_error_free (error); ++ } ++} ++ ++static void ++do_auth_async (const gchar *action, ++ const gchar *result, ++ SetTimeCallbackData *data) ++{ ++ DBusGConnection *bus; ++ DBusGProxy *proxy; ++ ++ g_debug ("helper refused; returned polkit_result='%s' and polkit_action='%s'", ++ result, action); ++ ++ /* Now ask the user for auth... */ ++ bus = get_session_bus (); ++ if (bus == NULL) ++ return; ++ ++ proxy = dbus_g_proxy_new_for_name (bus, ++ "org.gnome.PolicyKit", ++ "/org/gnome/PolicyKit/Manager", ++ "org.gnome.PolicyKit.Manager"); ++ ++ data->ref_count++; ++ dbus_g_proxy_begin_call_with_timeout (proxy, ++ "ShowDialog", ++ auth_notify, ++ data, free_data, ++ INT_MAX, ++ G_TYPE_STRING, action, ++ G_TYPE_UINT, 0, ++ G_TYPE_INVALID); ++} ++ ++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 (dbus_g_error_has_name (error, "org.gnome.ClockApplet.Mechanism.NotPrivileged")) { ++ gchar **tokens; ++ ++ tokens = g_strsplit (error->message, " ", 2); ++ g_error_free (error); ++ if (g_strv_length (tokens) == 2) ++ do_auth_async (tokens[0], tokens[1], data); ++ else ++ g_warning ("helper return string malformed"); ++ g_strfreev (tokens); ++ } ++ 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; ++ DBusGProxyCall *call; ++ ++ bus = get_system_bus (); ++ if (bus == NULL) ++ return; ++ ++ proxy = dbus_g_proxy_new_for_name (bus, ++ "org.gnome.ClockApplet.Mechanism", ++ "/", ++ "org.gnome.ClockApplet.Mechanism"); ++ ++ data->ref_count++; ++ 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); ++} ++ ++void ++set_system_time_async (gint64 time, ++ GFunc callback, ++ gpointer d, ++ GDestroyNotify notify) ++{ ++ SetTimeCallbackData *data; ++ ++ if (time == -1) ++ return; ++ ++ data = g_new (SetTimeCallbackData, 1); ++ data->ref_count = 1; ++ data->time = time; ++ data->callback = callback; ++ data->data = d; ++ data->notify = notify; ++ ++ set_time_async (data); ++ free_data (data); ++} +diff --git a/src/set-timezone.h b/src/set-timezone.h +new file mode 100644 +index 0000000..c71622c +--- /dev/null ++++ b/src/set-timezone.h +@@ -0,0 +1,36 @@ ++/* -*- 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 ++ ++gboolean set_system_timezone (const char *filename, ++ GError **err); ++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); ++ ++#endif -- cgit