diff --git a/src/Makefile.am b/src/Makefile.am index 2b74b82..94a50ce 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,7 +6,7 @@ EXTRA_DIST = fprintd.xml libexec_PROGRAMS = fprintd -fprintd_SOURCES = main.c manager.c device.c file_storage.c +fprintd_SOURCES = main.c manager.c device.c file_storage.c egg-dbus-monitor.c egg-dbus-monitor.h fprintd_LDADD = $(FPRINT_LIBS) $(DAEMON_LIBS) fprintd_CFLAGS = $(WARN_CFLAGS) $(FPRINT_CFLAGS) $(DAEMON_CFLAGS) -DLOCALEDIR=\""$(datadir)/locale"\" -DPLUGINDIR=\""$(libdir)/fprintd/modules"\" diff --git a/src/device.c b/src/device.c index 5f257ba..811995b 100644 --- a/src/device.c +++ b/src/device.c @@ -31,6 +31,7 @@ #include "fprintd.h" #include "storage.h" +#include "egg-dbus-monitor.h" extern DBusGConnection *fprintd_dbus_conn; @@ -92,6 +93,9 @@ struct FprintDevicePrivate { /* type of storage */ int storage_type; + /* Hashtable of connected clients */ + GHashTable *clients; + /* whether we're running an identify, or a verify */ FprintDeviceAction current_action; }; @@ -102,7 +106,7 @@ typedef struct FprintDevicePrivate FprintDevicePrivate; enum fprint_device_properties { FPRINT_DEVICE_CONSTRUCT_DDEV = 1, - FPRINT_DEVICE_ACTION, + FPRINT_DEVICE_IN_USE, }; enum fprint_device_signals { @@ -118,6 +122,10 @@ static guint signals[NUM_SIGNALS] = { 0, }; static void fprint_device_finalize(GObject *object) { + FprintDevice *self = (FprintDevice *) object; + FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self); + + g_hash_table_destroy (priv->clients); /* FIXME close and stuff */ } @@ -144,8 +152,8 @@ static void fprint_device_get_property(GObject *object, guint property_id, FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self); switch (property_id) { - case FPRINT_DEVICE_ACTION: - g_value_set_int(value, priv->current_action); + case FPRINT_DEVICE_IN_USE: + g_value_set_boolean(value, g_hash_table_size (priv->clients) != 0); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); @@ -153,17 +161,6 @@ static void fprint_device_get_property(GObject *object, guint property_id, } } -static void fprint_device_set_action(FprintDevice *device, FprintDeviceAction action) -{ - FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(device); - - if (priv->current_action == action) - return; - - priv->current_action = action; - g_object_notify (G_OBJECT(device), "action"); -} - static void fprint_device_class_init(FprintDeviceClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS(klass); @@ -183,11 +180,11 @@ static void fprint_device_class_init(FprintDeviceClass *klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE); g_object_class_install_property(gobject_class, FPRINT_DEVICE_CONSTRUCT_DDEV, pspec); - pspec = g_param_spec_int("action", "Current device action", - "The current device action", ACTION_NONE, ACTION_ENROLL, - ACTION_NONE, G_PARAM_READABLE); + pspec = g_param_spec_boolean("in-use", "In use", + "Whether the device is currently in use", FALSE, + G_PARAM_READABLE); g_object_class_install_property(gobject_class, - FPRINT_DEVICE_ACTION, pspec); + FPRINT_DEVICE_IN_USE, pspec); signals[SIGNAL_VERIFY_STATUS] = g_signal_new("verify-status", G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, @@ -247,6 +244,10 @@ static void fprint_device_init(FprintDevice *device) polkit_context_unref (priv->pol_ctx); priv->pol_ctx = NULL; } + priv->clients = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_object_unref); } G_DEFINE_TYPE(FprintDevice, fprint_device, G_TYPE_OBJECT); @@ -414,6 +415,82 @@ _fprint_device_check_for_username (FprintDevice *rdev, return g_strdup (username); } +static void action_stop_cb(struct fp_dev *dev, void *user_data) +{ + gboolean *done = (gboolean *) user_data; + *done = TRUE; +} + +static void +_fprint_device_client_disconnected (EggDbusMonitor *monitor, gboolean connected, FprintDevice *rdev) +{ + FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); + + if (connected == FALSE) { + const char *sender; + sender = egg_dbus_monitor_get_service (monitor); + + /* Was that the client that claimed the device? */ + if (priv->sender != NULL) { + gboolean done = FALSE; + switch (priv->current_action) { + case ACTION_NONE: + break; + case ACTION_IDENTIFY: + fp_async_identify_stop(priv->dev, action_stop_cb, &done); + while (done == FALSE) + g_main_context_iteration (NULL, TRUE); + break; + case ACTION_VERIFY: + fp_async_verify_stop(priv->dev, action_stop_cb, &done); + while (done == FALSE) + g_main_context_iteration (NULL, TRUE); + break; + case ACTION_ENROLL: + fp_async_enroll_stop(priv->dev, action_stop_cb, &done); + while (done == FALSE) + g_main_context_iteration (NULL, TRUE); + break; + } + priv->current_action = ACTION_NONE; + done = FALSE; + + /* Close the claimed device as well */ + fp_async_dev_close (priv->dev, action_stop_cb, &done); + while (done == FALSE) + g_main_context_iteration (NULL, TRUE); + + g_free (priv->sender); + priv->sender = NULL; + g_free (priv->username); + priv->username = NULL; + } + g_hash_table_remove (priv->clients, sender); + } + + if (g_hash_table_size (priv->clients) == 0) { + g_object_notify (G_OBJECT (rdev), "in-use"); + } +} + +static void +_fprint_device_add_client (FprintDevice *rdev, const char *sender) +{ + EggDbusMonitor *monitor; + FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); + + monitor = g_hash_table_lookup (priv->clients, sender); + if (monitor == NULL) { + monitor = egg_dbus_monitor_new (); + egg_dbus_monitor_assign (monitor, fprintd_dbus_conn, sender); + //FIXME handle replaced + g_signal_connect (G_OBJECT (monitor), "connection-changed", + G_CALLBACK (_fprint_device_client_disconnected), rdev); + g_hash_table_insert (priv->clients, g_strdup (sender), monitor); + g_object_notify (G_OBJECT (rdev), "in-use"); + } +} + static void dev_open_cb(struct fp_dev *dev, int status, void *user_data) { FprintDevice *rdev = user_data; @@ -481,6 +558,8 @@ static void fprint_device_claim(FprintDevice *rdev, return; } + _fprint_device_add_client (rdev, sender); + priv->username = user; priv->sender = sender; @@ -493,6 +572,12 @@ static void fprint_device_claim(FprintDevice *rdev, if (r < 0) { g_slice_free(struct session_data, priv->session); priv->session = NULL; + + g_free (priv->username); + priv->username = NULL; + g_free (priv->sender); + priv->sender = NULL; + g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE, "Could not attempt device open, error %d", r); dbus_g_method_return_error(context, error); @@ -543,10 +628,6 @@ static void fprint_device_release(FprintDevice *rdev, session->context_release_device = context; fp_async_dev_close(priv->dev, dev_close_cb, rdev); - g_free (priv->sender); - priv->sender = NULL; - g_free (priv->username); - priv->username = NULL; } static void verify_cb(struct fp_dev *dev, int r, struct fp_img *img, @@ -642,17 +723,19 @@ static void fprint_device_verify_start(FprintDevice *rdev, if (fp_dev_supports_identification(priv->dev) && finger_num == -1) { if (gallery == NULL) { - //FIXME exit - g_message ("NO GALLERY"); + g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT, + "No fingerprints on that device"); + dbus_g_method_return_error(context, error); + g_error_free (error); return; } - fprint_device_set_action (rdev, ACTION_IDENTIFY); + priv->current_action = ACTION_IDENTIFY; g_message ("start identification device %d", priv->id); //FIXME we're supposed to free the gallery here? r = fp_async_identify_start (priv->dev, gallery, identify_cb, rdev); } else { - fprint_device_set_action (rdev, ACTION_VERIFY); + priv->current_action = ACTION_VERIFY; g_message("start verification device %d finger %d", priv->id, finger_num); @@ -739,7 +822,7 @@ static void fprint_device_verify_stop(FprintDevice *rdev, g_error_free (error); } - fprint_device_set_action (rdev, ACTION_NONE); + priv->current_action = ACTION_NONE; } static void enroll_stage_cb(struct fp_dev *dev, int result, @@ -804,7 +887,7 @@ static void fprint_device_enroll_start(FprintDevice *rdev, return; } - fprint_device_set_action (rdev, ACTION_ENROLL); + priv->current_action = ACTION_ENROLL; dbus_g_method_return(context); } @@ -847,7 +930,7 @@ static void fprint_device_enroll_stop(FprintDevice *rdev, g_error_free (error); } - fprint_device_set_action (rdev, ACTION_NONE); + priv->current_action = ACTION_NONE; } static void fprint_device_list_enrolled_fingers(FprintDevice *rdev, @@ -859,7 +942,7 @@ static void fprint_device_list_enrolled_fingers(FprintDevice *rdev, GSList *prints; GSList *item; GArray *ret; - char *user; + char *user, *sender; user = _fprint_device_check_for_username (rdev, context, @@ -878,6 +961,10 @@ static void fprint_device_list_enrolled_fingers(FprintDevice *rdev, return; } + sender = dbus_g_method_get_sender (context); + _fprint_device_add_client (rdev, sender); + g_free (sender); + prints = store.discover_prints(priv->ddev, user); g_free (user); if (!prints) { @@ -904,7 +991,7 @@ static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev, FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); GError *error = NULL; guint i; - char *user; + char *user, *sender; user = _fprint_device_check_for_username (rdev, context, @@ -923,6 +1010,10 @@ static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev, return; } + sender = dbus_g_method_get_sender (context); + _fprint_device_add_client (rdev, sender); + g_free (sender); + for (i = LEFT_THUMB; i <= RIGHT_LITTLE; i++) { store.print_data_delete(priv->ddev, i, user); } diff --git a/src/egg-dbus-monitor.c b/src/egg-dbus-monitor.c new file mode 100644 index 0000000..f5a5eb5 --- /dev/null +++ b/src/egg-dbus-monitor.c @@ -0,0 +1,265 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2006-2008 Richard Hughes + * + * Licensed under the GNU General Public License Version 2 + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "egg-dbus-monitor.h" + +static void egg_dbus_monitor_class_init (EggDbusMonitorClass *klass); +static void egg_dbus_monitor_init (EggDbusMonitor *dbus_monitor); +static void egg_dbus_monitor_finalize (GObject *object); + +#define EGG_DBUS_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_DBUS_MONITOR, EggDbusMonitorPrivate)) + +struct EggDbusMonitorPrivate +{ + gchar *service; + DBusGProxy *proxy; + DBusGConnection *connection; + const gchar *unique_name; +}; + +enum { + EGG_DBUS_MONITOR_CONNECTION_CHANGED, + EGG_DBUS_MONITOR_CONNECTION_REPLACED, + EGG_DBUS_MONITOR_LAST_SIGNAL +}; + +static guint signals [EGG_DBUS_MONITOR_LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (EggDbusMonitor, egg_dbus_monitor, G_TYPE_OBJECT) + +/** + * egg_dbus_monitor_name_owner_changed_cb: + **/ +static void +egg_dbus_monitor_name_owner_changed_cb (DBusGProxy *proxy, const gchar *name, + const gchar *prev, const gchar *new, + EggDbusMonitor *monitor) +{ + guint new_len; + guint prev_len; + + g_return_if_fail (EGG_IS_DBUS_MONITOR (monitor)); + if (monitor->priv->proxy == NULL) + return; + + /* not us */ + if (strcmp (name, monitor->priv->service) != 0) + return; + + /* ITS4: ignore, not used for allocation */ + new_len = strlen (new); + /* ITS4: ignore, not used for allocation */ + prev_len = strlen (prev); + + /* something --> nothing */ + if (prev_len != 0 && new_len == 0) { + g_signal_emit (monitor, signals [EGG_DBUS_MONITOR_CONNECTION_CHANGED], 0, FALSE); + return; + } + + /* nothing --> something */ + if (prev_len == 0 && new_len != 0) { + g_signal_emit (monitor, signals [EGG_DBUS_MONITOR_CONNECTION_CHANGED], 0, TRUE); + return; + } + + /* something --> something (we've replaced the old process) */ + if (prev_len != 0 && new_len != 0) { + /* only send this to the prev client */ + if (strcmp (monitor->priv->unique_name, prev) == 0) + g_signal_emit (monitor, signals [EGG_DBUS_MONITOR_CONNECTION_REPLACED], 0); + return; + } +} + +/** + * egg_dbus_monitor_assign: + * @monitor: This class instance + * @connection: The bus connection + * @service: The EGG_DBUS_MONITOR service name + * Return value: success + * + * Emits connection-changed(TRUE) if connection is alive - this means you + * have to connect up the callback before this function is called. + **/ +gboolean +egg_dbus_monitor_assign (EggDbusMonitor *monitor, DBusGConnection *connection, const gchar *service) +{ + GError *error = NULL; + gboolean connected; + DBusConnection *conn; + + g_return_val_if_fail (EGG_IS_DBUS_MONITOR (monitor), FALSE); + g_return_val_if_fail (service != NULL, FALSE); + g_return_val_if_fail (connection != NULL, FALSE); + + if (monitor->priv->proxy != NULL) { + g_warning ("already assigned!"); + return FALSE; + } + + monitor->priv->service = g_strdup (service); + monitor->priv->connection = connection; + monitor->priv->proxy = dbus_g_proxy_new_for_name_owner (monitor->priv->connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + &error); + if (error != NULL) { + g_warning ("Cannot connect to DBUS: %s", error->message); + g_error_free (error); + return FALSE; + } + dbus_g_proxy_add_signal (monitor->priv->proxy, "NameOwnerChanged", + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (monitor->priv->proxy, "NameOwnerChanged", + G_CALLBACK (egg_dbus_monitor_name_owner_changed_cb), + monitor, NULL); + + /* coldplug */ + connected = egg_dbus_monitor_is_connected (monitor); + if (connected) + g_signal_emit (monitor, signals [EGG_DBUS_MONITOR_CONNECTION_CHANGED], 0, TRUE); + + /* save this for the replaced check */ + conn = dbus_g_connection_get_connection (monitor->priv->connection); + monitor->priv->unique_name = dbus_bus_get_unique_name (conn); + return TRUE; +} + +/** + * egg_dbus_monitor_is_connected: + * @monitor: This class instance + * Return value: if we are connected to a valid watch + **/ +gboolean +egg_dbus_monitor_is_connected (EggDbusMonitor *monitor) +{ + DBusError error; + DBusConnection *conn; + gboolean ret; + g_return_val_if_fail (EGG_IS_DBUS_MONITOR (monitor), FALSE); + + /* get raw connection */ + conn = dbus_g_connection_get_connection (monitor->priv->connection); + dbus_error_init (&error); + ret = dbus_bus_name_has_owner (conn, monitor->priv->service, &error); + if (dbus_error_is_set (&error)) { + g_debug ("error: %s", error.message); + dbus_error_free (&error); + } + + return ret; +} + +/** + * egg_dbus_monitor_get_service: + * @monitor: This class instance + * Return value: the service name being monitored + **/ +const gchar * +egg_dbus_monitor_get_service (EggDbusMonitor *monitor) +{ + g_return_val_if_fail (EGG_IS_DBUS_MONITOR (monitor), FALSE); + + return monitor->priv->service; +} + +/** + * egg_dbus_monitor_class_init: + * @klass: The EggDbusMonitorClass + **/ +static void +egg_dbus_monitor_class_init (EggDbusMonitorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = egg_dbus_monitor_finalize; + g_type_class_add_private (klass, sizeof (EggDbusMonitorPrivate)); + signals [EGG_DBUS_MONITOR_CONNECTION_CHANGED] = + g_signal_new ("connection-changed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EggDbusMonitorClass, connection_changed), + NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + signals [EGG_DBUS_MONITOR_CONNECTION_REPLACED] = + g_signal_new ("connection-replaced", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EggDbusMonitorClass, connection_replaced), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +/** + * egg_dbus_monitor_init: + * @monitor: This class instance + **/ +static void +egg_dbus_monitor_init (EggDbusMonitor *monitor) +{ + monitor->priv = EGG_DBUS_MONITOR_GET_PRIVATE (monitor); + monitor->priv->service = NULL; + monitor->priv->connection = NULL; + monitor->priv->proxy = NULL; +} + +/** + * egg_dbus_monitor_finalize: + * @object: The object to finalize + **/ +static void +egg_dbus_monitor_finalize (GObject *object) +{ + EggDbusMonitor *monitor; + + g_return_if_fail (EGG_IS_DBUS_MONITOR (object)); + + monitor = EGG_DBUS_MONITOR (object); + + g_return_if_fail (monitor->priv != NULL); + if (monitor->priv->proxy != NULL) + g_object_unref (monitor->priv->proxy); + + G_OBJECT_CLASS (egg_dbus_monitor_parent_class)->finalize (object); +} + +/** + * egg_dbus_monitor_new: + * + * Return value: a new EggDbusMonitor object. + **/ +EggDbusMonitor * +egg_dbus_monitor_new (void) +{ + EggDbusMonitor *monitor; + monitor = g_object_new (EGG_TYPE_DBUS_MONITOR, NULL); + return EGG_DBUS_MONITOR (monitor); +} + diff --git a/src/egg-dbus-monitor.h b/src/egg-dbus-monitor.h new file mode 100644 index 0000000..92b10a4 --- /dev/null +++ b/src/egg-dbus-monitor.h @@ -0,0 +1,66 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Richard Hughes + * + * Licensed under the GNU General Public License Version 2 + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_DBUS_MONITOR_H +#define __EGG_DBUS_MONITOR_H + +#include +#include + +G_BEGIN_DECLS + +#define EGG_TYPE_DBUS_MONITOR (egg_dbus_monitor_get_type ()) +#define EGG_DBUS_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EGG_TYPE_DBUS_MONITOR, EggDbusMonitor)) +#define EGG_DBUS_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EGG_TYPE_DBUS_MONITOR, EggDbusMonitorClass)) +#define EGG_IS_DBUS_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EGG_TYPE_DBUS_MONITOR)) +#define EGG_IS_DBUS_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EGG_TYPE_DBUS_MONITOR)) +#define EGG_DBUS_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EGG_TYPE_DBUS_MONITOR, EggDbusMonitorClass)) +#define EGG_DBUS_MONITOR_ERROR (egg_dbus_monitor_error_quark ()) +#define EGG_DBUS_MONITOR_TYPE_ERROR (egg_dbus_monitor_error_get_type ()) + +typedef struct EggDbusMonitorPrivate EggDbusMonitorPrivate; + +typedef struct +{ + GObject parent; + EggDbusMonitorPrivate *priv; +} EggDbusMonitor; + +typedef struct +{ + GObjectClass parent_class; + void (* connection_changed) (EggDbusMonitor *watch, + gboolean connected); + void (* connection_replaced) (EggDbusMonitor *watch); +} EggDbusMonitorClass; + +GType egg_dbus_monitor_get_type (void) G_GNUC_CONST; +EggDbusMonitor *egg_dbus_monitor_new (void); +gboolean egg_dbus_monitor_assign (EggDbusMonitor *monitor, + DBusGConnection *connection, + const gchar *service); +const gchar *egg_dbus_monitor_get_service (EggDbusMonitor *monitor); +gboolean egg_dbus_monitor_is_connected (EggDbusMonitor *monitor); + +G_END_DECLS + +#endif /* __EGG_DBUS_MONITOR_H */ + diff --git a/src/manager.c b/src/manager.c index 158c362..195a5ff 100644 --- a/src/manager.c +++ b/src/manager.c @@ -41,7 +41,6 @@ typedef struct GError *last_error; GSList *dev_registry; guint timeout_id; - volatile int num_device_used; } FprintManagerPrivate; #define FPRINT_MANAGER_GET_PRIVATE(o) \ @@ -81,27 +80,32 @@ fprint_manager_timeout_cb (FprintManager *manager) g_message ("No devices in use, exit"); //FIXME kill all the devices exit(0); + return FALSE; } static void -fprint_manager_action_notified (FprintDevice *rdev, GParamSpec *spec, FprintManager *manager) +fprint_manager_in_use_notified (FprintDevice *rdev, GParamSpec *spec, FprintManager *manager) { FprintManagerPrivate *priv = FPRINT_MANAGER_GET_PRIVATE (manager); - int action; + guint num_devices_used = 0; + GSList *l; + gboolean in_use; - g_object_get (G_OBJECT(rdev), "action", &action, NULL); if (priv->timeout_id > 0) { g_source_remove (priv->timeout_id); priv->timeout_id = 0; } - if (action == 0) { - if (g_atomic_int_dec_and_test (&priv->num_device_used)) { - if (!no_timeout) - priv->timeout_id = g_timeout_add_seconds (TIMEOUT, (GSourceFunc) fprint_manager_timeout_cb, manager); - } - } else { - g_atomic_int_add (&priv->num_device_used, 1); + + for (l = priv->dev_registry; l != NULL; l = l->next) { + FprintDevice *dev = l->data; + + g_object_get (G_OBJECT(dev), "in-use", &in_use, NULL); + if (in_use != FALSE) + num_devices_used++; } + + if (num_devices_used == 0 && !no_timeout) + priv->timeout_id = g_timeout_add_seconds (TIMEOUT, (GSourceFunc) fprint_manager_timeout_cb, manager); } static void @@ -112,8 +116,6 @@ fprint_manager_init (FprintManager *manager) struct fp_dscv_dev *ddev; int i = 0; - priv->num_device_used = 0; - if (!discovered_devs) { priv->last_error = g_error_new (FPRINT_ERROR, FPRINT_ERROR_INTERNAL, _("An internal error occurred in libfprint")); @@ -127,8 +129,8 @@ fprint_manager_init (FprintManager *manager) FprintDevice *rdev = fprint_device_new(ddev); gchar *path; - g_signal_connect (G_OBJECT(rdev), "notify::action", - G_CALLBACK (fprint_manager_action_notified), manager); + g_signal_connect (G_OBJECT(rdev), "notify::in-use", + G_CALLBACK (fprint_manager_in_use_notified), manager); priv->dev_registry = g_slist_prepend(priv->dev_registry, rdev); path = get_device_path(rdev); diff --git a/tests/verify.c b/tests/verify.c index 891c418..fbfae4f 100644 --- a/tests/verify.c +++ b/tests/verify.c @@ -148,6 +148,7 @@ static DBusGProxy *open_device(const char *username) if (!net_reactivated_Fprint_Device_claim(dev, username, &error)) g_error("failed to claim device: %s", error->message); + return dev; }