[RFC libinput] Add a "switch" interface for parts of the SW_* range

Peter Hutterer peter.hutterer at who-t.net
Sun Jan 3 17:20:04 PST 2016


This is a first draft to gather some comments, it's not hooked up to
anything yet and really just to get the main intention across.

Things up for comments and discussion:
Unlike buttons, we only expose switches we understand, hence enum
libinput_switch rather than just forwarding uint32_t
devices. This enables us to be selective on which devices should be handled
by libinput, e.g. libinput doesn't need to handle devices that expose
SW_JACK_PHYSICAL_INSERT. The ones that matter because they are input
device-related are SW_LID, SW_TABLET_MODE, SW_DOCK, and SW_MUTE_DEVICE and
SW_KEYPAD_SLIDE.

libinput will also handle switch events internally, e.g. disable the
touchpad automatically when the lid is closed. this will be transparent to
the caller, though they will receive the event too. See
https://bugs.freedesktop.org/show_bug.cgi?id=86223
This feature is the main driver for the interface, the alternative would be
to handle the device completely internally and let the caller open a
separate fd for the any switch device. That makes some sense for the "Led
Switch" device, not so much for the Wacom tablets that have SW_MUTE_DEVICE
on the device itself.

Should we have a separate event type for the current state of the switch
when the device is added? I think sending a EVENT_SWITCH_TOGGLE burst on
DEVICE_ADDED is sufficient. There will also be a
libinput_device_switch_has_switch() and
libinput_device_switch_get_switch_state() that do the obvious thing.

comments, etc. welcome. Any typos you can safely ignore for now, this is
just a first draft :)

Cheers,
   Peter
---
 doc/Makefile.am        |  1 +
 doc/switches.dox       | 14 ++++++++
 src/libinput-private.h |  6 ++++
 src/libinput.c         | 80 ++++++++++++++++++++++++++++++++++++++++++++
 src/libinput.h         | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/libinput.sym       |  7 ++++
 6 files changed, 198 insertions(+)
 create mode 100644 doc/switches.dox

diff --git a/doc/Makefile.am b/doc/Makefile.am
index fe70f6a..84eb033 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -22,6 +22,7 @@ header_files = \
 	$(srcdir)/reporting-bugs.dox \
 	$(srcdir)/scrolling.dox \
 	$(srcdir)/seats.dox \
+	$(srcdir)/switches.dox \
 	$(srcdir)/t440-support.dox \
 	$(srcdir)/tapping.dox \
 	$(srcdir)/test-suite.dox \
diff --git a/doc/switches.dox b/doc/switches.dox
new file mode 100644
index 0000000..ae070560
--- /dev/null
+++ b/doc/switches.dox
@@ -0,0 +1,14 @@
+/**
+ at page switches Switches
+
+libinput supports a couple of switches. Unlike button events that come in
+press and release pairs, switches are usually toggled once and left at the
+setting for an extended period of time.
+
+Only some switches are handled by libinput, see @ref libinput_switch for a
+list of supported switches. Switch events are exposed to the caller, but
+libinput may handle some switch events internally and enable or disable
+specific features based on a switch state.
+
+*/
+
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 51ac35e..91c843b 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -444,6 +444,12 @@ gesture_notify_pinch_end(struct libinput_device *device,
 			 double scale,
 			 int cancelled);
 
+void
+switch_notify_toggle(struct libinput_device *device,
+		     uint64_t time,
+		     enum libinput_switch sw,
+		     enum libinput_switch_state state);
+
 static inline uint64_t
 libinput_now(struct libinput *libinput)
 {
diff --git a/src/libinput.c b/src/libinput.c
index dd16ab7..120552b 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -125,6 +125,13 @@ struct libinput_event_gesture {
 	double angle;
 };
 
+struct libinput_event_switch {
+	struct libinput_event base;
+	uint64_t time;
+	enum libinput_switch sw;
+	enum libinput_switch_state state;
+};
+
 static void
 libinput_default_log_func(struct libinput *libinput,
 			  enum libinput_log_priority priority,
@@ -304,6 +311,17 @@ libinput_event_get_device_notify_event(struct libinput_event *event)
 	return (struct libinput_event_device_notify *) event;
 }
 
+LIBINPUT_EXPORT struct libinput_event_switch *
+libinput_event_get_switch_event(struct libinput_event *event)
+{
+	require_event_type(libinput_event_get_context(event),
+			   event->type,
+			   NULL,
+			   LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+	return (struct libinput_event_switch *) event;
+}
+
 LIBINPUT_EXPORT uint32_t
 libinput_event_keyboard_get_time(struct libinput_event_keyboard *event)
 {
@@ -884,6 +902,28 @@ libinput_event_gesture_get_angle_delta(struct libinput_event_gesture *event)
 	return event->angle;
 }
 
+LIBINPUT_EXPORT enum libinput_switch
+libinput_event_switch_get_switch(struct libinput_event_switch *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+	return event->sw;
+}
+
+LIBINPUT_EXPORT enum libinput_switch_state
+libinput_event_switch_get_switch_state(struct libinput_event_switch *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+	return event->state;
+}
+
 struct libinput_source *
 libinput_add_fd(struct libinput *libinput,
 		int fd,
@@ -1355,6 +1395,9 @@ device_has_cap(struct libinput_device *device,
 	case LIBINPUT_DEVICE_CAP_GESTURE:
 		capability = "CAP_GESTURE";
 		break;
+	case LIBINPUT_DEVICE_CAP_SWITCH:
+		capability = "CAP_SWITCH";
+		break;
 	}
 
 	log_bug_libinput(device->seat->libinput,
@@ -1694,6 +1737,32 @@ gesture_notify_pinch_end(struct libinput_device *device,
 		       2, cancelled, &zero, &zero, scale, 0.0);
 }
 
+void
+switch_notify_toggle(struct libinput_device *device,
+		     uint64_t time,
+		     enum libinput_switch sw,
+		     enum libinput_switch_state state)
+{
+	struct libinput_event_switch *switch_event;
+
+	if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_SWITCH))
+		return;
+
+	switch_event = zalloc(sizeof *switch_event);
+	if (!switch_event)
+		return;
+
+	*switch_event = (struct libinput_event_switch) {
+		.time = time,
+		.sw = sw,
+		.state = state,
+	};
+
+	post_device_event(device, time,
+			  LIBINPUT_EVENT_SWITCH_TOGGLE,
+			  &switch_event->base);
+}
+
 static void
 libinput_post_event(struct libinput *libinput,
 		    struct libinput_event *event)
@@ -1976,6 +2045,17 @@ libinput_event_gesture_get_base_event(struct libinput_event_gesture *event)
 	return &event->base;
 }
 
+LIBINPUT_EXPORT struct libinput_event *
+libinput_event_switch_get_base_event(struct libinput_event_switch *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   NULL,
+			   LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+	return &event->base;
+}
+
 LIBINPUT_EXPORT struct libinput_device_group *
 libinput_device_group_ref(struct libinput_device_group *group)
 {
diff --git a/src/libinput.h b/src/libinput.h
index 79d6e90..2c353ff 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -59,6 +59,7 @@ enum libinput_device_capability {
 	LIBINPUT_DEVICE_CAP_POINTER = 1,
 	LIBINPUT_DEVICE_CAP_TOUCH = 2,
 	LIBINPUT_DEVICE_CAP_GESTURE = 5,
+	LIBINPUT_DEVICE_CAP_SWITCH = 6,
 };
 
 /**
@@ -134,6 +135,34 @@ enum libinput_pointer_axis_source {
 };
 
 /**
+ * @ingroup device
+ *
+ * The type of a switch.
+ */
+enum libinput_switch {
+	/**
+	 * The laptop lid was closed or opened.
+	 */
+	LIBINPUT_SWITCH_LID = 1,
+	/**
+	 * The device was switched to or from tablet mode, usually by
+	 * rotating the screen and fixating it in place over the keyboard so
+	 * that the device now looks like a tablet.
+	 */
+	LIBINPUT_SWITCH_TABLET_MODE = 2,
+};
+
+/**
+ * @ingroup device
+ *
+ * The state of a switch.
+ */
+enum libinput_switch_state {
+	LIBINPUT_SWITCH_STATE_OFF = 0,
+	LIBINPUT_SWITCH_STATE_ON = 1,
+};
+
+/**
  * @ingroup base
  *
  * Event type for events returned by libinput_get_event().
@@ -185,6 +214,8 @@ enum libinput_event_type {
 	LIBINPUT_EVENT_GESTURE_PINCH_BEGIN,
 	LIBINPUT_EVENT_GESTURE_PINCH_UPDATE,
 	LIBINPUT_EVENT_GESTURE_PINCH_END,
+
+	LIBINPUT_EVENT_SWITCH_TOGGLE = 900,
 };
 
 /**
@@ -274,6 +305,14 @@ struct libinput_event_pointer;
 struct libinput_event_touch;
 
 /**
+ * @ingroup event_switch
+ * @struct libinput_event_switch
+ *
+ * A switch event representing a changed state in a switch.
+ */
+struct libinput_event_switch;
+
+/**
  * @defgroup event Accessing and destruction of events
  */
 
@@ -384,6 +423,19 @@ libinput_event_get_gesture_event(struct libinput_event *event);
 /**
  * @ingroup event
  *
+ * Return the switch event that is this input event. If the event type does
+ * not match the switch event types, this function returns NULL.
+ *
+ * The inverse of this function is libinput_event_switch_get_base_event().
+ *
+ * @return A switch event, or NULL for other events
+ */
+struct libinput_event_switch *
+libinput_event_get_switch_event(struct libinput_event *event);
+
+/**
+ * @ingroup event
+ *
  * Return the device event that is this input event. If the event type does
  * not match the device event types, this function returns NULL.
  *
@@ -1170,6 +1222,44 @@ double
 libinput_event_gesture_get_angle_delta(struct libinput_event_gesture *event);
 
 /**
+ * @ingroup event_switch
+ *
+ * Return the switch that triggered this event.
+ * For pointer events that are not of type @ref
+ * LIBINPUT_EVENT_SWITCH_TOGGLE, this function returns 0.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_SWITCH_TOGGLE.
+ *
+ * @return The switch triggering this event
+ */
+enum libinput_switch
+libinput_event_switch_get_switch(struct libinput_event_switch *event);
+
+/**
+ * @ingroup event_switch
+ *
+ * Return the switch state that triggered this event.
+ * For switch events that are not of type @ref
+ * LIBINPUT_EVENT_SWITCH_TOGGLE, this function returns 0.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_SWITCH_TOGGLE.
+ *
+ * @return The switch state triggering this event
+ */
+enum libinput_switch_state
+libinput_event_switch_get_switch_state(struct libinput_event_switch *event);
+
+/**
+ * @ingroup event_switch
+ *
+ * @return The generic libinput_event of this event
+ */
+struct libinput_event *
+libinput_event_switch_get_base_event(struct libinput_event_switch *event);
+
+/**
  * @defgroup base Initialization and manipulation of libinput contexts
  */
 
diff --git a/src/libinput.sym b/src/libinput.sym
index 15203c8..5b1efee 100644
--- a/src/libinput.sym
+++ b/src/libinput.sym
@@ -179,3 +179,10 @@ LIBINPUT_1.1 {
 	libinput_device_config_accel_get_default_profile;
 	libinput_device_config_accel_set_profile;
 } LIBINPUT_0.21.0;
+
+LIBINPUT_SWITCH {
+	libinput_event_get_switch_event;
+	libinput_event_switch_get_base_event;
+	libinput_event_switch_get_switch_state;
+	libinput_event_switch_get_switch;
+} LIBINPUT_1.1;
-- 
2.5.0



More information about the wayland-devel mailing list