OSDN Git Service

Merge WebKit at r84325: Initial merge by git.
[android-x86/external-webkit.git] / Source / WebCore / platform / gtk / GeolocationServiceGtk.cpp
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)