#include #include #include #include /* * compile with * gcc -Wall -g `pkg-config --libs --cflags gtk+-2.0` -o cairo-mt cairo-mt.c */ typedef struct _blobinfo BlobInfo; struct _blobinfo { gint id; gint px; gint py; gint ori; gint tmaj; gint tmin; }; static GArray *drawblobs = NULL; static GtkWidget *drawarea = NULL; gdouble colors[] = { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5, 0.5, 0.5, 0.0, 0.0, 0.5, 0.5, 0.5, 0.0, 0.5, 0.5, 0.5, 0.5, }; void draw (GtkWidget *darea) { GtkAllocation *alloc; gdouble scaling; cairo_t *cr; gdouble dx = 1.0, dy = 1.0; BlobInfo *cur_blob; int i; cr = gdk_cairo_create (darea->window); alloc = &darea->allocation; scaling = MIN (alloc->width, alloc->height) / 2.2; cairo_translate (cr, alloc->width / 2, alloc->height / 2); cairo_scale (cr, scaling, -scaling); cairo_device_to_user_distance (cr, &dx, &dy); cairo_set_line_width (cr, MAX (dx, dy)); cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 1.0); /* this is a unit-box around the center of the window */ cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 1.0); cairo_new_path (cr); cairo_rectangle (cr, -1, -1, 2, 2); cairo_stroke (cr); if (drawblobs) { cairo_scale (cr, 1./3096, -1./3096); for (i = 0; i < drawblobs->len; i++) { cur_blob = &g_array_index (drawblobs, BlobInfo, i); cairo_save (cr); cairo_translate (cr, cur_blob->px, cur_blob->py); cairo_rotate (cr, -G_PI / 2.0 / 32 * cur_blob->ori); cairo_scale (cr, 0.1 * cur_blob->tmin, 0.1 * cur_blob->tmaj); cairo_arc (cr, 0, 0, 5, 0, 2*G_PI); cairo_set_source_rgba (cr, colors[3 * cur_blob->id + 0], colors[3 * cur_blob->id + 1], colors[3 * cur_blob->id + 2], 0.7); cairo_fill (cr); cairo_restore (cr); } } cairo_destroy (cr); } gboolean expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer *data) { GtkWidget *darea = GTK_WIDGET (data); draw (darea); return FALSE; } gboolean evdev_callback (GIOChannel *source, GIOCondition condition, gpointer data) { static GArray *blobs = NULL; static BlobInfo cur_blob = { 0, }; struct input_event event_buffer[256]; gsize bytes_read; GError *error = NULL; GIOStatus status; int i; if (!blobs) blobs = g_array_new (FALSE, FALSE, sizeof (BlobInfo)); status = g_io_channel_read_chars (source, (gchar *) event_buffer, sizeof (event_buffer), &bytes_read, &error); for (i = 0; i < bytes_read / sizeof (event_buffer[0]); i++) { if (event_buffer[i].type == EV_ABS) { switch (event_buffer[i].code) { case ABS_MT_TRACKING_ID: cur_blob.id = event_buffer[i].value; break; case ABS_MT_POSITION_X: cur_blob.px = event_buffer[i].value; break; case ABS_MT_POSITION_Y: cur_blob.py = event_buffer[i].value; break; case ABS_MT_ORIENTATION: cur_blob.ori = event_buffer[i].value; break; case ABS_MT_TOUCH_MAJOR: cur_blob.tmaj = event_buffer[i].value; break; case ABS_MT_TOUCH_MINOR: cur_blob.tmin = event_buffer[i].value; break; case ABS_X: case ABS_Y: break; default: g_printerr ("unknown ABS event code %d\n", event_buffer[i].code); } } else if (event_buffer[i].type == EV_SYN) { switch (event_buffer[i].code) { case SYN_MT_REPORT: g_array_append_val (blobs, cur_blob); break; case SYN_REPORT: if (drawblobs) g_array_free (drawblobs, TRUE); drawblobs = blobs; blobs = g_array_new (FALSE, FALSE, sizeof (BlobInfo)); gtk_widget_queue_draw (drawarea); break; default: g_printerr ("unknown SYN event code %d\n", event_buffer[i].code); } } } return TRUE; } void open_input (char *filename) { GIOChannel *evdev; GError *error = NULL; evdev = g_io_channel_new_file (filename, "r", &error); g_io_channel_set_encoding (evdev, NULL, NULL); g_io_channel_set_flags (evdev, G_IO_FLAG_NONBLOCK, NULL); g_io_add_watch (evdev, G_IO_IN, evdev_callback, NULL); } void create_window (void) { GtkWidget *window, *darea; window = g_object_new (GTK_TYPE_WINDOW, "title", "Test", "default-width", 800, "default-height", 600, "visible", TRUE, NULL); g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); darea = g_object_new (GTK_TYPE_DRAWING_AREA, "width-request", 100, "height-request", 100, "visible", TRUE, "parent", window, NULL); drawarea = darea; g_object_connect (G_OBJECT (darea), "signal::expose-event", G_CALLBACK (expose_event), darea, NULL); } gint main (gint argc, char *argv[]) { gtk_init (&argc, &argv); create_window (); open_input (argc > 1 ? argv[1] : "/dev/input/event9"); gtk_main (); return 0; }