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