WebCore/platform/gtk/GeolocationServiceGtk.cpp
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebCore/platform/gtk/GeolocationServiceGtk.cpp	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "GeolocationServiceGtk.h"
+
+#include "GOwnPtr.h"
+#include "NotImplemented.h"
+#include "PositionOptions.h"
+#include <wtf/text/CString.h>
+
+namespace WTF {
+    template<> void freeOwnedGPtr<GeoclueAccuracy>(GeoclueAccuracy* accuracy)
+    {
+        if (!accuracy)
+            return;
+
+        geoclue_accuracy_free(accuracy);
+    }
+}
+
+namespace WebCore {
+
+GeolocationService* GeolocationServiceGtk::create(GeolocationServiceClient* client)
+{
+    return new GeolocationServiceGtk(client);
+}
+
+GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &GeolocationServiceGtk::create;
+
+GeolocationServiceGtk::GeolocationServiceGtk(GeolocationServiceClient* client)
+    : GeolocationService(client)
+    , m_geoclueClient(0)
+    , m_geocluePosition(0)
+    , m_latitude(0.0)
+    , m_longitude(0.0)
+    , m_altitude(0.0)
+    , m_altitudeAccuracy(0.0)
+    , m_timestamp(0)
+{
+}
+
+GeolocationServiceGtk::~GeolocationServiceGtk()
+{
+    if (m_geoclueClient)
+        g_object_unref(m_geoclueClient);
+
+    if (m_geocluePosition)
+        g_object_unref(m_geocluePosition);
+}
+
+//
+// 1.) Initialize Geoclue with our requirements
+// 2.) Try to get a GeocluePosition
+// 3.) Update the Information and get the current position
+//
+// TODO: Also get GeoclueVelocity but there is no master client
+//       API for that.
+//
+bool GeolocationServiceGtk::startUpdating(PositionOptions* options)
+{
+    ASSERT(!m_geoclueClient);
+
+    m_lastPosition = 0;
+    m_lastError = 0;
+
+    GOwnPtr<GError> error;
+    GeoclueMaster* master = geoclue_master_get_default();
+    GeoclueMasterClient* client = geoclue_master_create_client(master, 0, 0);
+    g_object_unref(master);
+
+    if (!client) {
+        setError(PositionError::POSITION_UNAVAILABLE, "Could not connect to location provider.");
+        return false;
+    }
+
+    GeoclueAccuracyLevel accuracyLevel = GEOCLUE_ACCURACY_LEVEL_LOCALITY;
+    int timeout = 0;
+    if (options) {
+        accuracyLevel = options->enableHighAccuracy() ? GEOCLUE_ACCURACY_LEVEL_DETAILED : GEOCLUE_ACCURACY_LEVEL_LOCALITY;
+        if (options->hasTimeout())
+            timeout = options->timeout();
+    }
+
+    gboolean result = geoclue_master_client_set_requirements(client, accuracyLevel, timeout,
+                                                             false, GEOCLUE_RESOURCE_ALL, &error.outPtr());
+
+    if (!result) {
+        setError(PositionError::POSITION_UNAVAILABLE, error->message);
+        g_object_unref(client);
+        return false;
+    }
+
+    m_geocluePosition = geoclue_master_client_create_position(client, &error.outPtr());
+    if (!m_geocluePosition) {
+        setError(PositionError::POSITION_UNAVAILABLE, error->message);
+        g_object_unref(client);
+        return false;
+    }
+
+    m_geoclueClient = client;
+
+    geoclue_position_get_position_async(m_geocluePosition, (GeocluePositionCallback)getPositionCallback, this);
+
+    g_signal_connect(G_OBJECT(m_geocluePosition), "position-changed",
+                     G_CALLBACK(position_changed), this);
+
+    return true;
+}
+
+void GeolocationServiceGtk::stopUpdating()
+{
+    if (!m_geoclueClient)
+        return;
+
+    g_object_unref(m_geocluePosition);
+    g_object_unref(m_geoclueClient);
+
+    m_geocluePosition = 0;
+    m_geoclueClient = 0;
+}
+
+void GeolocationServiceGtk::suspend()
+{
+    // not available with geoclue
+    notImplemented();
+}
+
+void GeolocationServiceGtk::resume()
+{
+    // not available with geoclue
+    notImplemented();
+}
+
+Geoposition* GeolocationServiceGtk::lastPosition() const
+{
+    return m_lastPosition.get();
+}
+
+PositionError* GeolocationServiceGtk::lastError() const
+{
+    return m_lastError.get();
+}
+
+void GeolocationServiceGtk::updatePosition()
+{
+    m_lastError = 0;
+
+    RefPtr<Coordinates> coordinates = Coordinates::create(m_latitude, m_longitude,
+                                                          true, m_altitude, m_accuracy,
+                                                          true, m_altitudeAccuracy, false, 0.0, false, 0.0);
+    m_lastPosition = Geoposition::create(coordinates.release(), m_timestamp * 1000.0);
+    positionChanged();
+}
+
+void GeolocationServiceGtk::getPositionCallback(GeocluePosition *position,
+                                                GeocluePositionFields fields,
+                                                int timestamp,
+                                                double latitude,
+                                                double longitude,
+                                                double altitude,
+                                                GeoclueAccuracy* accuracy,
+                                                GError* error,
+                                                GeolocationServiceGtk* that)
+{
+    if (error) {
+        that->setError(PositionError::POSITION_UNAVAILABLE, error->message);
+        g_error_free(error);
+        return;
+    }
+    position_changed(position, fields, timestamp, latitude, longitude, altitude, accuracy, that);
+}
+
+void GeolocationServiceGtk::position_changed(GeocluePosition*, GeocluePositionFields fields, int timestamp, double latitude, double longitude, double altitude, GeoclueAccuracy* accuracy, GeolocationServiceGtk* that)
+{
+    if (!(fields & GEOCLUE_POSITION_FIELDS_LATITUDE && fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)) {
+        that->setError(PositionError::POSITION_UNAVAILABLE, "Position could not be determined.");
+        return;
+    }
+
+    that->m_timestamp = timestamp;
+    that->m_latitude = latitude;
+    that->m_longitude = longitude;
+    that->m_altitude = altitude;
+
+    GeoclueAccuracyLevel level;
+    geoclue_accuracy_get_details(accuracy, &level, &that->m_accuracy, &that->m_altitudeAccuracy);
+    that->updatePosition();
+}
+
+void GeolocationServiceGtk::setError(PositionError::ErrorCode errorCode, const char* message)
+{
+    m_lastPosition = 0;
+    m_lastError = PositionError::create(errorCode, String::fromUTF8(message));
+}
+
+}