mirror of
https://gitlab.com/mishakmak/pam-fprint-grosshack.git
synced 2026-04-08 20:03:34 +02:00
Implement suspend/resume handling
This commit is contained in:
75
src/device.c
75
src/device.c
@ -475,6 +475,81 @@ _fprint_device_get_id (FprintDevice *rdev)
|
||||
return priv->id;
|
||||
}
|
||||
|
||||
static void
|
||||
suspend_cb (GObject *source_obj,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GTask) task = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
fp_device_suspend_finish (FP_DEVICE (source_obj), res, &error);
|
||||
if (error)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
resume_cb (GObject *source_obj,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GTask) task = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
fp_device_resume_finish (FP_DEVICE (source_obj), res, &error);
|
||||
if (error)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
fprint_device_suspend (FprintDevice *rdev,
|
||||
GAsyncReadyCallback callback,
|
||||
void *user_data)
|
||||
{
|
||||
GTask *task = NULL;
|
||||
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
|
||||
|
||||
/* Just forward to libfprint. */
|
||||
|
||||
task = g_task_new (rdev, NULL, callback, user_data);
|
||||
fp_device_suspend (priv->dev, NULL, suspend_cb, task);
|
||||
}
|
||||
|
||||
void
|
||||
fprint_device_resume (FprintDevice *rdev,
|
||||
GAsyncReadyCallback callback,
|
||||
void *user_data)
|
||||
{
|
||||
GTask *task = NULL;
|
||||
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
|
||||
|
||||
/* Just forward to libfprint. */
|
||||
|
||||
task = g_task_new (rdev, NULL, callback, user_data);
|
||||
fp_device_resume (priv->dev, NULL, resume_cb, task);
|
||||
}
|
||||
|
||||
void
|
||||
fprint_device_suspend_finish (FprintDevice *rdev,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
void
|
||||
fprint_device_resume_finish (FprintDevice *rdev,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
fp_finger_to_name (FpFinger finger)
|
||||
{
|
||||
|
||||
@ -95,6 +95,22 @@ struct _FprintDevice
|
||||
|
||||
FprintDevice *fprint_device_new (FpDevice *dev);
|
||||
guint32 _fprint_device_get_id (FprintDevice *rdev);
|
||||
|
||||
void fprint_device_suspend (FprintDevice *rdev,
|
||||
GAsyncReadyCallback callback,
|
||||
void *user_data);
|
||||
void fprint_device_resume (FprintDevice *rdev,
|
||||
GAsyncReadyCallback callback,
|
||||
void *user_data);
|
||||
|
||||
void fprint_device_suspend_finish (FprintDevice *rdev,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
void fprint_device_resume_finish (FprintDevice *rdev,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
|
||||
/* Print */
|
||||
/* TODO */
|
||||
|
||||
|
||||
174
src/manager.c
174
src/manager.c
@ -24,9 +24,14 @@
|
||||
#include <glib/gi18n.h>
|
||||
#include <fprint.h>
|
||||
#include <glib-object.h>
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
#include "fprintd.h"
|
||||
|
||||
#define LOGIND_BUS_NAME "org.freedesktop.login1"
|
||||
#define LOGIND_IFACE_NAME "org.freedesktop.login1.Manager"
|
||||
#define LOGIND_OBJ_PATH "/org/freedesktop/login1"
|
||||
|
||||
static void fprint_manager_constructed (GObject *object);
|
||||
static gboolean fprint_manager_get_devices (FprintManager *manager,
|
||||
GPtrArray **devices,
|
||||
@ -43,6 +48,9 @@ typedef struct
|
||||
FpContext *context;
|
||||
gboolean no_timeout;
|
||||
guint timeout_id;
|
||||
gint prepare_for_sleep_pending;
|
||||
guint prepare_for_sleep_id;
|
||||
gint sleep_inhibit_fd;
|
||||
} FprintManagerPrivate;
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (FprintManager, fprint_manager, G_TYPE_OBJECT, G_ADD_PRIVATE (FprintManager))
|
||||
@ -60,6 +68,10 @@ fprint_manager_finalize (GObject *object)
|
||||
{
|
||||
FprintManagerPrivate *priv = fprint_manager_get_instance_private (FPRINT_MANAGER (object));
|
||||
|
||||
if (priv->prepare_for_sleep_id)
|
||||
g_dbus_connection_signal_unsubscribe (priv->connection,
|
||||
priv->prepare_for_sleep_id);
|
||||
|
||||
g_clear_object (&priv->object_manager);
|
||||
g_clear_object (&priv->dbus_manager);
|
||||
g_clear_object (&priv->connection);
|
||||
@ -227,6 +239,153 @@ handle_get_default_device (FprintManager *manager,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
fprint_device_suspend_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
FprintManager *manager = FPRINT_MANAGER (user_data);
|
||||
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
|
||||
|
||||
/* Fetch the result (except for the NULL dummy call). */
|
||||
if (source_object != NULL)
|
||||
{
|
||||
fprint_device_suspend_finish (FPRINT_DEVICE (source_object), res, &error);
|
||||
if (error)
|
||||
{
|
||||
if (!g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_OPEN) &&
|
||||
!g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED))
|
||||
g_message ("Unexpected error while suspending device: %s", error->message);
|
||||
}
|
||||
}
|
||||
|
||||
priv->prepare_for_sleep_pending -= 1;
|
||||
|
||||
/* Close FD when all devices are prepared for sleeping. */
|
||||
if (priv->prepare_for_sleep_pending == 0)
|
||||
{
|
||||
if (priv->sleep_inhibit_fd >= 0)
|
||||
close (priv->sleep_inhibit_fd);
|
||||
priv->sleep_inhibit_fd = -1;
|
||||
g_debug ("Released delay inhibitor for sleep.");
|
||||
}
|
||||
|
||||
g_object_unref (manager);
|
||||
}
|
||||
|
||||
static void
|
||||
logind_sleep_inhibit_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GVariant) data = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GUnixFDList) out_fd_list = NULL;
|
||||
g_autoptr(FprintManager) manager = FPRINT_MANAGER (user_data);
|
||||
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
|
||||
gint fd_offset;
|
||||
|
||||
data = g_dbus_connection_call_with_unix_fd_list_finish (priv->connection, &out_fd_list, res, &error);
|
||||
|
||||
if (!data)
|
||||
{
|
||||
g_warning ("Failed to install a sleep delay inhibitor: %s", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (priv->sleep_inhibit_fd >= 0)
|
||||
close (priv->sleep_inhibit_fd);
|
||||
|
||||
g_debug ("Got delay inhibitor for sleep.");
|
||||
|
||||
g_variant_get (data, "(h)", &fd_offset);
|
||||
priv->sleep_inhibit_fd = g_unix_fd_list_get (out_fd_list, fd_offset, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_prepare_for_sleep_signal (GDBusConnection *connection,
|
||||
const gchar *sender_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autolist (GDBusObject) devices = NULL;
|
||||
FprintManager *manager = FPRINT_MANAGER (user_data);
|
||||
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
|
||||
gboolean prepare_for_sleep;
|
||||
GList *l;
|
||||
|
||||
if (!g_variant_check_format_string (parameters, "(b)", FALSE))
|
||||
{
|
||||
g_warning ("Received incorrect parameter for PrepareForSleep signal");
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_get (parameters, "(b)", &prepare_for_sleep);
|
||||
|
||||
/* called one more time to handle the case of no devices */
|
||||
if (prepare_for_sleep)
|
||||
priv->prepare_for_sleep_pending = 1;
|
||||
|
||||
devices = g_dbus_object_manager_get_objects (priv->object_manager);
|
||||
|
||||
g_debug ("Preparing devices for %s", prepare_for_sleep ? "sleep" : "resume");
|
||||
|
||||
for (l = devices; l != NULL; l = l->next)
|
||||
{
|
||||
g_autoptr(FprintDevice) dev = NULL;
|
||||
FprintDBusObjectSkeleton *object = l->data;
|
||||
|
||||
dev = fprint_dbus_object_skeleton_get_device (object);
|
||||
|
||||
if (prepare_for_sleep)
|
||||
{
|
||||
priv->prepare_for_sleep_pending += 1;
|
||||
g_object_ref (manager);
|
||||
fprint_device_suspend (dev, fprint_device_suspend_cb, manager);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprint_device_resume (dev, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (prepare_for_sleep)
|
||||
{
|
||||
/* "Notify" the initial dummy device we added, handling no devices that suspending */
|
||||
g_object_ref (manager);
|
||||
fprint_device_suspend_cb (NULL, NULL, manager);
|
||||
}
|
||||
else
|
||||
{
|
||||
GVariant *arg = NULL;
|
||||
|
||||
arg = g_variant_new ("(ssss)",
|
||||
"sleep",
|
||||
"net.reactivated.Fprint",
|
||||
"Suspend fingerprint readers",
|
||||
"delay");
|
||||
|
||||
/* Grab a sleep inhibitor. */
|
||||
g_dbus_connection_call_with_unix_fd_list (priv->connection,
|
||||
LOGIND_BUS_NAME,
|
||||
LOGIND_OBJ_PATH,
|
||||
LOGIND_IFACE_NAME,
|
||||
"Inhibit",
|
||||
arg,
|
||||
G_VARIANT_TYPE ("(h)"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL,
|
||||
NULL,
|
||||
logind_sleep_inhibit_cb,
|
||||
g_object_ref (manager));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
device_added_cb (FprintManager *manager, FpDevice *device, FpContext *context)
|
||||
{
|
||||
@ -290,6 +449,7 @@ device_removed_cb (FprintManager *manager, FpDevice *device, FpContext *context)
|
||||
static void
|
||||
fprint_manager_constructed (GObject *object)
|
||||
{
|
||||
g_autoptr(GVariant) param_false = NULL;
|
||||
FprintManager *manager = FPRINT_MANAGER (object);
|
||||
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
|
||||
GDBusObjectManagerServer *object_manager_server;
|
||||
@ -319,6 +479,20 @@ fprint_manager_constructed (GObject *object)
|
||||
g_dbus_object_manager_server_set_connection (object_manager_server,
|
||||
priv->connection);
|
||||
|
||||
priv->prepare_for_sleep_id = g_dbus_connection_signal_subscribe (priv->connection,
|
||||
LOGIND_BUS_NAME,
|
||||
LOGIND_IFACE_NAME,
|
||||
"PrepareForSleep",
|
||||
LOGIND_OBJ_PATH,
|
||||
NULL,
|
||||
G_DBUS_SIGNAL_FLAGS_NONE,
|
||||
handle_prepare_for_sleep_signal,
|
||||
manager,
|
||||
NULL);
|
||||
/* Fake a resume as that triggers the inhibitor to be taken. */
|
||||
param_false = g_variant_new ("(b)", FALSE);
|
||||
handle_prepare_for_sleep_signal (priv->connection, NULL, NULL, NULL, NULL, param_false, manager);
|
||||
|
||||
/* And register the signals for initial enumeration and hotplug. */
|
||||
g_signal_connect_object (priv->context,
|
||||
"device-added",
|
||||
|
||||
Reference in New Issue
Block a user