main: Make Claim* calls work before sensor is available

It's tedious for clients to know whether they can call Release* when
sensors disappear, or making sure that the device is claimed before
releasing it when they go in power save mode.

You can now claim the sensor whether it's available or not, and it will
automatically start sending out the updates when it appears.

Closes #23
This commit is contained in:
Bastien Nocera
2015-05-21 15:41:52 +02:00
parent 2b24dfde61
commit 035ad06eae
3 changed files with 61 additions and 71 deletions

View File

@@ -132,6 +132,23 @@ find_sensors (GUdevClient *client,
return found;
}
static void
free_client_watch (gpointer data)
{
guint watch_id = GPOINTER_TO_UINT (data);
if (watch_id == 0)
return;
g_bus_unwatch_name (watch_id);
}
static GHashTable *
create_clients_hash_table (void)
{
return g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, free_client_watch);
}
typedef enum {
PROP_HAS_ACCELEROMETER = 1 << 0,
PROP_ACCELEROMETER_ORIENTATION = 1 << 1,
@@ -233,11 +250,10 @@ any_sensors_left (SensorData *data)
return exists;
}
static gboolean
static void
client_release (SensorData *data,
const char *sender,
DriverType driver_type,
GDBusMethodInvocation *invocation)
DriverType driver_type)
{
GHashTable *ht;
guint watch_id;
@@ -245,24 +261,13 @@ client_release (SensorData *data,
ht = data->clients[driver_type];
watch_id = GPOINTER_TO_UINT (g_hash_table_lookup (ht, sender));
if (watch_id == 0) {
if (invocation) {
g_dbus_method_invocation_return_error (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"D-Bus client '%s' is not monitoring %s",
sender, driver_type_to_str (driver_type));
}
return FALSE;
}
if (watch_id == 0)
return;
g_bus_unwatch_name (watch_id);
g_hash_table_remove (ht, sender);
if (g_hash_table_size (ht) == 0)
driver_set_polling (DRIVER_FOR_TYPE(driver_type), FALSE);
return TRUE;
}
static void
@@ -288,7 +293,7 @@ client_vanished_cb (GDBusConnection *connection,
watch_id = GPOINTER_TO_UINT (g_hash_table_lookup (ht, sender));
if (watch_id > 0)
client_release (data, sender, i, NULL);
client_release (data, sender, i);
}
g_free (sender);
@@ -323,15 +328,6 @@ handle_method_call (GDBusConnection *connection,
return;
}
/* Check if we have a sensor for that type */
if (!driver_type_exists (data, driver_type)) {
g_dbus_method_invocation_return_error (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_INVALID_ARGS,
"Driver type '%s' is not present", driver_type_to_str (driver_type));
return;
}
ht = data->clients[driver_type];
if (g_str_has_prefix (method_name, "Claim")) {
@@ -346,7 +342,8 @@ handle_method_call (GDBusConnection *connection,
}
/* No other clients for this sensor? Start it */
if (g_hash_table_size (ht) == 0)
if (driver_type_exists (data, driver_type) &&
g_hash_table_size (ht) == 0)
driver_set_polling (DRIVER_FOR_TYPE(driver_type), TRUE);
watch_id = g_bus_watch_name_on_connection (data->connection,
@@ -360,8 +357,8 @@ handle_method_call (GDBusConnection *connection,
g_dbus_method_invocation_return_value (invocation, NULL);
} else if (g_str_has_prefix (method_name, "Release")) {
if (client_release (data, sender, driver_type, invocation))
g_dbus_method_invocation_return_value (invocation, NULL);
client_release (data, sender, driver_type);
g_dbus_method_invocation_return_value (invocation, NULL);
}
}
@@ -576,8 +573,13 @@ sensor_changes (GUdevClient *client,
g_debug ("Sensor type %s got removed (%s)",
driver_type_to_str (i),
g_udev_device_get_sysfs_path (dev));
g_clear_object (&DEVICE_FOR_TYPE(i));
DRIVER_FOR_TYPE(i) = NULL;
g_clear_pointer (&data->clients[i], g_hash_table_unref);
data->clients[i] = create_clients_hash_table ();
send_driver_changed_dbus_event (data, i);
}
}
@@ -598,9 +600,16 @@ sensor_changes (GUdevClient *client,
if (driver_open (driver, device,
driver_type_to_callback_func (driver->type), data)) {
GHashTable *ht;
DEVICE_FOR_TYPE(driver->type) = g_object_ref (device);
DRIVER_FOR_TYPE(driver->type) = (SensorDriver *) driver;
send_driver_changed_dbus_event (data, driver->type);
ht = data->clients[driver->type];
if (g_hash_table_size (ht) > 0)
driver_set_polling (DRIVER_FOR_TYPE(driver->type), TRUE);
}
break;
}
@@ -634,10 +643,7 @@ int main (int argc, char **argv)
G_CALLBACK (sensor_changes), data);
for (i = 0; i < NUM_SENSOR_TYPES; i++) {
data->clients[i] = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
NULL);
data->clients[i] = create_clients_hash_table ();
if (!driver_type_exists (data, i))
continue;

View File

@@ -58,10 +58,6 @@ appeared_cb (GDBusConnection *connection,
gpointer user_data)
{
GError *error = NULL;
gboolean has_accel, has_als;
GVariant *v;
has_accel = has_als = FALSE;
iio_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
@@ -75,38 +71,22 @@ appeared_cb (GDBusConnection *connection,
G_CALLBACK (properties_changed), NULL);
/* Accelerometer */
v = g_dbus_proxy_get_cached_property (iio_proxy, "HasAccelerometer");
if (v) {
has_accel = g_variant_get_boolean (v);
g_variant_unref (v);
}
if (has_accel && !accel_claimed) {
g_dbus_proxy_call_sync (iio_proxy,
"ClaimAccelerometer",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &error);
g_assert_no_error (error);
accel_claimed = TRUE;
}
g_dbus_proxy_call_sync (iio_proxy,
"ClaimAccelerometer",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &error);
g_assert_no_error (error);
/* ALS */
v = g_dbus_proxy_get_cached_property (iio_proxy, "HasAmbientLight");
if (v) {
has_als = g_variant_get_boolean (v);
g_variant_unref (v);
}
if (has_als && !als_claimed) {
g_dbus_proxy_call_sync (iio_proxy,
"ClaimLight",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &error);
g_assert_no_error (error);
als_claimed = TRUE;
}
g_dbus_proxy_call_sync (iio_proxy,
"ClaimLight",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL, &error);
g_assert_no_error (error);
}
static void

View File

@@ -66,7 +66,9 @@
ClaimAccelerometer:
To start receiving accelerometer reading updates from the proxy, the application
must call the net.hadess.SensorProxy.ClaimAccelerometer() method.
must call the net.hadess.SensorProxy.ClaimAccelerometer() method. It can do so
whether an accelerometer is available or not, updates would then be sent when an
accelerometer appears.
Applications should call net.hadess.SensorProxy.ReleaseAccelerometer() when
readings are not required anymore. For example, an application that monitors
@@ -83,7 +85,7 @@
This should be called as soon as readings are not required anymore. Note
that resources are freed up if a monitoring application exits without
calling net.hadess.SensorProxy.Release(), or crashes.
calling net.hadess.SensorProxy.Release(), crashes or the sensor disappears.
-->
<method name="ReleaseAccelerometer"/>
@@ -91,7 +93,9 @@
ClaimLight:
To start receiving ambient light sensor reading updates from the proxy, the
application must call the net.hadess.SensorProxy.ClaimLight() method.
application must call the net.hadess.SensorProxy.ClaimLight() method. It can do so
whether an ambient light sensor is available or not, updates would then be sent
when such a sensor appears.
Applications should call net.hadess.SensorProxy.ReleaseLight() when readings are
not required anymore. For example, an application that monitors the ambient light
@@ -108,7 +112,7 @@
This should be called as soon as readings are not required anymore. Note
that resources are freed up if a monitoring application exits without
calling net.hadess.SensorProxy.Release(), or crashes.
calling net.hadess.SensorProxy.Release(), crashes or the sensor disappears.
-->
<method name="ReleaseLight"/>