Fix #80: Add Geoclue2 location provider
This simply runs a GLib main loop when the location is requested and tries to get the location from GeoClue2. We need to run a main loop since the location is not immediately available, instead it becomes available through a signal.
This commit is contained in:
+2
-1
@@ -8,5 +8,6 @@ install:
|
||||
- sudo apt-get install -qq libxcb1-dev libxcb-randr0-dev
|
||||
- sudo apt-get install -qq libx11-dev libxxf86vm-dev
|
||||
- sudo apt-get install -qq libgeoclue-dev
|
||||
- sudo apt-get install -qq libglib2.0-dev
|
||||
- sudo apt-get install -qq python3
|
||||
script: ./bootstrap && ./configure --enable-drm --enable-vidmode --enable-randr --enable-geoclue --enable-gui && make -j2 distcheck
|
||||
script: ./bootstrap && ./configure --enable-drm --enable-vidmode --enable-randr --enable-geoclue --enable-geoclue2 --enable-gui && make -j2 distcheck
|
||||
|
||||
@@ -32,6 +32,7 @@ PKG_CHECK_MODULES([XCB_RANDR], [xcb-randr],
|
||||
|
||||
PKG_CHECK_MODULES([GLIB], [glib-2.0 gobject-2.0], [have_glib=yes], [have_glib=no])
|
||||
PKG_CHECK_MODULES([GEOCLUE], [geoclue], [have_geoclue=yes], [have_geoclue=no])
|
||||
PKG_CHECK_MODULES([GEOCLUE2], [glib-2.0 gio-2.0 >= 2.26], [have_geoclue2=yes], [have_geoclue2=no])
|
||||
|
||||
AC_CHECK_HEADER([windows.h], [have_windows_h=yes], [have_windows_h=no])
|
||||
|
||||
@@ -159,6 +160,30 @@ AS_IF([test "x$enable_geoclue" != xno], [
|
||||
])
|
||||
AM_CONDITIONAL([ENABLE_GEOCLUE], [test "x$enable_geoclue" = xyes])
|
||||
|
||||
# Check Geoclue2 location provider
|
||||
AC_MSG_CHECKING([whether to enable Geoclue2 location provider])
|
||||
AC_ARG_ENABLE([geoclue2], [AC_HELP_STRING([--enable-geoclue2],
|
||||
[enable Geoclue2 location provider])],
|
||||
[enable_geoclue2=$enableval],[enable_geoclue2=maybe])
|
||||
AS_IF([test "x$enable_geoclue2" != xno], [
|
||||
AS_IF([test "x$have_geoclue2" = xyes], [
|
||||
AC_DEFINE([ENABLE_GEOCLUE2], 1,
|
||||
[Define to 1 to enable Geoclue2 location provider])
|
||||
AC_MSG_RESULT([yes])
|
||||
enable_geoclue2=yes
|
||||
], [
|
||||
AC_MSG_RESULT([missing dependencies])
|
||||
AS_IF([test "x$enable_geoclue2" = xyes], [
|
||||
AC_MSG_ERROR([missing dependencies for Geoclue2 location provider])
|
||||
])
|
||||
enable_geoclue2=no
|
||||
])
|
||||
], [
|
||||
AC_MSG_RESULT([no])
|
||||
enable_geoclue2=no
|
||||
])
|
||||
AM_CONDITIONAL([ENABLE_GEOCLUE2], [test "x$enable_geoclue2" = xyes])
|
||||
|
||||
|
||||
# Check for GUI status icon
|
||||
AC_MSG_CHECKING([whether to enable GUI status icon])
|
||||
@@ -249,6 +274,7 @@ echo "
|
||||
|
||||
Location providers:
|
||||
Geoclue: ${enable_geoclue}
|
||||
Geoclue2: ${enable_geoclue2}
|
||||
|
||||
GUI: ${enable_gui}
|
||||
Ubuntu icons: ${enable_ubuntu}
|
||||
|
||||
@@ -13,6 +13,7 @@ src/gamma-w32gdi.c
|
||||
src/gamma-dummy.c
|
||||
|
||||
src/location-geoclue.c
|
||||
src/location-geoclue2.c
|
||||
src/location-manual.c
|
||||
|
||||
src/redshift-gtk/statusicon.py
|
||||
|
||||
@@ -66,3 +66,11 @@ redshift_LDADD += \
|
||||
$(GEOCLUE_LIBS) $(GEOCLUE_CFLAGS)
|
||||
$(GLIB_LIBS) $(GLIB_CFLAGS)
|
||||
endif
|
||||
|
||||
if ENABLE_GEOCLUE2
|
||||
redshift_SOURCES += location-geoclue2.c location-geoclue2.h
|
||||
AM_CFLAGS += \
|
||||
$(GEOCLUE2_CFLAGS)
|
||||
redshift_LDADD += \
|
||||
$(GEOCLUE2_LIBS) $(GEOCLUE2_CFLAGS)
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
/* location-geoclue2.c -- GeoClue2 location provider source
|
||||
This file is part of Redshift.
|
||||
|
||||
Redshift is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Redshift is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gprintf.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "location-geoclue2.h"
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(s) gettext(s)
|
||||
#else
|
||||
# define _(s) s
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
GMainLoop *loop;
|
||||
|
||||
int available;
|
||||
float latitude;
|
||||
float longitude;
|
||||
} 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);
|
||||
|
||||
fputs(_("NOTE: currently redshift doesn't recheck GeoClue2 once started,\n"
|
||||
"which means it has to be restarted to take notice after travel.\n"),
|
||||
f);
|
||||
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,
|
||||
gchar *signal_name, GVariant *parameters,
|
||||
gpointer *user_data)
|
||||
{
|
||||
get_location_data_t *data = (get_location_data_t *)user_data;
|
||||
|
||||
/* Only handle LocationUpdated signals */
|
||||
if (g_strcmp0(signal_name, "LocationUpdated") != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Obtain location path */
|
||||
const gchar *location_path;
|
||||
g_variant_get_child(parameters, 1, "&o", &location_path);
|
||||
|
||||
/* Obtain location */
|
||||
GError *error = NULL;
|
||||
GDBusProxy *location =
|
||||
g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL,
|
||||
"org.freedesktop.GeoClue2",
|
||||
location_path,
|
||||
"org.freedesktop.GeoClue2.Location",
|
||||
NULL, &error);
|
||||
if (location == NULL) {
|
||||
g_printerr(_("Unable to obtain location: %s.\n"),
|
||||
error->message);
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read location properties */
|
||||
GVariant *lat_v = g_dbus_proxy_get_cached_property(location,
|
||||
"Latitude");
|
||||
data->latitude = g_variant_get_double(lat_v);
|
||||
|
||||
GVariant *lon_v = g_dbus_proxy_get_cached_property(location,
|
||||
"Longitude");
|
||||
data->longitude = g_variant_get_double(lon_v);
|
||||
|
||||
data->available = 1;
|
||||
|
||||
/* Return from main loop */
|
||||
g_main_loop_quit(data->loop);
|
||||
}
|
||||
|
||||
/* Callback when GeoClue name appears on the bus */
|
||||
static void
|
||||
on_name_appeared(GDBusConnection *conn, const gchar *name,
|
||||
const gchar *name_owner, gpointer user_data)
|
||||
{
|
||||
get_location_data_t *data = (get_location_data_t *)user_data;
|
||||
|
||||
/* Obtain GeoClue Manager */
|
||||
GError *error = NULL;
|
||||
GDBusProxy *geoclue_manager =
|
||||
g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL,
|
||||
"org.freedesktop.GeoClue2",
|
||||
"/org/freedesktop/GeoClue2/Manager",
|
||||
"org.freedesktop.GeoClue2.Manager",
|
||||
NULL, &error);
|
||||
if (geoclue_manager == NULL) {
|
||||
g_printerr(_("Unable to obtain GeoClue Manager: %s.\n"),
|
||||
error->message);
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Obtain GeoClue Client path */
|
||||
error = NULL;
|
||||
GVariant *client_path_v =
|
||||
g_dbus_proxy_call_sync(geoclue_manager,
|
||||
"GetClient",
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, NULL, &error);
|
||||
if (client_path_v == NULL) {
|
||||
g_printerr(_("Unable to obtain GeoClue client path: %s.\n"),
|
||||
error->message);
|
||||
g_error_free(error);
|
||||
g_object_unref(geoclue_manager);
|
||||
return;
|
||||
}
|
||||
|
||||
const gchar *client_path;
|
||||
g_variant_get(client_path_v, "(&o)", &client_path);
|
||||
|
||||
/* Obtain GeoClue client */
|
||||
error = NULL;
|
||||
GDBusProxy *geoclue_client =
|
||||
g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL,
|
||||
"org.freedesktop.GeoClue2",
|
||||
client_path,
|
||||
"org.freedesktop.GeoClue2.Client",
|
||||
NULL, &error);
|
||||
if (geoclue_client == NULL) {
|
||||
g_printerr(_("Unable to obtain GeoClue Client: %s.\n"),
|
||||
error->message);
|
||||
g_error_free(error);
|
||||
g_variant_unref(client_path_v);
|
||||
g_object_unref(geoclue_manager);
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_unref(client_path_v);
|
||||
|
||||
/* Set distance threshold */
|
||||
error = NULL;
|
||||
GVariant *ret_v =
|
||||
g_dbus_proxy_call_sync(geoclue_client,
|
||||
"org.freedesktop.DBus.Properties.Set",
|
||||
g_variant_new("(ssv)",
|
||||
"org.freedesktop.GeoClue2.Client",
|
||||
"DistanceThreshold",
|
||||
g_variant_new("u", 50000)),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, NULL, &error);
|
||||
if (ret_v == NULL) {
|
||||
g_printerr(_("Unable to set distance threshold: %s.\n"),
|
||||
error->message);
|
||||
g_error_free(error);
|
||||
g_object_unref(geoclue_client);
|
||||
g_object_unref(geoclue_manager);
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_unref(ret_v);
|
||||
|
||||
/* Attach signal callback to client */
|
||||
g_signal_connect(geoclue_client, "g-signal",
|
||||
G_CALLBACK(geoclue_client_signal_cb),
|
||||
data);
|
||||
|
||||
/* Start GeoClue client */
|
||||
error = NULL;
|
||||
ret_v = g_dbus_proxy_call_sync(geoclue_client,
|
||||
"Start",
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1, NULL, &error);
|
||||
if (ret_v == NULL) {
|
||||
g_printerr(_("Unable to start GeoClue client: %s.\n"),
|
||||
error->message);
|
||||
g_error_free(error);
|
||||
g_object_unref(geoclue_client);
|
||||
g_object_unref(geoclue_manager);
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_unref(ret_v);
|
||||
}
|
||||
|
||||
/* Callback when GeoClue disappears from the bus */
|
||||
static void
|
||||
on_name_vanished(GDBusConnection *connection, const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
get_location_data_t *data = (get_location_data_t *)user_data;
|
||||
|
||||
g_fprintf(stderr, _("Unable to connect to GeoClue.\n"));
|
||||
|
||||
g_main_loop_quit(data->loop);
|
||||
}
|
||||
|
||||
int
|
||||
location_geoclue2_get_location(void *state,
|
||||
float *lat, float *lon)
|
||||
{
|
||||
get_location_data_t data;
|
||||
data.available = 0;
|
||||
|
||||
guint watcher_id = g_bus_watch_name(G_BUS_TYPE_SYSTEM,
|
||||
"org.freedesktop.GeoClue2",
|
||||
G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
|
||||
on_name_appeared,
|
||||
on_name_vanished,
|
||||
&data, NULL);
|
||||
data.loop = g_main_loop_new(NULL, FALSE);
|
||||
g_main_loop_run(data.loop);
|
||||
|
||||
g_bus_unwatch_name(watcher_id);
|
||||
|
||||
if (!data.available) return -1;
|
||||
|
||||
*lat = data.latitude;
|
||||
*lon = data.longitude;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* location-geoclue2.h -- Geoclue2 location provider header
|
||||
This file is part of Redshift.
|
||||
|
||||
Redshift is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Redshift is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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>
|
||||
*/
|
||||
|
||||
#ifndef REDSHIFT_LOCATION_GEOCLUE2_H
|
||||
#define REDSHIFT_LOCATION_GEOCLUE2_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int location_geoclue2_init(void *state);
|
||||
int location_geoclue2_start(void *state);
|
||||
void location_geoclue2_free(void *state);
|
||||
|
||||
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,
|
||||
float *lat, float *lon);
|
||||
|
||||
|
||||
#endif /* ! REDSHIFT_LOCATION_GEOCLUE2_H */
|
||||
+19
-1
@@ -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) 2013 Jon Lund Steffensen <jonlst@gmail.com>
|
||||
Copyright (c) 2009-2014 Jon Lund Steffensen <jonlst@gmail.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@@ -76,6 +76,10 @@
|
||||
# include "location-geoclue.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_GEOCLUE2
|
||||
# include "location-geoclue2.h"
|
||||
#endif
|
||||
|
||||
|
||||
/* Union of state data for gamma adjustment methods */
|
||||
typedef union {
|
||||
@@ -182,6 +186,20 @@ static const location_provider_t location_providers[] = {
|
||||
(location_provider_get_location_func *)
|
||||
location_geoclue_get_location
|
||||
},
|
||||
#endif
|
||||
#ifdef ENABLE_GEOCLUE2
|
||||
{
|
||||
"geoclue2",
|
||||
(location_provider_init_func *)location_geoclue2_init,
|
||||
(location_provider_start_func *)location_geoclue2_start,
|
||||
(location_provider_free_func *)location_geoclue2_free,
|
||||
(location_provider_print_help_func *)
|
||||
location_geoclue2_print_help,
|
||||
(location_provider_set_option_func *)
|
||||
location_geoclue2_set_option,
|
||||
(location_provider_get_location_func *)
|
||||
location_geoclue2_get_location
|
||||
},
|
||||
#endif
|
||||
{
|
||||
"manual",
|
||||
|
||||
Reference in New Issue
Block a user