Home | History | Annotate | Download | only in gtk
      1 /*
      2  * Copyright (C) 2008 Holger Hans Peter Freyther
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Library General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Library General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Library General Public License
     15  * along with this library; see the file COPYING.LIB.  If not, write to
     16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  * Boston, MA 02110-1301, USA.
     18  */
     19 
     20 #include "config.h"
     21 #include "GeolocationServiceGtk.h"
     22 #if ENABLE(GEOLOCATION)
     23 
     24 #include "GOwnPtr.h"
     25 #include "NotImplemented.h"
     26 #include "PositionOptions.h"
     27 #include <wtf/text/CString.h>
     28 
     29 namespace WTF {
     30     template<> void freeOwnedGPtr<GeoclueAccuracy>(GeoclueAccuracy* accuracy)
     31     {
     32         if (!accuracy)
     33             return;
     34 
     35         geoclue_accuracy_free(accuracy);
     36     }
     37 }
     38 
     39 namespace WebCore {
     40 
     41 GeolocationService* GeolocationServiceGtk::create(GeolocationServiceClient* client)
     42 {
     43     return new GeolocationServiceGtk(client);
     44 }
     45 
     46 GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &GeolocationServiceGtk::create;
     47 
     48 GeolocationServiceGtk::GeolocationServiceGtk(GeolocationServiceClient* client)
     49     : GeolocationService(client)
     50     , m_geoclueClient(0)
     51     , m_geocluePosition(0)
     52     , m_latitude(0.0)
     53     , m_longitude(0.0)
     54     , m_altitude(0.0)
     55     , m_altitudeAccuracy(0.0)
     56     , m_timestamp(0)
     57 {
     58 }
     59 
     60 GeolocationServiceGtk::~GeolocationServiceGtk()
     61 {
     62     if (m_geoclueClient)
     63         g_object_unref(m_geoclueClient);
     64 
     65     if (m_geocluePosition)
     66         g_object_unref(m_geocluePosition);
     67 }
     68 
     69 //
     70 // 1.) Initialize Geoclue with our requirements
     71 // 2.) Try to get a GeocluePosition
     72 // 3.) Update the Information and get the current position
     73 //
     74 // TODO: Also get GeoclueVelocity but there is no master client
     75 //       API for that.
     76 //
     77 bool GeolocationServiceGtk::startUpdating(PositionOptions* options)
     78 {
     79     ASSERT(!m_geoclueClient);
     80 
     81     m_lastPosition = 0;
     82     m_lastError = 0;
     83 
     84     GOwnPtr<GError> error;
     85     GeoclueMaster* master = geoclue_master_get_default();
     86     GeoclueMasterClient* client = geoclue_master_create_client(master, 0, 0);
     87     g_object_unref(master);
     88 
     89     if (!client) {
     90         setError(PositionError::POSITION_UNAVAILABLE, "Could not connect to location provider.");
     91         return false;
     92     }
     93 
     94     GeoclueAccuracyLevel accuracyLevel = GEOCLUE_ACCURACY_LEVEL_LOCALITY;
     95     int timeout = 0;
     96     if (options) {
     97         accuracyLevel = options->enableHighAccuracy() ? GEOCLUE_ACCURACY_LEVEL_DETAILED : GEOCLUE_ACCURACY_LEVEL_LOCALITY;
     98         if (options->hasTimeout())
     99             timeout = options->timeout();
    100     }
    101 
    102     gboolean result = geoclue_master_client_set_requirements(client, accuracyLevel, timeout,
    103                                                              false, GEOCLUE_RESOURCE_ALL, &error.outPtr());
    104 
    105     if (!result) {
    106         setError(PositionError::POSITION_UNAVAILABLE, error->message);
    107         g_object_unref(client);
    108         return false;
    109     }
    110 
    111     m_geocluePosition = geoclue_master_client_create_position(client, &error.outPtr());
    112     if (!m_geocluePosition) {
    113         setError(PositionError::POSITION_UNAVAILABLE, error->message);
    114         g_object_unref(client);
    115         return false;
    116     }
    117 
    118     m_geoclueClient = client;
    119 
    120     geoclue_position_get_position_async(m_geocluePosition, (GeocluePositionCallback)getPositionCallback, this);
    121 
    122     g_signal_connect(G_OBJECT(m_geocluePosition), "position-changed",
    123                      G_CALLBACK(position_changed), this);
    124 
    125     return true;
    126 }
    127 
    128 void GeolocationServiceGtk::stopUpdating()
    129 {
    130     if (!m_geoclueClient)
    131         return;
    132 
    133     g_object_unref(m_geocluePosition);
    134     g_object_unref(m_geoclueClient);
    135 
    136     m_geocluePosition = 0;
    137     m_geoclueClient = 0;
    138 }
    139 
    140 void GeolocationServiceGtk::suspend()
    141 {
    142     // not available with geoclue
    143     notImplemented();
    144 }
    145 
    146 void GeolocationServiceGtk::resume()
    147 {
    148     // not available with geoclue
    149     notImplemented();
    150 }
    151 
    152 Geoposition* GeolocationServiceGtk::lastPosition() const
    153 {
    154     return m_lastPosition.get();
    155 }
    156 
    157 PositionError* GeolocationServiceGtk::lastError() const
    158 {
    159     return m_lastError.get();
    160 }
    161 
    162 void GeolocationServiceGtk::updatePosition()
    163 {
    164     m_lastError = 0;
    165 
    166     RefPtr<Coordinates> coordinates = Coordinates::create(m_latitude, m_longitude,
    167                                                           true, m_altitude, m_accuracy,
    168                                                           true, m_altitudeAccuracy, false, 0.0, false, 0.0);
    169     m_lastPosition = Geoposition::create(coordinates.release(), m_timestamp * 1000.0);
    170     positionChanged();
    171 }
    172 
    173 void GeolocationServiceGtk::getPositionCallback(GeocluePosition *position,
    174                                                 GeocluePositionFields fields,
    175                                                 int timestamp,
    176                                                 double latitude,
    177                                                 double longitude,
    178                                                 double altitude,
    179                                                 GeoclueAccuracy* accuracy,
    180                                                 GError* error,
    181                                                 GeolocationServiceGtk* that)
    182 {
    183     if (error) {
    184         that->setError(PositionError::POSITION_UNAVAILABLE, error->message);
    185         g_error_free(error);
    186         return;
    187     }
    188     position_changed(position, fields, timestamp, latitude, longitude, altitude, accuracy, that);
    189 }
    190 
    191 void GeolocationServiceGtk::position_changed(GeocluePosition*, GeocluePositionFields fields, int timestamp, double latitude, double longitude, double altitude, GeoclueAccuracy* accuracy, GeolocationServiceGtk* that)
    192 {
    193     if (!(fields & GEOCLUE_POSITION_FIELDS_LATITUDE && fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)) {
    194         that->setError(PositionError::POSITION_UNAVAILABLE, "Position could not be determined.");
    195         return;
    196     }
    197 
    198     that->m_timestamp = timestamp;
    199     that->m_latitude = latitude;
    200     that->m_longitude = longitude;
    201     that->m_altitude = altitude;
    202 
    203     GeoclueAccuracyLevel level;
    204     geoclue_accuracy_get_details(accuracy, &level, &that->m_accuracy, &that->m_altitudeAccuracy);
    205     that->updatePosition();
    206 }
    207 
    208 void GeolocationServiceGtk::setError(PositionError::ErrorCode errorCode, const char* message)
    209 {
    210     m_lastPosition = 0;
    211     m_lastError = PositionError::create(errorCode, String::fromUTF8(message));
    212 }
    213 
    214 }
    215 #endif // ENABLE(GEOLOCATION)
    216