Index: location_ip.cpp
===================================================================
--- location_ip.cpp	(revision 1080874)
+++ location_ip.cpp	(working copy)
@@ -61,7 +61,6 @@
 
         // ordering of first three to preserve backwards compatibility
 
-        outd["accuracy"] = 40000;
         outd["country"] = country;
         outd["country code"] = countryCode;
         outd["city"] = city;
@@ -75,7 +74,8 @@
 Ip::Ip(QObject* parent, const QVariantList& args)
     : GeolocationProvider(parent, args), d(new Private())
 {
-    setUpdateTriggers(SourceEvent | NetworkConnected);
+    setUpdateTriggers(NetworkConnected);
+    setAccuracy(40000);
 }
 
 Ip::~Ip()
Index: geolocation.cpp
===================================================================
--- geolocation.cpp	(revision 1080874)
+++ geolocation.cpp	(working copy)
@@ -26,7 +26,7 @@
 
 Geolocation::Geolocation(QObject* parent, const QVariantList& args)
     : Plasma::DataEngine(parent, args),
-      m_networkStatus(false)
+      m_networkUp(false)
 {
     Q_UNUSED(args)
     setMinimumPollingInterval(500);
@@ -39,7 +39,12 @@
 
 void Geolocation::init()
 {
-    m_networkStatus = Solid::Networking::status();
+    int networkStatus = Solid::Networking::status();
+    if (networkStatus == Solid::Networking::Connected || networkStatus == Solid::Networking::Unknown) {
+        m_networkUp = true;
+    } else {
+        m_networkUp = false;
+    }
 
     //TODO: should this be delayed even further, e.g. when the source is requested?
     const KService::List offers = KServiceTypeTrader::self()->query("Plasma/GeolocationProvider");
@@ -85,7 +90,7 @@
     bool changed = false;
 
     foreach (GeolocationProvider *plugin, m_plugins) {
-        changed = plugin->requestUpdate(triggers) || changed;
+        changed = plugin->requestUpdate(triggers, m_networkUp) || changed;
     }
 
     if (changed) {
@@ -97,7 +102,6 @@
 
 bool Geolocation::sourceRequestEvent(const QString &name)
 {
-    kDebug() << name;
     if (name == SOURCE) {
         updatePlugins(GeolocationProvider::ForcedUpdate);
         setData(SOURCE, m_data);
@@ -109,9 +113,12 @@
 
 void Geolocation::networkStatusChanged()
 {
-    m_networkStatus = Solid::Networking::status();
-    if (m_networkStatus == Solid::Networking::Connected || m_networkStatus == Solid::Networking::Unknown) {
+    int networkStatus = Solid::Networking::status();
+    if (networkStatus == Solid::Networking::Connected || networkStatus == Solid::Networking::Unknown) {
+        m_networkUp = true;
         updatePlugins(GeolocationProvider::NetworkConnected);
+    } else {
+        m_networkUp = false;
     }
 }
 
@@ -120,7 +127,7 @@
     m_data.clear();
     m_accuracy.clear();
 
-    provider->requestUpdate(GeolocationProvider::ForcedUpdate);
+    provider->requestUpdate(GeolocationProvider::ForcedUpdate, m_networkUp);
 
     bool changed = false;
     foreach (GeolocationProvider *plugin, m_plugins) {
@@ -139,6 +146,12 @@
 
 void Geolocation::actuallySetData()
 {
+    if (m_latitude != m_data["latitude"].toString() ||
+        m_longitude != m_data["longitude"].toString()) {
+        m_latitude = m_data["latitude"].toString();
+        m_longitude = m_data["longitude"].toString();
+        updatePlugins(GeolocationProvider::CoordinatesChanged);
+    }
     setData(SOURCE, m_data);
 }
 
Index: location_name.cpp
===================================================================
--- location_name.cpp	(revision 0)
+++ location_name.cpp	(revision 0)
@@ -0,0 +1,171 @@
+/*
+ *   Copyright (C) 2009 Andrew Coles  <andrew.coles@yahoo.co.uk>
+ *   Copyright (C) 2009 2009 Petri Damstén <damu@iki.fi>
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License as
+ *   published by the Free Software Foundation; either version 2 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "location_name.h"
+#include <KJob>
+#include <KIO/Job>
+#include <KIO/TransferJob>
+
+#include <QtXml/QXmlStreamReader>
+
+class Name::Private
+{
+public:
+    QXmlStreamReader m_xmlReader;
+    double lastLongitude;
+    double lastLatitude;
+    bool guardPlaceNameCheck;
+
+    Private()
+        : lastLongitude(-1.0)
+        , lastLatitude(-1.0)
+    {}
+
+    void populateDataEngineData(Plasma::DataEngine::Data & outd)
+    {
+        QString country, countryCode, city;
+        while (!m_xmlReader.atEnd()) {
+            m_xmlReader.readNext();
+            if (m_xmlReader.isEndElement() && m_xmlReader.name() == "geoname") {
+                break;
+            }
+
+            if (m_xmlReader.isStartElement()) {
+                if (m_xmlReader.name() == "countryCode") {
+                    countryCode = m_xmlReader.readElementText();
+                } else if (m_xmlReader.name() == "countryName") {
+                    country = m_xmlReader.readElementText();
+                } else if (m_xmlReader.name() == "name") {
+                    city = m_xmlReader.readElementText();
+                } else { // for the other fields
+                    m_xmlReader.readElementText();
+                }
+            }
+        }
+
+        // ordering of first three to preserve backwards compatibility
+        outd["country"] = country;
+        outd["country code"] = countryCode;
+        outd["city"] = city;
+    }
+};
+
+Name::Name(QObject* parent, const QVariantList& args)
+    : GeolocationProvider(parent, args)
+    , d(new Private())
+{
+    setUpdateTriggers(CoordinatesChanged | NetworkConnected);
+    setAccuracy(40000);
+}
+
+Name::~Name()
+{
+    delete d;
+}
+
+void Name::update()
+{
+    bool success;
+    const double latitude = data("latitude").toDouble(&success);
+    if (!success) {
+        setData(Plasma::DataEngine::Data());
+        return;
+    }
+
+    const double longitude = data("longitude").toDouble(&success);
+    if (!success) {
+        setData(Plasma::DataEngine::Data());
+        return;
+    }
+
+    bool refreshLocation = false;
+
+    if (d->lastLongitude < 0) {
+        refreshLocation = true;
+        d->lastLatitude = latitude;
+        d->lastLongitude = longitude;
+    } else {
+        const double xChange = 69.1 * (latitude - d->lastLatitude);
+        const double yChange = 53.0 * (longitude - d->lastLongitude);
+
+        if ((xChange * xChange + yChange * yChange) > 25) {  // if we have moved > 5 miles
+            d->lastLatitude = latitude;
+            d->lastLongitude = longitude;
+            refreshLocation = true;
+        }
+    }
+
+    if (refreshLocation) {
+        d->m_xmlReader.clear();
+
+        KIO::TransferJob *job = KIO::get(
+                KUrl(QString("http://ws.geonames.org/findNearbyPlaceName?lat=%1&lng=%2")
+                        .arg(latitude).arg(longitude)),
+                KIO::NoReload, KIO::HideProgressInfo);
+
+        if (job) {
+            d->guardPlaceNameCheck = true;
+            kDebug() << QString("http://ws.geonames.org/findNearbyPlaceName?lat=%1&lng=%2")
+                        .arg(latitude).arg(longitude);
+            connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)),
+                    this, SLOT(readData(KIO::Job *, const QByteArray &)));
+            connect(job, SIGNAL(result(KJob *)), this, SLOT(result(KJob *)));
+        } else {
+            setData(Plasma::DataEngine::Data());
+            kDebug() << "error";
+        }
+    }
+}
+
+void Name::readData(KIO::Job* job, const QByteArray& data)
+{
+    Q_UNUSED(job)
+
+    if (data.isEmpty()) {
+        return;
+    }
+
+    d->m_xmlReader.addData(data);
+}
+
+void Name::result(KJob* job)
+{
+    Plasma::DataEngine::Data outd;
+    d->guardPlaceNameCheck = false;
+
+    if(job && !job->error()) {
+
+        while (!d->m_xmlReader.atEnd()) {
+            d->m_xmlReader.readNext();
+
+            if (d->m_xmlReader.isStartElement()) {
+                if (d->m_xmlReader.name() == "geoname") {
+                    d->populateDataEngineData(outd);
+                    break;
+                }
+            }
+        }
+    } else {
+        kDebug() << "error";
+    }
+    setData(outd);
+}
+
+K_EXPORT_PLASMA_GEOLOCATIONPROVIDER(name, Name)
+
+#include "location_name.moc"
Index: geolocation.h
===================================================================
--- geolocation.h	(revision 1080874)
+++ geolocation.h	(working copy)
@@ -53,7 +53,9 @@
         EntryAccuracy m_accuracy;
         QList<GeolocationProvider *> m_plugins;
         QTimer m_updateTimer;
-        bool m_networkStatus;
+        bool m_networkUp;
+        QString m_latitude;
+        QString m_longitude;
 };
 
 K_EXPORT_PLASMA_DATAENGINE(geolocation, Geolocation)
Index: location_name.h
===================================================================
--- location_name.h	(revision 0)
+++ location_name.h	(revision 0)
@@ -0,0 +1,47 @@
+/*
+ *   Copyright (C) 2009 Petri Damstén <damu@iki.fi>
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License as
+ *   published by the Free Software Foundation; either version 2 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NAME_H
+#define NAME_H
+
+#include "geolocationprovider.h"
+
+class KJob;
+namespace KIO {
+    class Job;
+}
+
+class Name : public GeolocationProvider
+{
+    Q_OBJECT
+public:
+    explicit Name(QObject *parent = 0, const QVariantList &args = QVariantList());
+    ~Name();
+
+    virtual void update();
+
+protected slots:
+    void readData(KIO::Job *, const QByteArray& data);
+    void result(KJob* job);
+
+private:
+    class Private;
+    Private *const d;
+
+};
+
+#endif
Index: geolocationprovider.cpp
===================================================================
--- geolocationprovider.cpp	(revision 1080874)
+++ geolocationprovider.cpp	(working copy)
@@ -50,8 +50,11 @@
     return m_available;
 }
 
-bool GeolocationProvider::requestUpdate(GeolocationProvider::UpdateTriggers triggers)
+bool GeolocationProvider::requestUpdate(GeolocationProvider::UpdateTriggers triggers, bool networkUp)
 {
+    if ((m_updateTriggers & NetworkConnected) && !networkUp) {
+        return false;
+    }
     if (m_available && !m_updating && (triggers == ForcedUpdate || triggers & m_updateTriggers)) {
         m_updating = true;
         update();
@@ -108,6 +111,11 @@
     }
 }
 
+QVariant GeolocationProvider::data(const QString &key)
+{
+    return m_sharedData->value(key);
+}
+
 void GeolocationProvider::setData(const QString &key, const QVariant &value)
 {
     m_updating = false;
Index: location_gps.cpp
===================================================================
--- location_gps.cpp	(revision 1080874)
+++ location_gps.cpp	(working copy)
@@ -56,7 +56,6 @@
                 //kDebug() << "online";
                 if (m_gpsdata->status != STATUS_NO_FIX) {
                     //kDebug() << "fix";
-                    d["accuracy"] = 30;
                     d["latitude"] = QString::number(m_gpsdata->fix.latitude);
                     d["longitude"] = QString::number(m_gpsdata->fix.longitude);
                 }
@@ -73,6 +72,7 @@
     : GeolocationProvider(parent, args),
       m_gpsd(0)
 {
+    setAccuracy(30);
     gps_data_t* gpsdata = gps_open("localhost", DEFAULT_GPSD_PORT);
     if (gpsdata) {
         kDebug() << "gpsd found.";
Index: plasma-geolocation-name.desktop
===================================================================
--- plasma-geolocation-name.desktop	(revision 0)
+++ plasma-geolocation-name.desktop	(revision 0)
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=Geolocation Name
+Comment=Geolocation name from coordinates.
+X-KDE-ServiceTypes=Plasma/GeolocationProvider
+X-KDE-ParentApp=geolocation
+Type=Service
+Icon=applications-internet
+X-KDE-Library=plasma-geolocation-name
+X-KDE-PluginInfo-Name=name
Index: geolocationprovider.h
===================================================================
--- geolocationprovider.h	(revision 1080874)
+++ geolocationprovider.h	(working copy)
@@ -33,7 +33,8 @@
     Q_OBJECT
 
 public:
-    enum UpdateTrigger { ForcedUpdate = 0, SourceEvent = 1, NetworkConnected = 2 };
+    enum UpdateTrigger { ForcedUpdate = 0, SourceEvent = 1, NetworkConnected = 2,
+                         CoordinatesChanged = 4 };
     Q_DECLARE_FLAGS(UpdateTriggers, UpdateTrigger)
 
     GeolocationProvider(QObject *parent = 0, const QVariantList &args = QVariantList());
@@ -42,7 +43,7 @@
     UpdateTriggers updateTriggers() const;
     int accuracy() const;
     bool isAvailable() const;
-    bool requestUpdate(UpdateTriggers trigger);
+    bool requestUpdate(UpdateTriggers trigger, bool networkUp);
     bool populateSharedData();
 
 Q_SIGNALS:
@@ -55,6 +56,7 @@
     void setUpdateTriggers(UpdateTriggers triggers);
     virtual void init();
     virtual void update();
+    QVariant data(const QString &key);
 
 protected Q_SLOTS:
     void setData(const Plasma::DataEngine::Data &data);
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt	(revision 1080874)
+++ CMakeLists.txt	(working copy)
@@ -45,6 +45,14 @@
 
 # -------------------------------------------------------------------------------------------------
 
+set(plasma_geolocation_name_SRCS location_name.cpp)
+kde4_add_plugin(plasma-geolocation-name ${plasma_geolocation_name_SRCS})
+target_link_libraries(plasma-geolocation-name plasma-geolocation-interface)
+install(FILES plasma-geolocation-name.desktop DESTINATION ${SERVICES_INSTALL_DIR})
+install(TARGETS plasma-geolocation-name DESTINATION ${PLUGIN_INSTALL_DIR})
+
+# -------------------------------------------------------------------------------------------------
+
 set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH})
 find_package(libgps)
 macro_log_feature(LIBGPS_FOUND "libgps" "GPS support for geolocation" "http://gpsd.berlios.de/" FALSE "" "")
