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 29namespace WTF { 30 template<> void freeOwnedGPtr<GeoclueAccuracy>(GeoclueAccuracy* accuracy) 31 { 32 if (!accuracy) 33 return; 34 35 geoclue_accuracy_free(accuracy); 36 } 37} 38 39namespace WebCore { 40 41GeolocationService* GeolocationServiceGtk::create(GeolocationServiceClient* client) 42{ 43 return new GeolocationServiceGtk(client); 44} 45 46GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &GeolocationServiceGtk::create; 47 48GeolocationServiceGtk::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 60GeolocationServiceGtk::~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// 77bool 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 128void 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 140void GeolocationServiceGtk::suspend() 141{ 142 // not available with geoclue 143 notImplemented(); 144} 145 146void GeolocationServiceGtk::resume() 147{ 148 // not available with geoclue 149 notImplemented(); 150} 151 152Geoposition* GeolocationServiceGtk::lastPosition() const 153{ 154 return m_lastPosition.get(); 155} 156 157PositionError* GeolocationServiceGtk::lastError() const 158{ 159 return m_lastError.get(); 160} 161 162void 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 173void 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 191void 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 208void 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