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 @@
<Root>
<popups>
<popup name="button3">
+ <menuitem name="Clock Copy Time Item" verb="ClockCopyTime" _label="Copy _Time"
+ pixtype="stock" pixname="gtk-copy"/>
+ <menuitem name="Clock Copy Date Item" verb="ClockCopyDate" _label="Copy _Date"
+ pixtype="stock" pixname="gtk-copy"/>
+ <separator/>
<menuitem name="Clock Configure Item" verb="IntlClockConfig"
- _label="Cha_nge Date or Time"
- pixtype="stock" pixname="gtk-preferences"/>
+ _label="Ad_just Date & Time"
+ pixtype="stock" pixname="gtk-preferences"/>
<menuitem name="Clock Preferences Item" verb="IntlClockPreferences" _label="_Preferences"
pixtype="stock" pixname="gtk-properties"/>
</popup>
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 @@
</oaf_attribute>
<oaf_attribute name="name" type="string" value="International Clock"/>
<oaf_attribute name="description" type="string" value="International Clock applet for the GNOME panel"/>
- <oaf_attribute name="panel:icon" type="string" value="clock.png"/>
+ <oaf_attribute name="panel:icon" type="string" value="gnome-panel-clock"/>
</oaf_server>
<oaf_server iid="OAFIID:GNOME_ClockApplet"
diff --git a/data/intlclock.glade b/data/intlclock.glade
index e7b8c01..626d835 100644
--- a/data/intlclock.glade
+++ b/data/intlclock.glade
@@ -21,12 +21,13 @@
<child>
<widget class="GtkVBox" id="vbox1">
+ <property name="border_width">6</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
- <widget class="GtkNotebook" id="notebook1">
+ <widget class="GtkNotebook" id="notebook">
<property name="border_width">6</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -37,194 +38,35 @@
<property name="enable_popup">False</property>
<child>
- <widget class="GtkTable" id="table1">
- <property name="border_width">6</property>
+ <widget class="GtkVBox" id="vbox17">
+ <property name="border_width">12</property>
<property name="visible">True</property>
- <property name="n_rows">4</property>
- <property name="n_columns">3</property>
<property name="homogeneous">False</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
+ <property name="spacing">18</property>
<child>
- <widget class="GtkLabel" id="label11">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Clock options:</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label12">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label13">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label14">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label15">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="seconds_check">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Show s_econds</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">3</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox3">
+ <widget class="GtkVBox" id="vbox18">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
- <widget class="GtkRadioButton" id="12hr_radio">
+ <widget class="GtkLabel" id="label210">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">12 _hour format</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
+ <property name="label" translatable="yes"><b>Clock Options</b></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
@@ -234,138 +76,150 @@
</child>
<child>
- <widget class="GtkRadioButton" id="24hr_radio">
+ <widget class="GtkHBox" id="hbox48">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">24 h_our format</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- <property name="group">12hr_radio</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label211">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox19">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox49">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">13</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="12hr_radio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">12 _hour format</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="24hr_radio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">24 h_our format</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">12hr_radio</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="date_check">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Show the _date</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="seconds_check">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Show _seconds</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
</packing>
</child>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="date_check">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Show the _date</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label16">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label17">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label201">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
</packing>
</child>
</widget>
@@ -376,7 +230,7 @@
</child>
<child>
- <widget class="GtkLabel" id="label1">
+ <widget class="GtkLabel" id="label209">
<property name="visible">True</property>
<property name="label" translatable="yes">General</property>
<property name="use_underline">False</property>
@@ -399,332 +253,105 @@
</child>
<child>
- <widget class="GtkTable" id="table5">
- <property name="border_width">6</property>
+ <widget class="GtkVBox" id="vbox24">
+ <property name="border_width">12</property>
<property name="visible">True</property>
- <property name="n_rows">8</property>
- <property name="n_columns">4</property>
<property name="homogeneous">False</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="label36">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">3</property>
- <property name="right_attach">4</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label37">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">3</property>
- <property name="right_attach">4</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
+ <property name="spacing">18</property>
<child>
- <widget class="GtkScrolledWindow" id="scrolledwindow2">
+ <widget class="GtkHBox" id="hbox54">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
- <property name="vscrollbar_policy">GTK_POLICY_NEVER</property>
- <property name="shadow_type">GTK_SHADOW_IN</property>
- <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
<child>
- <widget class="GtkTreeView" id="cities_list">
+ <widget class="GtkScrolledWindow" id="scrolledwindow10">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="headers_visible">False</property>
- <property name="rules_hint">False</property>
- <property name="reorderable">False</property>
- <property name="enable_search">True</property>
- <property name="fixed_height_mode">False</property>
- <property name="hover_selection">False</property>
- <property name="hover_expand">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="cities_list">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">True</property>
+ </widget>
+ </child>
</widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
</child>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">3</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">8</property>
- <property name="x_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkAlignment" id="alignment6">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xscale">0</property>
- <property name="yscale">1</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
<child>
- <widget class="GtkVBox" id="vbox2">
+ <widget class="GtkVButtonBox" id="vbuttonbox2">
<property name="visible">True</property>
- <property name="homogeneous">False</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
<property name="spacing">6</property>
<child>
- <widget class="GtkLabel" id="label39">
+ <widget class="GtkButton" id="prefs-locations-add-button">
+ <property name="width_request">24</property>
+ <property name="height_request">25</property>
<property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-add</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
</widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
</child>
<child>
- <widget class="GtkVButtonBox" id="vbuttonbox1">
+ <widget class="GtkButton" id="prefs-locations-edit-button">
+ <property name="width_request">24</property>
+ <property name="height_request">24</property>
<property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_START</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkButton" id="prefs-locations-add-button">
- <property name="width_request">24</property>
- <property name="height_request">25</property>
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-add</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="prefs-locations-edit-button">
- <property name="width_request">24</property>
- <property name="height_request">24</property>
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-edit</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="prefs-locations-remove-button">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-remove</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- </child>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-edit</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
</widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
</child>
<child>
- <widget class="GtkLabel" id="label38">
+ <widget class="GtkButton" id="prefs-locations-remove-button">
<property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-remove</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
</widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
</child>
</widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
</child>
</widget>
<packing>
- <property name="left_attach">3</property>
- <property name="right_attach">4</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">8</property>
- <property name="x_options"></property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="show_map_check">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Show the world _map in the clock</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label41">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label160">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkCheckButton" id="show_locations_check">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">S_how locations in the clock</property>
- <property name="use_underline">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <property name="active">False</property>
- <property name="inconsistent">False</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">3</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
</packing>
</child>
</widget>
@@ -735,7 +362,7 @@
</child>
<child>
- <widget class="GtkLabel" id="label2">
+ <widget class="GtkLabel" id="label220">
<property name="visible">True</property>
<property name="label" translatable="yes">Locations</property>
<property name="use_underline">False</property>
@@ -772,95 +399,20 @@
<property name="spacing">0</property>
<child>
- <widget class="GtkHButtonBox" id="hbuttonbox2">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property>
- <property name="spacing">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHButtonBox" id="hbuttonbox3">
+ <widget class="GtkHButtonBox" id="hbuttonbox22">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<property name="spacing">6</property>
<child>
- <widget class="GtkButton" id="prefs-time-settings-button">
+ <widget class="GtkButton" id="time-settings-button">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
+ <property name="label" translatable="yes">Time Settings</property>
+ <property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
-
- <child>
- <widget class="GtkAlignment" id="alignment5">
- <property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
-
- <child>
- <widget class="GtkHBox" id="hbox8">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">2</property>
-
- <child>
- <widget class="GtkImage" id="image5">
- <property name="visible">True</property>
- <property name="stock">gtk-properties</property>
- <property name="icon_size">4</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label35">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Time _Settings</property>
- <property name="use_underline">True</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
</widget>
</child>
@@ -910,13 +462,13 @@
<child>
<widget class="GtkVBox" id="vbox14">
+ <property name="border_width">12</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
- <property name="spacing">0</property>
+ <property name="spacing">24</property>
<child>
<widget class="GtkTable" id="table23">
- <property name="border_width">6</property>
<property name="visible">True</property>
<property name="n_rows">1</property>
<property name="n_columns">3</property>
@@ -926,7 +478,6 @@
<child>
<widget class="GtkVBox" id="vbox15">
- <property name="border_width">6</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
@@ -974,62 +525,6 @@
<property name="column_spacing">6</property>
<child>
- <widget class="GtkLabel" id="label174">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Timezone:</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label175">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Location Name:</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
<widget class="GtkVBox" id="vbox16">
<property name="visible">True</property>
<property name="homogeneous">True</property>
@@ -1070,45 +565,6 @@
</child>
<child>
- <widget class="GtkComboBoxEntry" id="edit-location-timezone-combo">
- <property name="visible">True</property>
- <property name="items">Dummy Item</property>
- <property name="add_tearoffs">False</property>
- <property name="has_frame">True</property>
- <property name="focus_on_click">True</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">4</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options">fill</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkEntry" id="edit-location-name-entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">True</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char">●</property>
- <property name="activates_default">False</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">4</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
<widget class="GtkLabel" id="label208">
<property name="visible">True</property>
<property name="label" translatable="yes">Longitude:</property>
@@ -1145,7 +601,7 @@
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">●</property>
+ <property name="invisible_char">•</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -1258,7 +714,7 @@ South</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
- <property name="invisible_char">●</property>
+ <property name="invisible_char">•</property>
<property name="activates_default">False</property>
</widget>
<packing>
@@ -1269,6 +725,131 @@ South</property>
<property name="y_options"></property>
</packing>
</child>
+
+ <child>
+ <widget class="GtkLabel" id="label175">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Location Name:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label174">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Timezone:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox55">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkEntry" id="edit-location-name-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">•</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="find-location-button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Find...</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBoxEntry" id="edit-location-timezone-combo">
+ <property name="visible">True</property>
+ <property name="items">Dummy Item</property>
+ <property name="add_tearoffs">False</property>
+ <property name="has_frame">True</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -1294,60 +875,33 @@ South</property>
</child>
<child>
- <widget class="GtkHBox" id="hbox40">
- <property name="border_width">6</property>
+ <widget class="GtkHButtonBox" id="hbuttonbox20">
<property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">0</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <property name="spacing">6</property>
<child>
- <widget class="GtkHButtonBox" id="hbuttonbox12">
+ <widget class="GtkButton" id="edit-location-cancel-button">
<property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property>
- <property name="spacing">0</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
</widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
</child>
<child>
- <widget class="GtkHButtonBox" id="hbuttonbox18">
+ <widget class="GtkButton" id="edit-location-ok-button">
<property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkButton" id="edit-location-cancel-button">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- </child>
-
- <child>
- <widget class="GtkButton" id="edit-location-ok-button">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- </widget>
- </child>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
</widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
</child>
</widget>
<packing>
@@ -1723,4 +1277,580 @@ South</property>
</child>
</widget>
+<widget class="GtkWindow" id="find-location-window">
+ <property name="title" translatable="yes"></property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox25">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">24</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox26">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow11">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="find-location-tree">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">False</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox56">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label221">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Find:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">find-location-entry</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="find-location-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">•</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="find-next-location-button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment31">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox57">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image29">
+ <property name="visible">True</property>
+ <property name="stock">gtk-find</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label222">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Find _Next</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox19">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="find-location-cancel-button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="find-location-ok-button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkWindow" id="set-time-window">
+ <property name="border_width">12</property>
+ <property name="title" translatable="yes">Time Settings</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox20">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label212">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>Time Settings</b></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="time_settings_box">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label217">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox52">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkCalendar" id="calendar">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="display_options">GTK_CALENDAR_SHOW_HEADING</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox22">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label218">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Current Time:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label219">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Time:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox23">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="current_time_label">
+ <property name="visible">True</property>
+ <property name="label">23:59:59</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox53">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkSpinButton" id="hours_spin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">True</property>
+ <property name="adjustment">23 0 23 1 12 12</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="minutes_spin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">True</property>
+ <property name="adjustment">59 0 59 1 30 30</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="seconds_spin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">True</property>
+ <property name="adjustment">59 0 59 1 30 30</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox58">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox21">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkButton" id="cancel-set-time-button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="set-time-button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Set System Time</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
</glade-interface>
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 @@
</schema>
<schema>
- <key>/schemas/apps/intlclock_applet/prefs/show_locations</key>
+ <key>/schemas/apps/intlclock_applet/prefs/cities</key>
+ <owner>clock-applet</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+ <default>[]</default>
+ <locale name="C">
+ <short>List of cities for the clock.</short>
+ <long>
+ List of cities to display in the international clock.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/intlclock_applet/prefs/expand_locations</key>
<owner>clock-applet</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
- <short>Show other locations in clock</short>
+ <short>Expand the location section in clock</short>
<long>
- If true, show a list of locations in the international clock.
+ If true, expand the list of locations in the international clock.
</long>
</locale>
</schema>
<schema>
- <key>/schemas/apps/intlclock_applet/prefs/show_map</key>
+ <key>/schemas/apps/intlclock_applet/prefs/expand_tasks</key>
<owner>clock-applet</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
- <short>Show world map in clock</short>
+ <short>Expand the tasks section in clock</short>
<long>
- If true, show the world map in the international clock.
+ If true, expand the list of tasks in the international clock.
</long>
</locale>
</schema>
<schema>
- <key>/schemas/apps/intlclock_applet/prefs/cities</key>
+ <key>/schemas/apps/intlclock_applet/prefs/expand_appointments</key>
<owner>clock-applet</owner>
- <type>list</type>
- <list_type>string</list_type>
- <default>[]</default>
+ <type>bool</type>
+ <default>true</default>
<locale name="C">
- <short>List of cities for the clock.</short>
+ <short>Expand the appointments section in clock</short>
<long>
- List of cities to display in the international clock.
+ If true, expand the list of appointments in the international clock.
</long>
</locale>
</schema>
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 <kenneth@gnu.org>
-# Darin Adler <darin@bentspoon.com>
-#
-
-## 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 <xml-i18n-tools\@gnome.org>.
-_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 = <IN>;
- }
-
- &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;
- 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 . "</$type>";
- } 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;
- $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);
-
-# <foo><!-- comment --><head id="a">Hello <em>there</em></head><bar>Howdy<ref/></bar>do</foo>
-# 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 =~ /
- <locale\ name="C">\s*
- (<default>\s*(?:<!--([^>]*?)-->\s*)?(.*?)\s*<\/default>\s*)?
- (<short>\s*(?:<!--([^>]*?)-->\s*)?(.*?)\s*<\/short>\s*)?
- (<long>\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>(..[^<]*)<\/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 =~ /<atkaction\s+action_name="([^>]*)"\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 <mjs@noisehavoc.org>
-# Kenneth Christiansen <kenneth@gnu.org>
-# Darin Adler <darin@bentspoon.com>
-#
-# Proper XML UTF-8'ification written by Cyrille Chepelov <chepelov@calixo.net>
-#
-
-## 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 <xml-i18n-tools\@gnome.org>.
-_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 (<CHARSET_ALIAS>)
- {
- 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 (<IN_PO_FILE>)
- {
- ## 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 = <CACHE>;
- }
- 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 (<PO_FILE>)
- {
- $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/</</g;
-
- return $_;
-}
-
-# entity_encode: (string)
-#
-# Encode the given string to XML format (encode '<' etc).
-
-sub entity_encode
-{
- my ($pre_encoded) = @_;
-
- my @list_of_chars = unpack ('C*', $pre_encoded);
-
- # with UTF-8 we only encode minimalistic
- return join ('', map (&entity_encode_int_minimalist, @list_of_chars));
-}
-
-sub entity_encode_int_minimalist
-{
- return """ if $_ == 34;
- return "&" if $_ == 38;
- return "'" if $_ == 39;
- return "<" if $_ == 60;
- return chr $_;
-}
-
-sub entity_encoded_translation
-{
- my ($lang, $string) = @_;
-
- my $translation = $translations{$lang, $string};
- return $string if !$translation;
- return entity_encode ($translation);
-}
-
-## XML (bonobo-activation specific) merge code
-
-sub ba_merge_translations
-{
- my $source;
-
- {
- local $/; # slurp mode
- open INPUT, "<$FILE" or die "can't open $FILE: $!";
- $source = <INPUT>;
- 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 . "</$type>";
- } 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 = "<root>$fragment</root>";
- 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 "</$nodename>";
-
- 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 "</$nodename>";
- }
- } 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 "</$nodename>";
- }
- }
- }
-
- } 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 "</$nodename>";
- } 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);
-
-# <foo><head id="a">Hello <em>there</em></head><bar>Howdy<ref/></bar>do</foo>
-# 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{<?xml version="1.0" encoding="UTF-8"?>\n};
- {
- local $/;
- open DOCINPUT, "<${FILE}" or die;
- $source = <DOCINPUT>;
- close DOCINPUT;
- }
- if ($source =~ /(<!DOCTYPE.*\[.*\]\s*>)/s)
- {
- print $fh "$1\n";
- }
- elsif ($source =~ /(<!DOCTYPE[^>]*>)/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 (<INPUT>)
- {
- 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 (<INPUT>)
- {
- 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 = <INPUT>;
- 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 <foo/>.
- $source =~ s|<\s*_($w+)\s*/>|<$1/>|g;
-
- while ($source =~ s/
- (.*?)
- (\s+)(<locale\ name="C">(\s*)
- (<default>\s*(?:<!--[^>]*?-->\s*)?(.*?)\s*<\/default>)?(\s*)
- (<short>\s*(?:<!--[^>]*?-->\s*)?(.*?)\s*<\/short>)?(\s*)
- (<long>\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<locale name=\"$lang\">";
-
- print OUTPUT "$default_spaces";
-
- if ($default_translation)
- {
- $default_translation = entity_encode($default_translation);
- print OUTPUT "<default>$default_translation</default>";
- }
-
- print OUTPUT "$short_spaces";
-
- if ($short_translation)
- {
- $short_translation = entity_encode($short_translation);
- print OUTPUT "<short>$short_translation</short>";
- }
-
- print OUTPUT "$long_spaces";
-
- if ($long_translation)
- {
- $long_translation = entity_encode($long_translation);
- print OUTPUT "<long>$long_translation</long>";
- }
-
- print OUTPUT "$locale_end_spaces</locale>";
- }
- }
-
- 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 = <INPUT>;
- 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 <kenneth@gnu.org>
-# Maciej Stachowiak
-# Darin Adler <darin@bentspoon.com>
-
-## 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 <xml-i18n-tools\@gnome.org>.
-_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*$)/, <POTFILES>;
- 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 (<FILE>)
- {
- 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 (<FILE>)
- {
- # 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 (<FILE>)
- {
- # 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 (<FILE>)
- {
- 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 (<FILE>)
- {
- 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 (<INFILE>)
- {
- 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 (<CONF>)
- {
- 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, "<Makevars") || die "can't open Makevars: $!";
-
- while (<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, "<Makefile") || return;
-
- while (<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 = <IN>;
- 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, "<Makevars") || (open(IN, "<Makefile.in.in") && ($varname = "XGETTEXT_KEYWORDS")) || return $keywords;
- seek (IN, 0, 0);
- local $/; # slurp mode
- $make_source = <IN>;
- close IN;
- }
-
- $keywords = $1 if $make_source =~ /^$varname[ ]*=\[?([^\n\]]+)/m;
-
- return $keywords;
-}
-
-sub FindMakevarsDomain
-{
-
- my $domain = "";
- my $makevars_source; {
- local (*IN);
- open (IN, "<Makevars") || return $domain;
- seek (IN, 0, 0);
- local $/; # slurp mode
- $makevars_source = <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, "<Makevars") || return undef;
- seek (IN, 0, 0);
- local $/; # slurp mode
- $makevars_source = <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 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="10"
+ height="10"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.45.1"
+ sodipodi:docbase="/home/mclasen/Desktop"
+ sodipodi:docname="star.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1"
+ inkscape:cx="88.125"
+ inkscape:cy="-22.797357"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ inkscape:window-width="1003"
+ inkscape:window-height="824"
+ inkscape:window-x="93"
+ inkscape:window-y="30"
+ width="10px"
+ height="10px" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-164.31866,-172.88433)">
+ <path
+ sodipodi:type="star"
+ style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:10.30000114;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path2160"
+ sodipodi:sides="5"
+ sodipodi:cx="311.42856"
+ sodipodi:cy="320.93362"
+ sodipodi:r1="121.8637"
+ sodipodi:r2="42.747437"
+ sodipodi:arg1="1.0073988"
+ sodipodi:arg2="1.6371268"
+ inkscape:flatsided="false"
+ inkscape:rounded="0"
+ inkscape:randomized="0"
+ d="M 376.51129,423.96274 L 308.59518,363.58706 L 233.55372,414.66873 L 269.98717,331.41956 L 198.21652,275.83599 L 288.64975,284.76085 L 319.33452,199.32664 L 338.79187,288.09169 L 429.52674,290.87401 L 351.11882,336.80896 L 376.51129,423.96274 z "
+ transform="matrix(3.8213745e-2,-2.1588882e-2,2.2396111e-2,3.6200569e-2,150.72076,172.68179)" />
+ </g>
+</svg>
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 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="7"
+ height="7"
+ id="svg6063"
+ sodipodi:version="0.32"
+ inkscape:version="0.45.1"
+ version="1.0"
+ sodipodi:docbase="/home/mclasen/Desktop/intlclock/pixmaps"
+ sodipodi:docname="intlclock-map-location-hilight.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/home/garrett/Desktop/dot.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs6065">
+ <linearGradient
+ id="linearGradient7251">
+ <stop
+ style="stop-color:#e1d9dc;stop-opacity:1;"
+ offset="0"
+ id="stop7253" />
+ <stop
+ id="stop3143"
+ offset="0.5"
+ style="stop-color:#e3bfca;stop-opacity:1;" />
+ <stop
+ style="stop-color:#3d0e1a;stop-opacity:1;"
+ offset="1"
+ id="stop7255" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.627417"
+ inkscape:cx="2.5000319"
+ inkscape:cy="2.5000319"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ inkscape:window-width="872"
+ inkscape:window-height="750"
+ inkscape:window-x="0"
+ inkscape:window-y="30" />
+ <metadata
+ id="metadata6068">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-474.64282,-409.86216)">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:13.16123206;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path7259"
+ sodipodi:cx="-418.5"
+ sodipodi:cy="-489.5"
+ sodipodi:rx="39.5"
+ sodipodi:ry="39.5"
+ d="M -379 -489.5 A 39.5 39.5 0 1 1 -458,-489.5 A 39.5 39.5 0 1 1 -379 -489.5 z"
+ transform="matrix(5.4243529e-2,8.5329805e-4,-8.5329805e-4,5.4243529e-2,499.42608,439.2715)"
+ inkscape:export-filename="/home/garrett/Desktop/map-new.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ </g>
+</svg>
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 <drepper@gnu.ai.mit.edu>
-#
-# 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 <otaylor@redhat.com> to use GETTEXT_PACKAGE
-# instead of PACKAGE and to look for po2tbl in ./ not in intl/
-#
-# - Modified by jacob berkman <jacob@ximian.com> to install
-# Makefile.in.in and po2tbl.sed.in for use with glib-gettextize
-#
-# - Modified by Rodney Dawes <dobey@novell.com> 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
+ * <name> elements within a parent element, they must come first and be
+ * grouped together.
+ * The format is as follows:
+ *
+ * <gweather format="1.0">
+ * <region>
+ * <name>Name of the region</name>
+ * <name xml:lang="xx">Translated Name</name>
+ * <name xml:lang="zz">Another Translated Name</name>
+ * <country>
+ * <name>Name of the country</name>
+ * <location>
+ * <name>Name of the location</name>
+ * <code>IWIN code</code>
+ * <zone>Forecast code (North America, Australia, UK only)</zone>
+ * <radar>Weather.com radar map code (North America only)</radar>
+ * <coordinates>Latitude and longitude as DD-MM[-SS][H] pair</coordinates>
+ * </location>
+ * <state>
+ * <location>
+ * ....
+ * </location>
+ * <city>
+ * <name>Name of city with multiple locations</city>
+ * <zone>Forecast code</zone>
+ * <radar>Radar Map code</radar>
+ * <location>
+ * ...
+ * </location>
+ * </city>
+ * </state>
+ * </country>
+ * </region>
+ * <gweather>
+ *
+ * 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 <string.h>
+#include <math.h>
+#include <locale.h>
+#include <gtk/gtk.h>
+#include <libxml/xmlreader.h>
+
+#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 <name> 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 <gweather> 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 <gtk/gtk.h>
+#include <libgweather/weather.h>
+
+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 <gtk/gtk.h>
#include <string.h>
#include <time.h>
+#include <gconf/gconf-client.h>
+#include <panel-applet-gconf.h>
#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 ("<b>%s</b>", 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 ("<small>%s</small>", 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 <glib.h>
#include <gtk/gtk.h>
@@ -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 ?
+ _("<small>Set...</small>") :
+ _("<small>Set</small>"));
+ 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 ("<b>%s</b>\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 <config.h>
@@ -13,9 +12,16 @@
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
+#include <math.h>
#include <glib.h>
#include <libgnome/gnome-i18n.h>
+#include <libgnomevfs/gnome-vfs.h>
+
+#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 <time.h>
#include <glib.h>
#include <glib-object.h>
+#include <libgweather/weather.h>
#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 <glib-object.h>
-
-
-#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 <glib-object.h>
-
-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 <jwz@lucid.com>
- *
- * 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 <jrb@redhat.com>
+ * Matthias Clasen <mclasen@redhat.com>
*/
-
-#include <assert.h>
-#include <math.h>
+
#include <time.h>
+#include <gtk/gtk.h>
+#include <math.h>
-#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 <libgnome/gnome-i18n.h>
#include <locale.h>
#include <math.h>
+#include <time.h>
#include <panel-applet-gconf.h>
#include <stdlib.h>
#include <string.h>
@@ -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
- ("<location name=\"%s\" timezone=\"%s\" latitude=\"%f\" longitude=\"%f\" />",
+ ("<location name=\"%s\" timezone=\"%s\" latitude=\"%f\" longitude=\"%f\" code=\"%s\"/>",
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 <david@fubar.dk>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <polkit/polkit.h>
+#include <polkit-dbus/polkit-dbus.h>
+
+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 <david@fubar.dk>
+ *
+ * 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 <time.h>
+
+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