Change location providers to allow updates

Change location provider implementations so it is possible for
location providers to dynamically update the location. This
commit adds the interfaces and infrastructure in redshift.c
but none of the location provides are changed to become dynamic.
This commit is contained in:
Jon Lund Steffensen
2017-08-17 19:52:29 -07:00
parent 25451b14d0
commit 153dec0e21
8 changed files with 383 additions and 183 deletions
+4 -3
View File
@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License
along with Redshift. If not, see <http://www.gnu.org/licenses/>.
Copyright (c) 2014 Jon Lund Steffense <jonlst@gmail.com>
Copyright (c) 2014-2017 Jon Lund Steffense <jonlst@gmail.com>
*/
#ifndef REDSHIFT_LOCATION_CORELOCATION_H
@@ -33,8 +33,9 @@ void location_corelocation_print_help(FILE *f);
int location_corelocation_set_option(void *state,
const char *key, const char *value);
int location_corelocation_get_location(void *state,
location_t *location);
int location_corelocation_get_fd(void *state);
int location_corelocation_handle(
void *state, location_t *location, int *available);
#endif /* ! REDSHIFT_LOCATION_CORELOCATION_H */
+68 -58
View File
@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License
along with Redshift. If not, see <http://www.gnu.org/licenses/>.
Copyright (c) 2014 Jon Lund Steffensen <jonlst@gmail.com>
Copyright (c) 2014-2017 Jon Lund Steffensen <jonlst@gmail.com>
*/
#ifdef HAVE_CONFIG_H
@@ -40,6 +40,7 @@
@interface Delegate : NSObject <CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (nonatomic) BOOL success;
@property (nonatomic) BOOL error;
@property (nonatomic) float latitude;
@property (nonatomic) float longitude;
@end
@@ -48,58 +49,61 @@
- (void)start
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
CLAuthorizationStatus authStatus =
[CLLocationManager authorizationStatus];
CLAuthorizationStatus authStatus =
[CLLocationManager authorizationStatus];
if (authStatus != kCLAuthorizationStatusNotDetermined &&
authStatus != kCLAuthorizationStatusAuthorized) {
fputs(_("Not authorized to obtain location"
" from CoreLocation.\n"), stderr);
CFRunLoopStop(CFRunLoopGetCurrent());
}
if (authStatus != kCLAuthorizationStatusNotDetermined &&
authStatus != kCLAuthorizationStatusAuthorized) {
fputs(_("Not authorized to obtain location"
" from CoreLocation.\n"), stderr);
self.error = YES;
CFRunLoopStop(CFRunLoopGetCurrent());
}
[self.locationManager startUpdatingLocation];
[self.locationManager startUpdatingLocation];
}
- (void)stop
{
[self.locationManager stopUpdatingLocation];
CFRunLoopStop(CFRunLoopGetCurrent());
[self.locationManager stopUpdatingLocation];
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
CLLocation *newLocation = [locations firstObject];
self.latitude = newLocation.coordinate.latitude;
self.longitude = newLocation.coordinate.longitude;
self.success = YES;
CLLocation *newLocation = [locations firstObject];
self.latitude = newLocation.coordinate.latitude;
self.longitude = newLocation.coordinate.longitude;
self.success = YES;
[self stop];
[self stop];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
fprintf(stderr, _("Error obtaining location from CoreLocation: %s\n"),
[[error localizedDescription] UTF8String]);
[self stop];
fprintf(stderr, _("Error obtaining location from CoreLocation: %s\n"),
[[error localizedDescription] UTF8String]);
self.error = YES;
[self stop];
}
- (void)locationManager:(CLLocationManager *)manager
didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if (status == kCLAuthorizationStatusNotDetermined) {
fputs(_("Waiting for authorization to obtain location...\n"),
stderr);
} else if (status != kCLAuthorizationStatusAuthorized) {
fputs(_("Request for location was not authorized!\n"),
stderr);
[self stop];
}
if (status == kCLAuthorizationStatusNotDetermined) {
fputs(_("Waiting for authorization to obtain location...\n"),
stderr);
} else if (status != kCLAuthorizationStatusAuthorized) {
fputs(_("Request for location was not authorized!\n"),
stderr);
self.error = YES;
[self stop];
}
}
@end
@@ -108,13 +112,13 @@
int
location_corelocation_init(void *state)
{
return 0;
return 0;
}
int
location_corelocation_start(void *state)
{
return 0;
return 0;
}
void
@@ -125,40 +129,46 @@ location_corelocation_free(void *state)
void
location_corelocation_print_help(FILE *f)
{
fputs(_("Use the location as discovered by the Corelocation provider.\n"), f);
fputs("\n", f);
fputs(_("Use the location as discovered by the Corelocation provider.\n"), f);
fputs("\n", f);
fprintf(f, _("NOTE: currently Redshift doesn't recheck %s once started,\n"
"which means it has to be restarted to take notice after travel.\n"),
"CoreLocation");
fputs("\n", f);
fprintf(f, _("NOTE: currently Redshift doesn't recheck %s once started,\n"
"which means it has to be restarted to take notice after travel.\n"),
"CoreLocation");
fputs("\n", f);
}
int
location_corelocation_set_option(void *state,
const char *key, const char *value)
const char *key, const char *value)
{
fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key);
return -1;
fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key);
return -1;
}
int
location_corelocation_get_location(void *state,
location_t *location)
location_corelocation_get_fd(void *state)
{
int result = -1;
@autoreleasepool {
Delegate *delegate = [[Delegate alloc] init];
[delegate performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
CFRunLoopRun();
if (delegate.success) {
location->lat = delegate.latitude;
location->lon = delegate.longitude;
result = 0;
}
}
return result;
return -1;
}
int
location_corelocation_handle(void *state, location_t *location, int *available)
{
@autoreleasepool {
Delegate *delegate = [[Delegate alloc] init];
[delegate performSelectorOnMainThread:@selector(start)
withObject:nil waitUntilDone:NO];
CFRunLoopRun();
if (delegate.error) return -1;
if (delegate.success) {
location->lat = delegate.latitude;
location->lon = delegate.longitude;
*available = 1;
}
}
return 0;
}
+53 -44
View File
@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License
along with Redshift. If not, see <http://www.gnu.org/licenses/>.
Copyright (c) 2014 Jon Lund Steffensen <jonlst@gmail.com>
Copyright (c) 2014-2017 Jon Lund Steffensen <jonlst@gmail.com>
*/
#include <stdio.h>
@@ -39,50 +39,11 @@ typedef struct {
GMainLoop *loop;
int available;
int error;
location_t location;
} get_location_data_t;
int
location_geoclue2_init(void *state)
{
#if !GLIB_CHECK_VERSION(2, 35, 0)
g_type_init();
#endif
return 0;
}
int
location_geoclue2_start(void *state)
{
return 0;
}
void
location_geoclue2_free(void *state)
{
}
void
location_geoclue2_print_help(FILE *f)
{
fputs(_("Use the location as discovered by a GeoClue2 provider.\n"), f);
fputs("\n", f);
fprintf(f, _("NOTE: currently Redshift doesn't recheck %s once started,\n"
"which means it has to be restarted to take notice after travel.\n"),
"GeoClue2");
fputs("\n", f);
}
int
location_geoclue2_set_option(void *state,
const char *key, const char *value)
{
fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key);
return -1;
}
/* Handle position change callbacks */
static void
geoclue_client_signal_cb(GDBusProxy *client, gchar *sender_name,
@@ -267,16 +228,63 @@ on_name_vanished(GDBusConnection *connection, const gchar *name,
get_location_data_t *data = (get_location_data_t *)user_data;
g_fprintf(stderr, _("Unable to connect to GeoClue.\n"));
data->error = 1;
g_main_loop_quit(data->loop);
}
int
location_geoclue2_get_location(void *state,
location_t *location)
location_geoclue2_init(void *state)
{
#if !GLIB_CHECK_VERSION(2, 35, 0)
g_type_init();
#endif
return 0;
}
int
location_geoclue2_start(void *state)
{
return 0;
}
void
location_geoclue2_free(void *state)
{
}
void
location_geoclue2_print_help(FILE *f)
{
fputs(_("Use the location as discovered by a GeoClue2 provider.\n"), f);
fputs("\n", f);
fprintf(f, _("NOTE: currently Redshift doesn't recheck %s once started,\n"
"which means it has to be restarted to take notice after travel.\n"),
"GeoClue2");
fputs("\n", f);
}
int
location_geoclue2_set_option(void *state,
const char *key, const char *value)
{
fprintf(stderr, _("Unknown method parameter: `%s'.\n"), key);
return -1;
}
int
location_geoclue2_get_fd(void *state)
{
return -1;
}
int
location_geoclue2_handle(void *state, location_t *location, int *available)
{
get_location_data_t data;
data.available = 0;
data.error = 0;
guint watcher_id = g_bus_watch_name(G_BUS_TYPE_SYSTEM,
"org.freedesktop.GeoClue2",
@@ -289,8 +297,9 @@ location_geoclue2_get_location(void *state,
g_bus_unwatch_name(watcher_id);
if (!data.available) return -1;
if (data.error) return -1;
*available = data.available;
*location = data.location;
return 0;
+4 -3
View File
@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License
along with Redshift. If not, see <http://www.gnu.org/licenses/>.
Copyright (c) 2014 Jon Lund Steffensen <jonlst@gmail.com>
Copyright (c) 2014-2017 Jon Lund Steffensen <jonlst@gmail.com>
*/
#ifndef REDSHIFT_LOCATION_GEOCLUE2_H
@@ -33,8 +33,9 @@ void location_geoclue2_print_help(FILE *f);
int location_geoclue2_set_option(void *state,
const char *key, const char *value);
int location_geoclue2_get_location(void *state,
location_t *loc);
int location_geoclue2_get_fd(void *state);
int location_geoclue2_handle(void *state,
location_t *location, int *available);
#endif /* ! REDSHIFT_LOCATION_GEOCLUE2_H */
+11 -4
View File
@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License
along with Redshift. If not, see <http://www.gnu.org/licenses/>.
Copyright (c) 2010-2014 Jon Lund Steffensen <jonlst@gmail.com>
Copyright (c) 2010-2017 Jon Lund Steffensen <jonlst@gmail.com>
*/
#include <stdio.h>
@@ -101,10 +101,17 @@ location_manual_set_option(location_manual_state_t *state, const char *key,
}
int
location_manual_get_location(location_manual_state_t *state,
location_t *loc)
location_manual_get_fd(location_manual_state_t *state)
{
*loc = state->loc;
return -1;
}
int
location_manual_handle(
location_manual_state_t *state, location_t *location, int *available)
{
*location = state->loc;
*available = 1;
return 0;
}
+4 -3
View File
@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License
along with Redshift. If not, see <http://www.gnu.org/licenses/>.
Copyright (c) 2010-2014 Jon Lund Steffensen <jonlst@gmail.com>
Copyright (c) 2010-2017 Jon Lund Steffensen <jonlst@gmail.com>
*/
#ifndef REDSHIFT_LOCATION_MANUAL_H
@@ -38,8 +38,9 @@ void location_manual_print_help(FILE *f);
int location_manual_set_option(location_manual_state_t *state,
const char *key, const char *value);
int location_manual_get_location(location_manual_state_t *state,
location_t *loc);
int location_manual_get_fd(location_manual_state_t *state);
int location_manual_handle(
location_manual_state_t *state, location_t *location, int *available);
#endif /* ! REDSHIFT_LOCATION_MANUAL_H */
+233 -65
View File
@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License
along with Redshift. If not, see <http://www.gnu.org/licenses/>.
Copyright (c) 2009-2015 Jon Lund Steffensen <jonlst@gmail.com>
Copyright (c) 2009-2017 Jon Lund Steffensen <jonlst@gmail.com>
*/
#ifdef HAVE_CONFIG_H
@@ -29,6 +29,21 @@
#include <locale.h>
#include <errno.h>
/* poll.h is not available on Windows but there is no Windows location provider
using polling. On Windows, we just define some stubs to make things compile.
*/
#ifndef _WIN32
# include <poll.h>
#else
#define POLLIN 0
struct pollfd {
int fd;
short events;
short revents;
};
int poll(struct pollfd *fds, int nfds, int timeout) { abort(); return -1; }
#endif
#if defined(HAVE_SIGNAL_H) && !defined(__WIN32__)
# include <signal.h>
#endif
@@ -206,8 +221,8 @@ static const location_provider_t location_providers[] = {
location_geoclue2_print_help,
(location_provider_set_option_func *)
location_geoclue2_set_option,
(location_provider_get_location_func *)
location_geoclue2_get_location
(location_provider_get_fd_func *)location_geoclue2_get_fd,
(location_provider_handle_func *)location_geoclue2_handle
},
#endif
#ifdef ENABLE_CORELOCATION
@@ -220,8 +235,8 @@ static const location_provider_t location_providers[] = {
location_corelocation_print_help,
(location_provider_set_option_func *)
location_corelocation_set_option,
(location_provider_get_location_func *)
location_corelocation_get_location
(location_provider_get_fd_func *)location_corelocation_get_fd,
(location_provider_handle_func *)location_corelocation_handle
},
#endif
{
@@ -233,8 +248,8 @@ static const location_provider_t location_providers[] = {
location_manual_print_help,
(location_provider_set_option_func *)
location_manual_set_option,
(location_provider_get_location_func *)
location_manual_get_location
(location_provider_get_fd_func *)location_manual_get_fd,
(location_provider_handle_func *)location_manual_handle
},
{ NULL }
};
@@ -717,6 +732,33 @@ gamma_is_valid(const float gamma[3])
}
/* Check whether location is valid.
Prints error message on stderr and returns 0 if invalid, otherwise
returns 1. */
static int
location_is_valid(const location_t *location)
{
/* Latitude */
if (location->lat < MIN_LAT || location->lat > MAX_LAT) {
/* TRANSLATORS: Append degree symbols if possible. */
fprintf(stderr,
_("Latitude must be between %.1f and %.1f.\n"),
MIN_LAT, MAX_LAT);
return 0;
}
/* Longitude */
if (location->lon < MIN_LON || location->lon > MAX_LON) {
/* TRANSLATORS: Append degree symbols if possible. */
fprintf(stderr,
_("Longitude must be between"
" %.1f and %.1f.\n"), MIN_LON, MAX_LON);
return 0;
}
return 1;
}
static const gamma_method_t *
find_gamma_method(const char *name)
{
@@ -747,13 +789,71 @@ find_location_provider(const char *name)
return provider;
}
/* Wait for location to become available from provider.
Waits until timeout (milliseconds) has elapsed or forever if timeout
is -1. Writes location to loc. Returns -1 on error,
0 if timeout was reached, 1 if location became available. */
static int
provider_get_location(
const location_provider_t *provider, location_state_t *state,
int timeout, location_t *loc)
{
int available = 0;
struct pollfd pollfds[1];
while (!available) {
int loc_fd = provider->get_fd(state);
if (loc_fd >= 0) {
/* Provider is dynamic. */
double now;
int r = systemtime_get_time(&now);
if (r < 0) {
fputs(_("Unable to read system time.\n"),
stderr);
return -1;
}
/* Poll on file descriptor until ready. */
pollfds[0].fd = loc_fd;
pollfds[0].events = POLLIN;
r = poll(pollfds, 1, timeout);
if (r < 0) {
perror("poll");
return -1;
} else if (r == 0) {
return 0;
}
double later;
r = systemtime_get_time(&later);
if (r < 0) {
fputs(_("Unable to read system time.\n"),
stderr);
return -1;
}
/* Adjust timeout by elapsed time */
if (timeout >= 0) {
timeout -= (later - now) * 1000;
timeout = timeout < 0 ? 0 : timeout;
}
}
int r = provider->handle(state, loc, &available);
if (r < 0) return -1;
}
return 1;
}
/* Run continual mode loop
This is the main loop of the continual mode which keeps track of the
current time and continuously updates the screen to the appropriate
color temperature. */
static int
run_continual_mode(const location_t *loc,
run_continual_mode(const location_provider_t *provider,
location_state_t *location_state,
const transition_scheme_t *scheme,
const gamma_method_t *method,
gamma_state_t *state,
@@ -786,9 +886,29 @@ run_continual_mode(const location_t *loc,
color_setting_t prev_interp =
{ -1, { NAN, NAN, NAN }, NAN };
fputs(_("Waiting for initial location"
" to become available...\n"), stderr);
/* Get initial location from provider */
location_t loc = { NAN, NAN };
r = provider_get_location(provider, location_state, -1, &loc);
if (r < 0) {
fputs(_("Unable to get location"
" from provider.\n"), stderr);
return -1;
}
if (!location_is_valid(&loc)) {
fputs(_("Invalid location returned from provider.\n"), stderr);
return -1;
}
print_location(&loc);
/* Continuously adjust color temperature */
int done = 0;
int disabled = 0;
int location_available = 1;
while (1) {
/* Check to see if disable signal was caught */
if (disable) {
@@ -849,8 +969,7 @@ run_continual_mode(const location_t *loc,
}
/* Current angular elevation of the sun */
double elevation = solar_elevation(now, loc->lat,
loc->lon);
double elevation = solar_elevation(now, loc.lat, loc.lon);
/* Use elevation of sun to set color temperature */
color_setting_t interp;
@@ -918,8 +1037,8 @@ run_continual_mode(const location_t *loc,
if (!disabled || short_trans_delta || set_adjustments) {
r = method->set_temperature(state, &interp);
if (r < 0) {
fputs(_("Temperature adjustment"
" failed.\n"), stderr);
fputs(_("Temperature adjustment failed.\n"),
stderr);
return -1;
}
}
@@ -930,10 +1049,64 @@ run_continual_mode(const location_t *loc,
sizeof(color_setting_t));
/* Sleep for 5 seconds or 0.1 second. */
int delay = SLEEP_DURATION;
if (short_trans_delta) {
systemtime_msleep(SLEEP_DURATION_SHORT);
delay = SLEEP_DURATION_SHORT;
}
int loc_fd = provider->get_fd(location_state);
if (loc_fd >= 0) {
/* Provider is dynamic. */
struct pollfd pollfds[1];
pollfds[0].fd = loc_fd;
pollfds[0].events = POLLIN;
int r = poll(pollfds, 1, delay);
if (r < 0) {
if (errno == EINTR) continue;
perror("poll");
fputs(_("Unable to get location"
" from provider.\n"), stderr);
return -1;
} else if (r == 0) {
continue;
}
/* Get new location and availability information. */
location_t new_loc;
int new_available;
provider->handle(
location_state, &new_loc,
&new_available);
if (r < 0) {
fputs(_("Unable to get location"
" from provider.\n"), stderr);
return -1;
}
if (!new_available &&
new_available != location_available) {
fputs(_("Location is temporarily unavailable;"
" Using previous location until it"
" becomes available...\n"), stderr);
}
if (new_available &&
(new_loc.lat != loc.lat ||
new_loc.lon != loc.lon ||
new_available != location_available)) {
loc = new_loc;
print_location(&loc);
}
location_available = new_available;
if (!location_is_valid(&loc)) {
fputs(_("Invalid location returned"
" from provider.\n"), stderr);
return -1;
}
} else {
systemtime_msleep(SLEEP_DURATION);
systemtime_msleep(delay);
}
}
@@ -1306,8 +1479,6 @@ main(int argc, char *argv[])
if (transition < 0) transition = 1;
location_t loc = { NAN, NAN };
/* Initialize location provider. If provider is NULL
try all providers until one that works is found. */
location_state_t location_state;
@@ -1352,19 +1523,7 @@ main(int argc, char *argv[])
}
}
/* Get current location. */
r = provider->get_location(&location_state, &loc);
if (r < 0) {
fputs(_("Unable to get location from provider.\n"),
stderr);
exit(EXIT_FAILURE);
}
provider->free(&location_state);
if (verbose) {
print_location(&loc);
printf(_("Temperatures: %dK at day, %dK at night\n"),
scheme.day.temperature,
scheme.night.temperature);
@@ -1374,24 +1533,6 @@ main(int argc, char *argv[])
scheme.high, scheme.low);
}
/* Latitude */
if (loc.lat < MIN_LAT || loc.lat > MAX_LAT) {
/* TRANSLATORS: Append degree symbols if possible. */
fprintf(stderr,
_("Latitude must be between %.1f and %.1f.\n"),
MIN_LAT, MAX_LAT);
exit(EXIT_FAILURE);
}
/* Longitude */
if (loc.lon < MIN_LON || loc.lon > MAX_LON) {
/* TRANSLATORS: Append degree symbols if possible. */
fprintf(stderr,
_("Longitude must be between"
" %.1f and %.1f.\n"), MIN_LON, MAX_LON);
exit(EXIT_FAILURE);
}
/* Color temperature */
if (scheme.day.temperature < MIN_TEMP ||
scheme.day.temperature > MAX_TEMP ||
@@ -1501,6 +1642,25 @@ main(int argc, char *argv[])
case PROGRAM_MODE_ONE_SHOT:
case PROGRAM_MODE_PRINT:
{
fputs(_("Waiting for current location"
" to become available...\n"), stderr);
/* Wait for location provider. */
location_t loc = { NAN, NAN };
int r = provider_get_location(
provider, &location_state, -1, &loc);
if (r < 0) {
fputs(_("Unable to get location"
" from provider.\n"), stderr);
exit(EXIT_FAILURE);
}
if (!location_is_valid(&loc)) {
exit(EXIT_FAILURE);
}
print_location(&loc);
/* Current angular elevation of the sun */
double now;
r = systemtime_get_time(&now);
@@ -1534,24 +1694,24 @@ main(int argc, char *argv[])
interp.brightness);
}
if (mode == PROGRAM_MODE_PRINT) {
exit(EXIT_SUCCESS);
}
if (mode != PROGRAM_MODE_PRINT) {
/* Adjust temperature */
r = method->set_temperature(&state, &interp);
if (r < 0) {
fputs(_("Temperature adjustment failed.\n"),
stderr);
method->free(&state);
exit(EXIT_FAILURE);
}
/* Adjust temperature */
r = method->set_temperature(&state, &interp);
if (r < 0) {
fputs(_("Temperature adjustment failed.\n"), stderr);
method->free(&state);
exit(EXIT_FAILURE);
}
/* In Quartz (OSX) the gamma adjustments will automatically
revert when the process exits. Therefore, we have to loop
until CTRL-C is received. */
if (strcmp(method->name, "quartz") == 0) {
fputs(_("Press ctrl-c to stop...\n"), stderr);
pause();
/* In Quartz (macOS) the gamma adjustments will
automatically revert when the process exits.
Therefore, we have to loop until CTRL-C is received.
*/
if (strcmp(method->name, "quartz") == 0) {
fputs(_("Press ctrl-c to stop...\n"), stderr);
pause();
}
}
}
break;
@@ -1601,7 +1761,7 @@ main(int argc, char *argv[])
break;
case PROGRAM_MODE_CONTINUAL:
{
r = run_continual_mode(&loc, &scheme,
r = run_continual_mode(provider, &location_state, &scheme,
method, &state,
transition, verbose);
if (r < 0) exit(EXIT_FAILURE);
@@ -1610,7 +1770,15 @@ main(int argc, char *argv[])
}
/* Clean up gamma adjustment state */
method->free(&state);
if (mode != PROGRAM_MODE_PRINT) {
method->free(&state);
}
/* Clean up location provider state */
if (mode != PROGRAM_MODE_RESET &&
mode != PROGRAM_MODE_MANUAL) {
provider->free(&location_state);
}
return EXIT_SUCCESS;
}
+6 -3
View File
@@ -89,7 +89,9 @@ typedef void location_provider_free_func(void *state);
typedef void location_provider_print_help_func(FILE *f);
typedef int location_provider_set_option_func(void *state, const char *key,
const char *value);
typedef int location_provider_get_location_func(void *state, location_t *loc);
typedef int location_provider_get_fd_func(void *state);
typedef int location_provider_handle_func(
void *state, location_t *location, int *available);
typedef struct {
char *name;
@@ -106,8 +108,9 @@ typedef struct {
/* Set an option key, value-pair. */
location_provider_set_option_func *set_option;
/* Get current location. */
location_provider_get_location_func *get_location;
/* Listen and handle location updates. */
location_provider_get_fd_func *get_fd;
location_provider_handle_func *handle;
} location_provider_t;