diff -r 000000000000 -r 4f2f89ce4247 WebCore/platform/gtk/GeolocationServiceGtk.cpp --- /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 + +namespace WTF { + template<> void freeOwnedGPtr(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 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::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)); +} + +}