Reference count event target struct when applicable
authorJonas Ådahl <jadahl@gmail.com>
Sat, 7 Dec 2013 15:41:43 +0000 (16:41 +0100)
committerJonas Ådahl <jadahl@gmail.com>
Sat, 7 Dec 2013 15:41:43 +0000 (16:41 +0100)
If the target of an event is a reference counted object, such as
libinput_seat and libinput_device, make events own its own reference to
the object, releasing it when destroyed.

In order to do this, a new API requirement and function are introduced;
libinput_event_destroy(). The user is required to use
libinput_event_destroy() instead of free() after having retrieved an
event using libinput_get_event().

This fixes a race that would be triggered if a device or seat would be
added and removed before the user calling libinput_get_event().

Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
src/libinput.c
src/libinput.h

index 239b85c..34c794e 100644 (file)
 #include "evdev.h"
 #include "udev-seat.h"
 
+enum libinput_event_class {
+       LIBINPUT_EVENT_CLASS_BASE,
+       LIBINPUT_EVENT_CLASS_SEAT,
+       LIBINPUT_EVENT_CLASS_DEVICE,
+};
+
 struct libinput_source {
        libinput_source_dispatch_t dispatch;
        void *user_data;
@@ -116,6 +122,48 @@ libinput_destroy(struct libinput *libinput)
        free(libinput);
 }
 
+static enum libinput_event_class
+libinput_event_get_class(struct libinput_event *event)
+{
+       switch (event->type) {
+       case LIBINPUT_EVENT_ADDED_SEAT:
+       case LIBINPUT_EVENT_REMOVED_SEAT:
+       case LIBINPUT_EVENT_ADDED_DEVICE:
+       case LIBINPUT_EVENT_REMOVED_DEVICE:
+               return LIBINPUT_EVENT_CLASS_BASE;
+
+       case LIBINPUT_EVENT_DEVICE_REGISTER_CAPABILITY:
+       case LIBINPUT_EVENT_DEVICE_UNREGISTER_CAPABILITY:
+       case LIBINPUT_EVENT_KEYBOARD_KEY:
+       case LIBINPUT_EVENT_POINTER_MOTION:
+       case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
+       case LIBINPUT_EVENT_POINTER_BUTTON:
+       case LIBINPUT_EVENT_POINTER_AXIS:
+       case LIBINPUT_EVENT_TOUCH_TOUCH:
+               return LIBINPUT_EVENT_CLASS_DEVICE;
+       }
+
+       /* We should never end up here. */
+       abort();
+}
+
+LIBINPUT_EXPORT void
+libinput_event_destroy(struct libinput_event *event)
+{
+       switch (libinput_event_get_class(event)) {
+       case LIBINPUT_EVENT_CLASS_BASE:
+               break;
+       case LIBINPUT_EVENT_CLASS_SEAT:
+               libinput_seat_unref(event->target.seat);
+               break;
+       case LIBINPUT_EVENT_CLASS_DEVICE:
+               libinput_device_unref(event->target.device);
+               break;
+       }
+
+       free(event);
+}
+
 int
 open_restricted(struct libinput *libinput,
                const char *path, int flags)
@@ -546,6 +594,17 @@ libinput_post_event(struct libinput *libinput,
                libinput->events_len = events_len;
        }
 
+       switch (libinput_event_get_class(event)) {
+       case LIBINPUT_EVENT_CLASS_BASE:
+               break;
+       case LIBINPUT_EVENT_CLASS_SEAT:
+               libinput_seat_ref(event->target.seat);
+               break;
+       case LIBINPUT_EVENT_CLASS_DEVICE:
+               libinput_device_ref(event->target.device);
+               break;
+       }
+
        libinput->events_count = events_count;
        events[libinput->events_in] = event;
        libinput->events_in = (libinput->events_in + 1) % libinput->events_len;
index 5ea260c..4994830 100644 (file)
@@ -296,7 +296,8 @@ libinput_dispatch(struct libinput *libinput);
  *
  * Retrieve the next event from libinput's internal event queue.
  *
- * After handling the retrieved event, the caller must free it using free().
+ * After handling the retrieved event, the caller must destroy it using
+ * libinput_event_destroy().
  *
  * @param libinput A previously initialized libinput context
  * @return The next available event, or NULL if no event is available.
@@ -351,6 +352,20 @@ void
 libinput_destroy(struct libinput *libinput);
 
 /**
+ * @defgroup event Acessing and destruction of events
+ */
+
+/**
+ * @ingroup event
+ *
+ * Destroy the event.
+ *
+ * @param event An event retrieved by libinput_get_event().
+ */
+void
+libinput_event_destroy(struct libinput_event *event);
+
+/**
  * @defgroup seat Initialization and manipulation of seats
  */