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; 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 { typedef enum {
PROP_HAS_ACCELEROMETER = 1 << 0, PROP_HAS_ACCELEROMETER = 1 << 0,
PROP_ACCELEROMETER_ORIENTATION = 1 << 1, PROP_ACCELEROMETER_ORIENTATION = 1 << 1,
@@ -233,11 +250,10 @@ any_sensors_left (SensorData *data)
return exists; return exists;
} }
static gboolean static void
client_release (SensorData *data, client_release (SensorData *data,
const char *sender, const char *sender,
DriverType driver_type, DriverType driver_type)
GDBusMethodInvocation *invocation)
{ {
GHashTable *ht; GHashTable *ht;
guint watch_id; guint watch_id;
@@ -245,24 +261,13 @@ client_release (SensorData *data,
ht = data->clients[driver_type]; ht = data->clients[driver_type];
watch_id = GPOINTER_TO_UINT (g_hash_table_lookup (ht, sender)); watch_id = GPOINTER_TO_UINT (g_hash_table_lookup (ht, sender));
if (watch_id == 0) { if (watch_id == 0)
if (invocation) { return;
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;
}
g_bus_unwatch_name (watch_id);
g_hash_table_remove (ht, sender); g_hash_table_remove (ht, sender);
if (g_hash_table_size (ht) == 0) if (g_hash_table_size (ht) == 0)
driver_set_polling (DRIVER_FOR_TYPE(driver_type), FALSE); driver_set_polling (DRIVER_FOR_TYPE(driver_type), FALSE);
return TRUE;
} }
static void static void
@@ -288,7 +293,7 @@ client_vanished_cb (GDBusConnection *connection,
watch_id = GPOINTER_TO_UINT (g_hash_table_lookup (ht, sender)); watch_id = GPOINTER_TO_UINT (g_hash_table_lookup (ht, sender));
if (watch_id > 0) if (watch_id > 0)
client_release (data, sender, i, NULL); client_release (data, sender, i);
} }
g_free (sender); g_free (sender);
@@ -323,15 +328,6 @@ handle_method_call (GDBusConnection *connection,
return; 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]; ht = data->clients[driver_type];
if (g_str_has_prefix (method_name, "Claim")) { 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 */ /* 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); driver_set_polling (DRIVER_FOR_TYPE(driver_type), TRUE);
watch_id = g_bus_watch_name_on_connection (data->connection, watch_id = g_bus_watch_name_on_connection (data->connection,
@@ -360,7 +357,7 @@ handle_method_call (GDBusConnection *connection,
g_dbus_method_invocation_return_value (invocation, NULL); g_dbus_method_invocation_return_value (invocation, NULL);
} else if (g_str_has_prefix (method_name, "Release")) { } else if (g_str_has_prefix (method_name, "Release")) {
if (client_release (data, sender, driver_type, invocation)) client_release (data, sender, driver_type);
g_dbus_method_invocation_return_value (invocation, NULL); g_dbus_method_invocation_return_value (invocation, NULL);
} }
} }
@@ -576,8 +573,13 @@ sensor_changes (GUdevClient *client,
g_debug ("Sensor type %s got removed (%s)", g_debug ("Sensor type %s got removed (%s)",
driver_type_to_str (i), driver_type_to_str (i),
g_udev_device_get_sysfs_path (dev)); g_udev_device_get_sysfs_path (dev));
g_clear_object (&DEVICE_FOR_TYPE(i)); g_clear_object (&DEVICE_FOR_TYPE(i));
DRIVER_FOR_TYPE(i) = NULL; 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); send_driver_changed_dbus_event (data, i);
} }
} }
@@ -598,9 +600,16 @@ sensor_changes (GUdevClient *client,
if (driver_open (driver, device, if (driver_open (driver, device,
driver_type_to_callback_func (driver->type), data)) { driver_type_to_callback_func (driver->type), data)) {
GHashTable *ht;
DEVICE_FOR_TYPE(driver->type) = g_object_ref (device); DEVICE_FOR_TYPE(driver->type) = g_object_ref (device);
DRIVER_FOR_TYPE(driver->type) = (SensorDriver *) driver; DRIVER_FOR_TYPE(driver->type) = (SensorDriver *) driver;
send_driver_changed_dbus_event (data, driver->type); 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; break;
} }
@@ -634,10 +643,7 @@ int main (int argc, char **argv)
G_CALLBACK (sensor_changes), data); G_CALLBACK (sensor_changes), data);
for (i = 0; i < NUM_SENSOR_TYPES; i++) { for (i = 0; i < NUM_SENSOR_TYPES; i++) {
data->clients[i] = g_hash_table_new_full (g_str_hash, data->clients[i] = create_clients_hash_table ();
g_str_equal,
g_free,
NULL);
if (!driver_type_exists (data, i)) if (!driver_type_exists (data, i))
continue; continue;

View File

@@ -58,10 +58,6 @@ appeared_cb (GDBusConnection *connection,
gpointer user_data) gpointer user_data)
{ {
GError *error = NULL; 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, iio_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE, G_DBUS_PROXY_FLAGS_NONE,
@@ -75,12 +71,6 @@ appeared_cb (GDBusConnection *connection,
G_CALLBACK (properties_changed), NULL); G_CALLBACK (properties_changed), NULL);
/* Accelerometer */ /* 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, g_dbus_proxy_call_sync (iio_proxy,
"ClaimAccelerometer", "ClaimAccelerometer",
NULL, NULL,
@@ -88,16 +78,8 @@ appeared_cb (GDBusConnection *connection,
-1, -1,
NULL, &error); NULL, &error);
g_assert_no_error (error); g_assert_no_error (error);
accel_claimed = TRUE;
}
/* ALS */ /* 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, g_dbus_proxy_call_sync (iio_proxy,
"ClaimLight", "ClaimLight",
NULL, NULL,
@@ -105,8 +87,6 @@ appeared_cb (GDBusConnection *connection,
-1, -1,
NULL, &error); NULL, &error);
g_assert_no_error (error); g_assert_no_error (error);
als_claimed = TRUE;
}
} }
static void static void

View File

@@ -66,7 +66,9 @@
ClaimAccelerometer: ClaimAccelerometer:
To start receiving accelerometer reading updates from the proxy, the application 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 Applications should call net.hadess.SensorProxy.ReleaseAccelerometer() when
readings are not required anymore. For example, an application that monitors 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 This should be called as soon as readings are not required anymore. Note
that resources are freed up if a monitoring application exits without 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"/> <method name="ReleaseAccelerometer"/>
@@ -91,7 +93,9 @@
ClaimLight: ClaimLight:
To start receiving ambient light sensor reading updates from the proxy, the 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 Applications should call net.hadess.SensorProxy.ReleaseLight() when readings are
not required anymore. For example, an application that monitors the ambient light 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 This should be called as soon as readings are not required anymore. Note
that resources are freed up if a monitoring application exits without 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"/> <method name="ReleaseLight"/>