demo: Add GTK+ test application
This commit is contained in:
parent
f7173e6645
commit
29461fa910
8 changed files with 1127 additions and 0 deletions
514
demo/gtk-libfprint-test.c
Normal file
514
demo/gtk-libfprint-test.c
Normal file
|
@ -0,0 +1,514 @@
|
||||||
|
/*
|
||||||
|
* Example libfprint GTK+ image capture program
|
||||||
|
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <libfprint/fprint.h>
|
||||||
|
|
||||||
|
#include "loop.h"
|
||||||
|
|
||||||
|
typedef GtkApplication LibfprintDemo;
|
||||||
|
typedef GtkApplicationClass LibfprintDemoClass;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (LibfprintDemo, libfprint_demo, GTK_TYPE_APPLICATION)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
IMAGE_DISPLAY_NONE = 0,
|
||||||
|
IMAGE_DISPLAY_MINUTIAE = 1 << 0,
|
||||||
|
IMAGE_DISPLAY_BINARY = 1 << 1
|
||||||
|
} ImageDisplayFlags;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GtkApplicationWindow parent_instance;
|
||||||
|
|
||||||
|
GtkWidget *header_bar;
|
||||||
|
GtkWidget *mode_stack;
|
||||||
|
GtkWidget *capture_button;
|
||||||
|
GtkWidget *capture_image;
|
||||||
|
GtkWidget *spinner;
|
||||||
|
GtkWidget *instructions;
|
||||||
|
|
||||||
|
struct fp_dscv_dev *ddev;
|
||||||
|
struct fp_dev *dev;
|
||||||
|
|
||||||
|
struct fp_img *img;
|
||||||
|
ImageDisplayFlags img_flags;
|
||||||
|
} LibfprintDemoWindow;
|
||||||
|
|
||||||
|
typedef GtkApplicationWindowClass LibfprintDemoWindowClass;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (LibfprintDemoWindow, libfprint_demo_window, GTK_TYPE_APPLICATION_WINDOW)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EMPTY_MODE,
|
||||||
|
NOIMAGING_MODE,
|
||||||
|
CAPTURE_MODE,
|
||||||
|
SPINNER_MODE,
|
||||||
|
ERROR_MODE
|
||||||
|
} LibfprintDemoMode;
|
||||||
|
|
||||||
|
static void libfprint_demo_set_mode (LibfprintDemoWindow *win,
|
||||||
|
LibfprintDemoMode mode);
|
||||||
|
|
||||||
|
static void
|
||||||
|
pixbuf_destroy (guchar *pixels, gpointer data)
|
||||||
|
{
|
||||||
|
if (pixels == NULL)
|
||||||
|
return;
|
||||||
|
g_free (pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char *
|
||||||
|
img_to_rgbdata (struct fp_img *img,
|
||||||
|
int width,
|
||||||
|
int height)
|
||||||
|
{
|
||||||
|
int size = width * height;
|
||||||
|
unsigned char *imgdata = fp_img_get_data (img);
|
||||||
|
unsigned char *rgbdata = g_malloc (size * 3);
|
||||||
|
size_t i;
|
||||||
|
size_t rgb_offset = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
unsigned char pixel = imgdata[i];
|
||||||
|
|
||||||
|
rgbdata[rgb_offset++] = pixel;
|
||||||
|
rgbdata[rgb_offset++] = pixel;
|
||||||
|
rgbdata[rgb_offset++] = pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rgbdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
plot_minutiae (unsigned char *rgbdata,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
struct fp_minutia **minlist,
|
||||||
|
int nr_minutiae)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
#define write_pixel(num) do { \
|
||||||
|
rgbdata[((num) * 3)] = 0xff; \
|
||||||
|
rgbdata[((num) * 3) + 1] = 0; \
|
||||||
|
rgbdata[((num) * 3) + 2] = 0; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
for (i = 0; i < nr_minutiae; i++) {
|
||||||
|
struct fp_minutia *min = minlist[i];
|
||||||
|
int x, y;
|
||||||
|
size_t pixel_offset;
|
||||||
|
|
||||||
|
fp_minutia_get_coords(min, &x, &y);
|
||||||
|
pixel_offset = (y * width) + x;
|
||||||
|
write_pixel(pixel_offset - 2);
|
||||||
|
write_pixel(pixel_offset - 1);
|
||||||
|
write_pixel(pixel_offset);
|
||||||
|
write_pixel(pixel_offset + 1);
|
||||||
|
write_pixel(pixel_offset + 2);
|
||||||
|
|
||||||
|
write_pixel(pixel_offset - (width * 2));
|
||||||
|
write_pixel(pixel_offset - (width * 1) - 1);
|
||||||
|
write_pixel(pixel_offset - (width * 1));
|
||||||
|
write_pixel(pixel_offset - (width * 1) + 1);
|
||||||
|
write_pixel(pixel_offset + (width * 1) - 1);
|
||||||
|
write_pixel(pixel_offset + (width * 1));
|
||||||
|
write_pixel(pixel_offset + (width * 1) + 1);
|
||||||
|
write_pixel(pixel_offset + (width * 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkPixbuf *
|
||||||
|
img_to_pixbuf (struct fp_img *img,
|
||||||
|
ImageDisplayFlags flags)
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
unsigned char *rgbdata;
|
||||||
|
|
||||||
|
width = fp_img_get_width (img);
|
||||||
|
height = fp_img_get_height (img);
|
||||||
|
|
||||||
|
if (flags & IMAGE_DISPLAY_BINARY) {
|
||||||
|
struct fp_img *binary;
|
||||||
|
binary = fp_img_binarize (img);
|
||||||
|
rgbdata = img_to_rgbdata (binary, width, height);
|
||||||
|
fp_img_free (binary);
|
||||||
|
} else {
|
||||||
|
rgbdata = img_to_rgbdata (img, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & IMAGE_DISPLAY_MINUTIAE) {
|
||||||
|
struct fp_minutia **minlist;
|
||||||
|
int nr_minutiae;
|
||||||
|
|
||||||
|
minlist = fp_img_get_minutiae (img, &nr_minutiae);
|
||||||
|
plot_minutiae (rgbdata, width, height, minlist, nr_minutiae);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB,
|
||||||
|
FALSE, 8, width, height,
|
||||||
|
width * 3, pixbuf_destroy,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_image (LibfprintDemoWindow *win)
|
||||||
|
{
|
||||||
|
GdkPixbuf *pixbuf;
|
||||||
|
|
||||||
|
if (win->img == NULL) {
|
||||||
|
gtk_image_clear (GTK_IMAGE (win->capture_image));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_debug ("Updating image, minutiae %s, binary mode %s",
|
||||||
|
win->img_flags & IMAGE_DISPLAY_MINUTIAE ? "shown" : "hidden",
|
||||||
|
win->img_flags & IMAGE_DISPLAY_BINARY ? "on" : "off");
|
||||||
|
pixbuf = img_to_pixbuf (win->img, win->img_flags);
|
||||||
|
gtk_image_set_from_pixbuf (GTK_IMAGE (win->capture_image), pixbuf);
|
||||||
|
g_object_unref (pixbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_set_spinner_label (LibfprintDemoWindow *win,
|
||||||
|
const char *message)
|
||||||
|
{
|
||||||
|
char *label;
|
||||||
|
|
||||||
|
label = g_strdup_printf ("<b><span size=\"large\">%s</span></b>", message);
|
||||||
|
gtk_label_set_markup (GTK_LABEL (win->instructions), label);
|
||||||
|
g_free (label);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_set_capture_label (LibfprintDemoWindow *win)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv;
|
||||||
|
enum fp_scan_type scan_type;
|
||||||
|
const char *message;
|
||||||
|
|
||||||
|
drv = fp_dscv_dev_get_driver (win->ddev);
|
||||||
|
scan_type = fp_driver_get_scan_type(drv);
|
||||||
|
|
||||||
|
switch (scan_type) {
|
||||||
|
case FP_SCAN_TYPE_PRESS:
|
||||||
|
message = "Place your finger on the fingerprint reader";
|
||||||
|
break;
|
||||||
|
case FP_SCAN_TYPE_SWIPE:
|
||||||
|
message = "Swipe your finger across the fingerprint reader";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
libfprint_demo_set_spinner_label (win, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dev_capture_start_cb (struct fp_dev *dev,
|
||||||
|
int result,
|
||||||
|
struct fp_img *img,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
|
||||||
|
if (result < 0) {
|
||||||
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_async_capture_stop (dev, NULL, NULL);
|
||||||
|
|
||||||
|
win->img = img;
|
||||||
|
update_image (win);
|
||||||
|
|
||||||
|
libfprint_demo_set_mode (win, CAPTURE_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dev_open_cb (struct fp_dev *dev, int status, void *user_data)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (status < 0) {
|
||||||
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
libfprint_demo_set_capture_label (win);
|
||||||
|
|
||||||
|
win->dev = dev;
|
||||||
|
r = fp_async_capture_start (win->dev, FALSE, dev_capture_start_cb, user_data);
|
||||||
|
if (r < 0) {
|
||||||
|
g_warning ("fp_async_capture_start failed: %d", r);
|
||||||
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate_capture (GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
libfprint_demo_set_mode (win, SPINNER_MODE);
|
||||||
|
g_clear_pointer (&win->img, fp_img_free);
|
||||||
|
|
||||||
|
if (win->dev != NULL) {
|
||||||
|
dev_open_cb (win->dev, 0, user_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
libfprint_demo_set_spinner_label (win, "Opening fingerprint reader");
|
||||||
|
|
||||||
|
r = fp_async_dev_open (win->ddev, dev_open_cb, user_data);
|
||||||
|
if (r < 0) {
|
||||||
|
g_warning ("fp_async_dev_open failed: %d", r);
|
||||||
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate_quit (GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GtkApplication *app = user_data;
|
||||||
|
GtkWidget *win;
|
||||||
|
GList *list, *next;
|
||||||
|
|
||||||
|
list = gtk_application_get_windows (app);
|
||||||
|
while (list)
|
||||||
|
{
|
||||||
|
win = list->data;
|
||||||
|
next = list->next;
|
||||||
|
|
||||||
|
gtk_widget_destroy (GTK_WIDGET (win));
|
||||||
|
|
||||||
|
list = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate_show_minutiae (GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
GVariant *state;
|
||||||
|
gboolean new_state;
|
||||||
|
|
||||||
|
state = g_action_get_state (G_ACTION (action));
|
||||||
|
new_state = !g_variant_get_boolean (state);
|
||||||
|
g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));
|
||||||
|
g_variant_unref (state);
|
||||||
|
|
||||||
|
if (new_state)
|
||||||
|
win->img_flags |= IMAGE_DISPLAY_MINUTIAE;
|
||||||
|
else
|
||||||
|
win->img_flags &= ~IMAGE_DISPLAY_MINUTIAE;
|
||||||
|
|
||||||
|
update_image (win);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate_show_binary (GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
GVariant *state;
|
||||||
|
gboolean new_state;
|
||||||
|
|
||||||
|
state = g_action_get_state (G_ACTION (action));
|
||||||
|
new_state = !g_variant_get_boolean (state);
|
||||||
|
g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));
|
||||||
|
g_variant_unref (state);
|
||||||
|
|
||||||
|
if (new_state)
|
||||||
|
win->img_flags |= IMAGE_DISPLAY_BINARY;
|
||||||
|
else
|
||||||
|
win->img_flags &= ~IMAGE_DISPLAY_BINARY;
|
||||||
|
|
||||||
|
update_image (win);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
change_show_minutiae_state (GSimpleAction *action,
|
||||||
|
GVariant *state,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_simple_action_set_state (action, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
change_show_binary_state (GSimpleAction *action,
|
||||||
|
GVariant *state,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_simple_action_set_state (action, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GActionEntry app_entries[] = {
|
||||||
|
{ "quit", activate_quit, NULL, NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static GActionEntry win_entries[] = {
|
||||||
|
{ "show-minutiae", activate_show_minutiae, NULL, "false", change_show_minutiae_state },
|
||||||
|
{ "show-binary", activate_show_binary, NULL, "false", change_show_binary_state },
|
||||||
|
{ "capture", activate_capture, NULL, NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate (GApplication *app)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *window;
|
||||||
|
|
||||||
|
window = g_object_new (libfprint_demo_window_get_type (),
|
||||||
|
"application", app,
|
||||||
|
NULL);
|
||||||
|
gtk_widget_show (GTK_WIDGET (window));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_set_mode (LibfprintDemoWindow *win,
|
||||||
|
LibfprintDemoMode mode)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv;
|
||||||
|
char *title;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case EMPTY_MODE:
|
||||||
|
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "empty-mode");
|
||||||
|
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||||
|
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||||
|
break;
|
||||||
|
case NOIMAGING_MODE:
|
||||||
|
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "noimaging-mode");
|
||||||
|
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||||
|
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||||
|
break;
|
||||||
|
case CAPTURE_MODE:
|
||||||
|
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "capture-mode");
|
||||||
|
gtk_widget_set_sensitive (win->capture_button, TRUE);
|
||||||
|
|
||||||
|
drv = fp_dscv_dev_get_driver (win->ddev);
|
||||||
|
title = g_strdup_printf ("%s Test", fp_driver_get_full_name (drv));
|
||||||
|
gtk_header_bar_set_title (GTK_HEADER_BAR (win->header_bar), title);
|
||||||
|
g_free (title);
|
||||||
|
|
||||||
|
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||||
|
break;
|
||||||
|
case SPINNER_MODE:
|
||||||
|
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "spinner-mode");
|
||||||
|
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||||
|
gtk_spinner_start (GTK_SPINNER (win->spinner));
|
||||||
|
break;
|
||||||
|
case ERROR_MODE:
|
||||||
|
gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "error-mode");
|
||||||
|
gtk_widget_set_sensitive (win->capture_button, FALSE);
|
||||||
|
gtk_spinner_stop (GTK_SPINNER (win->spinner));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_init (LibfprintDemo *app)
|
||||||
|
{
|
||||||
|
g_action_map_add_action_entries (G_ACTION_MAP (app),
|
||||||
|
app_entries, G_N_ELEMENTS (app_entries),
|
||||||
|
app);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_class_init (LibfprintDemoClass *class)
|
||||||
|
{
|
||||||
|
GApplicationClass *app_class = G_APPLICATION_CLASS (class);
|
||||||
|
|
||||||
|
app_class->activate = activate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_window_init (LibfprintDemoWindow *window)
|
||||||
|
{
|
||||||
|
struct fp_dscv_dev **discovered_devs;
|
||||||
|
|
||||||
|
gtk_widget_init_template (GTK_WIDGET (window));
|
||||||
|
gtk_window_set_default_size (GTK_WINDOW (window), 700, 500);
|
||||||
|
|
||||||
|
g_action_map_add_action_entries (G_ACTION_MAP (window),
|
||||||
|
win_entries, G_N_ELEMENTS (win_entries),
|
||||||
|
window);
|
||||||
|
|
||||||
|
if (fp_init () < 0) {
|
||||||
|
libfprint_demo_set_mode (window, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_pollfds ();
|
||||||
|
|
||||||
|
discovered_devs = fp_discover_devs();
|
||||||
|
if (!discovered_devs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!fp_driver_supports_imaging(fp_dscv_dev_get_driver(discovered_devs[0]))) {
|
||||||
|
libfprint_demo_set_mode (window, NOIMAGING_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->ddev = discovered_devs[0];
|
||||||
|
libfprint_demo_set_mode (window, CAPTURE_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libfprint_demo_window_class_init (LibfprintDemoWindowClass *class)
|
||||||
|
{
|
||||||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||||
|
|
||||||
|
gtk_widget_class_set_template_from_resource (widget_class, "/libfprint_demo/gtk-libfprint-test.ui");
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, header_bar);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, mode_stack);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_button);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_image);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, spinner);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, instructions);
|
||||||
|
|
||||||
|
//FIXME setup dispose
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
GtkApplication *app;
|
||||||
|
|
||||||
|
app = GTK_APPLICATION (g_object_new (libfprint_demo_get_type (),
|
||||||
|
"application-id", "org.freedesktop.libfprint.Demo",
|
||||||
|
"flags", G_APPLICATION_FLAGS_NONE,
|
||||||
|
NULL));
|
||||||
|
|
||||||
|
return g_application_run (G_APPLICATION (app), 0, NULL);
|
||||||
|
}
|
6
demo/gtk-libfprint-test.gresource.xml
Normal file
6
demo/gtk-libfprint-test.gresource.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/libfprint_demo">
|
||||||
|
<file>gtk-libfprint-test.ui</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
351
demo/gtk-libfprint-test.ui
Normal file
351
demo/gtk-libfprint-test.ui
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Generated with glade 3.22.1 -->
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="3.20"/>
|
||||||
|
<template class="LibfprintDemoWindow" parent="GtkApplicationWindow">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="default_width">500</property>
|
||||||
|
<property name="default_height">400</property>
|
||||||
|
<property name="show_menubar">False</property>
|
||||||
|
<child type="titlebar">
|
||||||
|
<object class="GtkHeaderBar" id="header_bar">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="title">Fingerprint Reader Test</property>
|
||||||
|
<property name="subtitle">Capture test</property>
|
||||||
|
<property name="show_close_button">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuButton" id="option-menu-button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="menu-model">options-menu</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="icon_name">open-menu-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="capture_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="action_name">win.capture</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="capture_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">_Capture</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="text-button"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkStack" id="mode_stack">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="spinner-mode">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="row_spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSpinner" id="spinner">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_bottom">9</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="instructions">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_top">9</property>
|
||||||
|
<property name="label" translatable="yes"><b><span size="large">Please press finger on reader</span></b></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">spinner-mode</property>
|
||||||
|
<property name="title">spinner-mode</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="empty-mode">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="row_spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_bottom">9</property>
|
||||||
|
<property name="pixel_size">192</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_top">9</property>
|
||||||
|
<property name="label" translatable="yes"><b><span size="large">No fingerprint readers found</span></b></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Please connect a supported fingerprint reader and start the application again</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">empty-mode</property>
|
||||||
|
<property name="title">empty-mode</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAspectFrame" id="capture-mode">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">none</property>
|
||||||
|
<property name="ratio">1.2999999523162842</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="capture_image">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">capture-mode</property>
|
||||||
|
<property name="title">capture-mode</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="error-mode">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="row_spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_bottom">9</property>
|
||||||
|
<property name="pixel_size">192</property>
|
||||||
|
<property name="icon_name">dialog-warning-symbolic</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_top">9</property>
|
||||||
|
<property name="label" translatable="yes"><b><span size="large">An error occurred trying to access the fingerprint reader</span></b></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Please consult the debugging output before restarting the application</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">error-mode</property>
|
||||||
|
<property name="title">error-mode</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="noimaging-mode">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="row_spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_bottom">9</property>
|
||||||
|
<property name="pixel_size">192</property>
|
||||||
|
<property name="icon_name">scanner-symbolic</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_top">9</property>
|
||||||
|
<property name="label" translatable="yes"><b><span size="large">Fingerprint reader does not support capturing images</span></b></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Please connect a supported fingerprint reader and start the application again</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">noimaging-mode</property>
|
||||||
|
<property name="title">noimaging-mode</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<menu id="options-menu">
|
||||||
|
<section>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Show Minutiae</attribute>
|
||||||
|
<attribute name="action">win.show-minutiae</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Show Binary</attribute>
|
||||||
|
<attribute name="action">win.show-binary</attribute>
|
||||||
|
</item>
|
||||||
|
</section>
|
||||||
|
</menu>
|
||||||
|
</interface>
|
196
demo/loop.c
Normal file
196
demo/loop.c
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
/*
|
||||||
|
* fprint D-Bus daemon
|
||||||
|
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
*
|
||||||
|
* 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.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <libfprint/fprint.h>
|
||||||
|
|
||||||
|
#include <poll.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "loop.h"
|
||||||
|
|
||||||
|
struct fdsource {
|
||||||
|
GSource source;
|
||||||
|
GSList *pollfds;
|
||||||
|
};
|
||||||
|
|
||||||
|
static gboolean source_prepare(GSource *source, gint *timeout)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
r = fp_get_next_timeout(&tv);
|
||||||
|
if (r == 0) {
|
||||||
|
*timeout = -1;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!timerisset(&tv))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
*timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean source_check(GSource *source)
|
||||||
|
{
|
||||||
|
struct fdsource *_fdsource = (struct fdsource *) source;
|
||||||
|
GSList *l;
|
||||||
|
struct timeval tv;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!_fdsource->pollfds)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
for (l = _fdsource->pollfds; l != NULL; l = l->next) {
|
||||||
|
GPollFD *pollfd = l->data;
|
||||||
|
|
||||||
|
if (pollfd->revents)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = fp_get_next_timeout(&tv);
|
||||||
|
if (r == 1 && !timerisset(&tv))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean source_dispatch(GSource *source, GSourceFunc callback,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
struct timeval zerotimeout = {
|
||||||
|
.tv_sec = 0,
|
||||||
|
.tv_usec = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* FIXME error handling */
|
||||||
|
fp_handle_events_timeout(&zerotimeout);
|
||||||
|
|
||||||
|
/* FIXME whats the return value used for? */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void source_finalize(GSource *source)
|
||||||
|
{
|
||||||
|
struct fdsource *_fdsource = (struct fdsource *) source;
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
if (!_fdsource->pollfds)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (l = _fdsource->pollfds; l != NULL; l = l->next) {
|
||||||
|
GPollFD *pollfd = l->data;
|
||||||
|
|
||||||
|
g_source_remove_poll((GSource *) _fdsource, pollfd);
|
||||||
|
g_slice_free(GPollFD, pollfd);
|
||||||
|
_fdsource->pollfds = g_slist_delete_link(_fdsource->pollfds, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_slist_free(_fdsource->pollfds);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSourceFuncs sourcefuncs = {
|
||||||
|
.prepare = source_prepare,
|
||||||
|
.check = source_check,
|
||||||
|
.dispatch = source_dispatch,
|
||||||
|
.finalize = source_finalize,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct fdsource *fdsource = NULL;
|
||||||
|
|
||||||
|
static void pollfd_add(int fd, short events)
|
||||||
|
{
|
||||||
|
GPollFD *pollfd;
|
||||||
|
|
||||||
|
pollfd = g_slice_new(GPollFD);
|
||||||
|
pollfd->fd = fd;
|
||||||
|
pollfd->events = 0;
|
||||||
|
pollfd->revents = 0;
|
||||||
|
if (events & POLLIN)
|
||||||
|
pollfd->events |= G_IO_IN;
|
||||||
|
if (events & POLLOUT)
|
||||||
|
pollfd->events |= G_IO_OUT;
|
||||||
|
|
||||||
|
fdsource->pollfds = g_slist_prepend(fdsource->pollfds, pollfd);
|
||||||
|
g_source_add_poll((GSource *) fdsource, pollfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pollfd_added_cb(int fd, short events)
|
||||||
|
{
|
||||||
|
g_debug("now monitoring fd %d", fd);
|
||||||
|
pollfd_add(fd, events);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pollfd_removed_cb(int fd)
|
||||||
|
{
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
g_debug("no longer monitoring fd %d", fd);
|
||||||
|
|
||||||
|
if (!fdsource->pollfds) {
|
||||||
|
g_debug("cannot remove from list as list is empty?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (l = fdsource->pollfds; l != NULL; l = l->next) {
|
||||||
|
GPollFD *pollfd = l->data;
|
||||||
|
|
||||||
|
if (pollfd->fd != fd)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_source_remove_poll((GSource *) fdsource, pollfd);
|
||||||
|
g_slice_free(GPollFD, pollfd);
|
||||||
|
fdsource->pollfds = g_slist_delete_link(fdsource->pollfds, l);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_error("couldn't find fd %d in list\n", fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int setup_pollfds(void)
|
||||||
|
{
|
||||||
|
ssize_t numfds;
|
||||||
|
size_t i;
|
||||||
|
struct fp_pollfd *fpfds;
|
||||||
|
GSource *gsource;
|
||||||
|
|
||||||
|
gsource = g_source_new(&sourcefuncs, sizeof(struct fdsource));
|
||||||
|
fdsource = (struct fdsource *) gsource;
|
||||||
|
fdsource->pollfds = NULL;
|
||||||
|
|
||||||
|
numfds = fp_get_pollfds(&fpfds);
|
||||||
|
if (numfds < 0) {
|
||||||
|
if (fpfds)
|
||||||
|
free(fpfds);
|
||||||
|
return (int) numfds;
|
||||||
|
} else if (numfds > 0) {
|
||||||
|
for (i = 0; i < numfds; i++) {
|
||||||
|
struct fp_pollfd *fpfd = &fpfds[i];
|
||||||
|
pollfd_add(fpfd->fd, fpfd->events);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(fpfds);
|
||||||
|
fp_set_pollfd_notifiers(pollfd_added_cb, pollfd_removed_cb);
|
||||||
|
g_source_attach(gsource, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
27
demo/loop.h
Normal file
27
demo/loop.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
*
|
||||||
|
* 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.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POLL_H
|
||||||
|
|
||||||
|
#define POLL_H
|
||||||
|
|
||||||
|
int setup_pollfds(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
17
demo/meson.build
Normal file
17
demo/meson.build
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
gtk_test_resources = gnome.compile_resources('gtk-test-resources', 'gtk-libfprint-test.gresource.xml',
|
||||||
|
source_dir : '.',
|
||||||
|
c_name : 'gtk_test')
|
||||||
|
|
||||||
|
prefix = get_option('prefix')
|
||||||
|
bindir = join_paths(prefix, get_option('bindir'))
|
||||||
|
|
||||||
|
executable('gtk-libfprint-test',
|
||||||
|
[ 'gtk-libfprint-test.c', 'loop.c', 'loop.h', gtk_test_resources ],
|
||||||
|
dependencies: [ libfprint_dep, gtk_dep ],
|
||||||
|
include_directories: [
|
||||||
|
root_inc,
|
||||||
|
],
|
||||||
|
c_args: [ common_cflags,
|
||||||
|
'-DPACKAGE_VERSION="' + meson.project_version() + '"' ],
|
||||||
|
install: true,
|
||||||
|
install_dir: bindir)
|
12
meson.build
12
meson.build
|
@ -111,6 +111,15 @@ if get_option('x11-examples')
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if get_option('gtk-examples')
|
||||||
|
gnome = import('gnome')
|
||||||
|
|
||||||
|
gtk_dep = dependency('gtk+-3.0', required: false)
|
||||||
|
if not gtk_dep.found()
|
||||||
|
error('GTK+ 3.x is required for GTK+ examples')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
libfprint_conf.set('API_EXPORTED', '__attribute__((visibility("default")))')
|
libfprint_conf.set('API_EXPORTED', '__attribute__((visibility("default")))')
|
||||||
configure_file(output: 'config.h', configuration: libfprint_conf)
|
configure_file(output: 'config.h', configuration: libfprint_conf)
|
||||||
|
|
||||||
|
@ -120,6 +129,9 @@ if get_option('doc')
|
||||||
gnome = import('gnome')
|
gnome = import('gnome')
|
||||||
subdir('doc')
|
subdir('doc')
|
||||||
endif
|
endif
|
||||||
|
if get_option('gtk-examples')
|
||||||
|
subdir('demo')
|
||||||
|
endif
|
||||||
|
|
||||||
pkgconfig = import('pkgconfig')
|
pkgconfig = import('pkgconfig')
|
||||||
pkgconfig.generate(
|
pkgconfig.generate(
|
||||||
|
|
|
@ -14,6 +14,10 @@ option('x11-examples',
|
||||||
description: 'Whether to build X11 example applications',
|
description: 'Whether to build X11 example applications',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
value: true)
|
value: true)
|
||||||
|
option('gtk-examples',
|
||||||
|
description: 'Whether to build GTK+ example applications',
|
||||||
|
type: 'boolean',
|
||||||
|
value: true)
|
||||||
option('doc',
|
option('doc',
|
||||||
description: 'Whether to build the API documentation',
|
description: 'Whether to build the API documentation',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
|
|
Loading…
Reference in a new issue