[PATCH v3 libinput 06/10] pad: implement basic mode group support (1 group with 1 mode)

Peter Hutterer peter.hutterer at who-t.net
Fri Jun 24 03:44:34 UTC 2016


Until the kernel patches to handle LED group switching are in place we provide
the external API backed by an implementation that simply exposes one group
with one mode and no toggle buttons. This allows us to ship a libinput release
with the API in place and switch libinput later without having all the stack
above us being delayed.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Changes to v2:
This is the patch I'll actually merge onto master, the v2 patch I'll keep
on a branch for those actually needing modes to work for testing. This is
essentially the unifdef HAVE_LIBWACOM version of the old patch with a few
extra cleanups in place.

Why this patch? I won't merge the other one onto master, but I will release
libinput with this patch in place. That way we'll have the libinput API in
place and have other pieces able to rely on that API. Once the kernel
patches Benjamin is working on are in place we can switch libinput and
everything will magically start working. If we want for the kernel patches
to be in first we'll likely miss the next gnome release, delaying everything
even further.

 src/Makefile.am             |   1 +
 src/evdev-tablet-pad-leds.c | 177 ++++++++++++++++++++++++++++++++++++++++++++
 src/evdev-tablet-pad.c      |  76 +++++++++++++++++--
 src/evdev-tablet-pad.h      |  12 +++
 src/evdev.h                 |  16 ++++
 src/libinput-private.h      |  22 +++++-
 src/libinput-util.h         |   1 +
 src/libinput.c              |  74 ++++++++++++++----
 8 files changed, 357 insertions(+), 22 deletions(-)
 create mode 100644 src/evdev-tablet-pad-leds.c

diff --git a/src/Makefile.am b/src/Makefile.am
index 39c22c2..48e704a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,6 +22,7 @@ libinput_la_SOURCES =			\
 	evdev-tablet.h			\
 	evdev-tablet-pad.c		\
 	evdev-tablet-pad.h		\
+	evdev-tablet-pad-leds.c		\
 	filter.c			\
 	filter.h			\
 	filter-private.h		\
diff --git a/src/evdev-tablet-pad-leds.c b/src/evdev-tablet-pad-leds.c
new file mode 100644
index 0000000..8b162a6
--- /dev/null
+++ b/src/evdev-tablet-pad-leds.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright © 2016 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "evdev-tablet-pad.h"
+
+struct pad_led_group {
+	struct libinput_tablet_pad_mode_group base;
+};
+
+static void
+pad_led_group_destroy(struct libinput_tablet_pad_mode_group *g)
+{
+	struct pad_led_group *group = (struct pad_led_group *)g;
+
+	free(group);
+}
+
+static struct pad_led_group *
+pad_group_new_basic(struct pad_dispatch *pad,
+		    unsigned int group_index,
+		    int nleds)
+{
+	struct pad_led_group *group;
+
+	group = zalloc(sizeof *group);
+	if (!group)
+		return NULL;
+
+	group->base.device = &pad->device->base;
+	group->base.refcount = 1;
+	group->base.index = group_index;
+	group->base.current_mode = 0;
+	group->base.num_modes = nleds;
+	group->base.destroy = pad_led_group_destroy;
+
+	return group;
+}
+
+static inline struct libinput_tablet_pad_mode_group *
+pad_get_mode_group(struct pad_dispatch *pad, unsigned int index)
+{
+	struct libinput_tablet_pad_mode_group *group;
+
+	list_for_each(group, &pad->modes.mode_group_list, link) {
+		if (group->index == index)
+			return group;
+	}
+
+	return NULL;
+}
+
+static int
+pad_init_fallback_group(struct pad_dispatch *pad)
+{
+	struct pad_led_group *group;
+
+	group = pad_group_new_basic(pad, 0, 1);
+	if (!group)
+		return 1;
+
+	/* If we only have one group, all buttons/strips/rings are part of
+	 * that group. We rely on the other layers to filter out invalid
+	 * indices */
+	group->base.button_mask = -1;
+	group->base.strip_mask = -1;
+	group->base.ring_mask = -1;
+	group->base.toggle_button_mask = 0;
+
+	list_insert(&pad->modes.mode_group_list, &group->base.link);
+
+	return 0;
+}
+
+int
+pad_init_leds(struct pad_dispatch *pad,
+	      struct evdev_device *device)
+{
+	int rc = 1;
+
+	list_init(&pad->modes.mode_group_list);
+
+	if (pad->nbuttons > 32) {
+		log_bug_libinput(device->base.seat->libinput,
+				 "Too many pad buttons for modes %d\n",
+				 pad->nbuttons);
+		return rc;
+	}
+
+	/* Eventually we slot the libwacom-based led detection in here. That
+	 * requires getting the kernel ready first. For now we just init the
+	 * fallback single-mode group.
+	 */
+	rc = pad_init_fallback_group(pad);
+
+	return rc;
+}
+
+void
+pad_destroy_leds(struct pad_dispatch *pad)
+{
+	struct libinput_tablet_pad_mode_group *group, *tmpgrp;
+
+	list_for_each_safe(group, tmpgrp, &pad->modes.mode_group_list, link)
+		libinput_tablet_pad_mode_group_unref(group);
+}
+
+void
+pad_button_update_mode(struct libinput_tablet_pad_mode_group *g,
+		       unsigned int button_index,
+		       enum libinput_button_state state)
+{
+	struct pad_led_group *group = (struct pad_led_group*)g;
+
+	if (state != LIBINPUT_BUTTON_STATE_PRESSED)
+		return;
+
+	if (!libinput_tablet_pad_mode_group_button_is_toggle(g, button_index))
+		return;
+
+	log_bug_libinput(group->base.device->seat->libinput,
+			 "Button %d should not be a toggle button",
+			 button_index);
+}
+
+int
+evdev_device_tablet_pad_get_num_mode_groups(struct evdev_device *device)
+{
+	struct pad_dispatch *pad = (struct pad_dispatch*)device->dispatch;
+	struct libinput_tablet_pad_mode_group *group;
+	int num_groups = 0;
+
+	if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD))
+		return -1;
+
+	list_for_each(group, &pad->modes.mode_group_list, link)
+		num_groups++;
+
+	return num_groups;
+}
+
+struct libinput_tablet_pad_mode_group *
+evdev_device_tablet_pad_get_mode_group(struct evdev_device *device,
+				       unsigned int index)
+{
+	struct pad_dispatch *pad = (struct pad_dispatch*)device->dispatch;
+
+	if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD))
+		return NULL;
+
+	return pad_get_mode_group(pad, index);
+}
diff --git a/src/evdev-tablet-pad.c b/src/evdev-tablet-pad.c
index b7a2950..0e95408 100644
--- a/src/evdev-tablet-pad.c
+++ b/src/evdev-tablet-pad.c
@@ -209,12 +209,45 @@ pad_handle_strip(struct pad_dispatch *pad,
 	return pos;
 }
 
+static inline struct libinput_tablet_pad_mode_group *
+pad_ring_get_mode_group(struct pad_dispatch *pad,
+			unsigned int ring)
+{
+	struct libinput_tablet_pad_mode_group *group;
+
+	list_for_each(group, &pad->modes.mode_group_list, link) {
+		if (libinput_tablet_pad_mode_group_has_ring(group, ring))
+			return group;
+	}
+
+	assert(!"Unable to find ring mode group");
+
+	return NULL;
+}
+
+static inline struct libinput_tablet_pad_mode_group *
+pad_strip_get_mode_group(struct pad_dispatch *pad,
+			unsigned int strip)
+{
+	struct libinput_tablet_pad_mode_group *group;
+
+	list_for_each(group, &pad->modes.mode_group_list, link) {
+		if (libinput_tablet_pad_mode_group_has_strip(group, strip))
+			return group;
+	}
+
+	assert(!"Unable to find strip mode group");
+
+	return NULL;
+}
+
 static void
 pad_check_notify_axes(struct pad_dispatch *pad,
 		      struct evdev_device *device,
 		      uint64_t time)
 {
 	struct libinput_device *base = &device->base;
+	struct libinput_tablet_pad_mode_group *group;
 	double value;
 	bool send_finger_up = false;
 
@@ -229,11 +262,13 @@ pad_check_notify_axes(struct pad_dispatch *pad,
 		if (send_finger_up)
 			value = -1.0;
 
+		group = pad_ring_get_mode_group(pad, 0);
 		tablet_pad_notify_ring(base,
 				       time,
 				       0,
 				       value,
-				       LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER);
+				       LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER,
+				       group);
 	}
 
 	if (pad->changed_axes & PAD_AXIS_RING2) {
@@ -241,11 +276,13 @@ pad_check_notify_axes(struct pad_dispatch *pad,
 		if (send_finger_up)
 			value = -1.0;
 
+		group = pad_ring_get_mode_group(pad, 1);
 		tablet_pad_notify_ring(base,
 				       time,
 				       1,
 				       value,
-				       LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER);
+				       LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER,
+				       group);
 	}
 
 	if (pad->changed_axes & PAD_AXIS_STRIP1) {
@@ -253,11 +290,13 @@ pad_check_notify_axes(struct pad_dispatch *pad,
 		if (send_finger_up)
 			value = -1.0;
 
+		group = pad_strip_get_mode_group(pad, 0);
 		tablet_pad_notify_strip(base,
 					time,
 					0,
 					value,
-					LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER);
+					LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER,
+					group);
 	}
 
 	if (pad->changed_axes & PAD_AXIS_STRIP2) {
@@ -265,11 +304,13 @@ pad_check_notify_axes(struct pad_dispatch *pad,
 		if (send_finger_up)
 			value = -1.0;
 
+		group = pad_strip_get_mode_group(pad, 1);
 		tablet_pad_notify_strip(base,
 					time,
 					1,
 					value,
-					LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER);
+					LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER,
+					group);
 	}
 
 	pad->changed_axes = PAD_AXIS_NONE;
@@ -288,6 +329,22 @@ pad_process_key(struct pad_dispatch *pad,
 	pad_button_set_down(pad, button, is_press);
 }
 
+static inline struct libinput_tablet_pad_mode_group *
+pad_button_get_mode_group(struct pad_dispatch *pad,
+			  unsigned int button)
+{
+	struct libinput_tablet_pad_mode_group *group;
+
+	list_for_each(group, &pad->modes.mode_group_list, link) {
+		if (libinput_tablet_pad_mode_group_has_button(group, button))
+			return group;
+	}
+
+	assert(!"Unable to find button mode group\n");
+
+	return NULL;
+}
+
 static void
 pad_notify_button_mask(struct pad_dispatch *pad,
 		       struct evdev_device *device,
@@ -296,6 +353,7 @@ pad_notify_button_mask(struct pad_dispatch *pad,
 		       enum libinput_button_state state)
 {
 	struct libinput_device *base = &device->base;
+	struct libinput_tablet_pad_mode_group *group;
 	int32_t code;
 	unsigned int i;
 
@@ -315,8 +373,11 @@ pad_notify_button_mask(struct pad_dispatch *pad,
 				continue;
 
 			map = pad->button_map[code - 1];
-			if (map != -1)
-				tablet_pad_notify_button(base, time, map, state);
+			if (map != -1) {
+				group = pad_button_get_mode_group(pad, map);
+				pad_button_update_mode(group, map, state);
+				tablet_pad_notify_button(base, time, map, state, group);
+			}
 		}
 	}
 }
@@ -437,6 +498,7 @@ pad_destroy(struct evdev_dispatch *dispatch)
 {
 	struct pad_dispatch *pad = (struct pad_dispatch*)dispatch;
 
+	pad_destroy_leds(pad);
 	free(pad);
 }
 
@@ -500,6 +562,8 @@ pad_init(struct pad_dispatch *pad, struct evdev_device *device)
 
 	pad_init_buttons(pad, device);
 	pad_init_left_handed(device);
+	if (pad_init_leds(pad, device) != 0)
+		return 1;
 
 	return 0;
 }
diff --git a/src/evdev-tablet-pad.h b/src/evdev-tablet-pad.h
index 84324bc..9002fca 100644
--- a/src/evdev-tablet-pad.h
+++ b/src/evdev-tablet-pad.h
@@ -64,6 +64,10 @@ struct pad_dispatch {
 		struct libinput_device_config_send_events config;
 		enum libinput_config_send_events_mode current_mode;
 	} sendevents;
+
+	struct {
+		struct list mode_group_list;
+	} modes;
 };
 
 static inline struct libinput *
@@ -72,4 +76,12 @@ pad_libinput_context(const struct pad_dispatch *pad)
 	return evdev_libinput_context(pad->device);
 }
 
+int
+pad_init_leds(struct pad_dispatch *pad, struct evdev_device *device);
+void
+pad_destroy_leds(struct pad_dispatch *pad);
+void
+pad_button_update_mode(struct libinput_tablet_pad_mode_group *g,
+		       unsigned int pressed_button,
+		       enum libinput_button_state state);
 #endif
diff --git a/src/evdev.h b/src/evdev.h
index ca13318..d5e2323 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -392,6 +392,22 @@ evdev_device_tablet_pad_get_num_rings(struct evdev_device *device);
 int
 evdev_device_tablet_pad_get_num_strips(struct evdev_device *device);
 
+int
+evdev_device_tablet_pad_get_num_mode_groups(struct evdev_device *device);
+
+struct libinput_tablet_pad_mode_group *
+evdev_device_tablet_pad_get_mode_group(struct evdev_device *device,
+				       unsigned int index);
+
+unsigned int
+evdev_device_tablet_pad_mode_group_get_button_target(
+				     struct libinput_tablet_pad_mode_group *g,
+				     unsigned int button_index);
+
+struct libinput_tablet_pad_led *
+evdev_device_tablet_pad_get_led(struct evdev_device *device,
+				unsigned int led);
+
 double
 evdev_device_transform_x(struct evdev_device *device,
 			 double x,
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 98cb419..b325707 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -330,9 +330,22 @@ struct libinput_tablet_tool {
 };
 
 struct libinput_tablet_pad_mode_group {
+	struct libinput_device *device;
 	struct list link;
 	int refcount;
 	void *user_data;
+
+	unsigned int index;
+	unsigned int num_modes;
+	unsigned int current_mode;
+
+	uint32_t button_mask;
+	uint32_t ring_mask;
+	uint32_t strip_mask;
+
+	uint32_t toggle_button_mask;
+
+	void (*destroy)(struct libinput_tablet_pad_mode_group *group);
 };
 
 struct libinput_event {
@@ -572,19 +585,22 @@ void
 tablet_pad_notify_button(struct libinput_device *device,
 			 uint64_t time,
 			 int32_t button,
-			 enum libinput_button_state state);
+			 enum libinput_button_state state,
+			 struct libinput_tablet_pad_mode_group *group);
 void
 tablet_pad_notify_ring(struct libinput_device *device,
 		       uint64_t time,
 		       unsigned int number,
 		       double value,
-		       enum libinput_tablet_pad_ring_axis_source source);
+		       enum libinput_tablet_pad_ring_axis_source source,
+		       struct libinput_tablet_pad_mode_group *group);
 void
 tablet_pad_notify_strip(struct libinput_device *device,
 			uint64_t time,
 			unsigned int number,
 			double value,
-			enum libinput_tablet_pad_strip_axis_source source);
+			enum libinput_tablet_pad_strip_axis_source source,
+			struct libinput_tablet_pad_mode_group *group);
 
 static inline uint64_t
 libinput_now(struct libinput *libinput)
diff --git a/src/libinput-util.h b/src/libinput-util.h
index 051d08f..a7ebc30 100644
--- a/src/libinput-util.h
+++ b/src/libinput-util.h
@@ -87,6 +87,7 @@ int list_empty(const struct list *list);
 	     pos = tmp,							\
 	     tmp = container_of(pos->member.next, tmp, member))
 
+#define NBITS(b) (b * 8)
 #define LONG_BITS (sizeof(long) * 8)
 #define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
diff --git a/src/libinput.c b/src/libinput.c
index a7892e1..cf0ed5b 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -1668,6 +1668,12 @@ libinput_event_tablet_tool_destroy(struct libinput_event_tablet_tool *event)
 	libinput_tablet_tool_unref(event->tool);
 }
 
+static void
+libinput_event_tablet_pad_destroy(struct libinput_event_tablet_pad *event)
+{
+	libinput_tablet_pad_mode_group_unref(event->mode_group);
+}
+
 LIBINPUT_EXPORT void
 libinput_event_destroy(struct libinput_event *event)
 {
@@ -1682,6 +1688,13 @@ libinput_event_destroy(struct libinput_event *event)
 		libinput_event_tablet_tool_destroy(
 		   libinput_event_get_tablet_tool_event(event));
 		break;
+	case LIBINPUT_EVENT_TABLET_PAD_RING:
+	case LIBINPUT_EVENT_TABLET_PAD_STRIP:
+	case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
+	case LIBINPUT_EVENT_TABLET_PAD_MODE:
+		libinput_event_tablet_pad_destroy(
+		   libinput_event_get_tablet_pad_event(event));
+		break;
 	default:
 		break;
 	}
@@ -2402,18 +2415,24 @@ void
 tablet_pad_notify_button(struct libinput_device *device,
 			 uint64_t time,
 			 int32_t button,
-			 enum libinput_button_state state)
+			 enum libinput_button_state state,
+			 struct libinput_tablet_pad_mode_group *group)
 {
 	struct libinput_event_tablet_pad *button_event;
+	unsigned int mode;
 
 	button_event = zalloc(sizeof *button_event);
 	if (!button_event)
 		return;
 
+	mode = libinput_tablet_pad_mode_group_get_mode(group);
+
 	*button_event = (struct libinput_event_tablet_pad) {
 		.time = time,
 		.button.number = button,
 		.button.state = state,
+		.mode_group = libinput_tablet_pad_mode_group_ref(group),
+		.mode = mode,
 	};
 
 	post_device_event(device,
@@ -2427,19 +2446,25 @@ tablet_pad_notify_ring(struct libinput_device *device,
 		       uint64_t time,
 		       unsigned int number,
 		       double value,
-		       enum libinput_tablet_pad_ring_axis_source source)
+		       enum libinput_tablet_pad_ring_axis_source source,
+		       struct libinput_tablet_pad_mode_group *group)
 {
 	struct libinput_event_tablet_pad *ring_event;
+	unsigned int mode;
 
 	ring_event = zalloc(sizeof *ring_event);
 	if (!ring_event)
 		return;
 
+	mode = libinput_tablet_pad_mode_group_get_mode(group);
+
 	*ring_event = (struct libinput_event_tablet_pad) {
 		.time = time,
 		.ring.number = number,
 		.ring.position = value,
 		.ring.source = source,
+		.mode_group = libinput_tablet_pad_mode_group_ref(group),
+		.mode = mode,
 	};
 
 	post_device_event(device,
@@ -2453,19 +2478,25 @@ tablet_pad_notify_strip(struct libinput_device *device,
 			uint64_t time,
 			unsigned int number,
 			double value,
-			enum libinput_tablet_pad_strip_axis_source source)
+			enum libinput_tablet_pad_strip_axis_source source,
+			struct libinput_tablet_pad_mode_group *group)
 {
 	struct libinput_event_tablet_pad *strip_event;
+	unsigned int mode;
 
 	strip_event = zalloc(sizeof *strip_event);
 	if (!strip_event)
 		return;
 
+	mode = libinput_tablet_pad_mode_group_get_mode(group);
+
 	*strip_event = (struct libinput_event_tablet_pad) {
 		.time = time,
 		.strip.number = number,
 		.strip.position = value,
 		.strip.source = source,
+		.mode_group = libinput_tablet_pad_mode_group_ref(group),
+		.mode = mode,
 	};
 
 	post_device_event(device,
@@ -2835,61 +2866,78 @@ libinput_device_tablet_pad_get_num_strips(struct libinput_device *device)
 LIBINPUT_EXPORT int
 libinput_device_tablet_pad_get_num_mode_groups(struct libinput_device *device)
 {
-	return 0;
+	return evdev_device_tablet_pad_get_num_mode_groups((struct evdev_device *)device);
 }
 
 LIBINPUT_EXPORT struct libinput_tablet_pad_mode_group*
 libinput_device_tablet_pad_get_mode_group(struct libinput_device *device,
 					  unsigned int index)
 {
-	return NULL;
+	return evdev_device_tablet_pad_get_mode_group((struct evdev_device *)device,
+						      index);
 }
 
 LIBINPUT_EXPORT unsigned int
 libinput_tablet_pad_mode_group_get_num_modes(
 				     struct libinput_tablet_pad_mode_group *group)
 {
-	return 1;
+	return group->num_modes;
 }
 
 LIBINPUT_EXPORT unsigned int
 libinput_tablet_pad_mode_group_get_mode(struct libinput_tablet_pad_mode_group *group)
 {
-	return 0;
+	return group->current_mode;
 }
 
 LIBINPUT_EXPORT unsigned int
 libinput_tablet_pad_mode_group_get_index(struct libinput_tablet_pad_mode_group *group)
 {
-	return 0;
+	return group->index;
 }
 
 LIBINPUT_EXPORT int
 libinput_tablet_pad_mode_group_has_button(struct libinput_tablet_pad_mode_group *group,
 					  unsigned int button)
 {
-	return 1;
+	if ((int)button >=
+	    libinput_device_tablet_pad_get_num_buttons(group->device))
+		return 0;
+
+	return !!(group->button_mask & (1 << button));
 }
 
 LIBINPUT_EXPORT int
 libinput_tablet_pad_mode_group_has_ring(struct libinput_tablet_pad_mode_group *group,
 					unsigned int ring)
 {
-	return 1;
+	if ((int)ring >=
+	    libinput_device_tablet_pad_get_num_rings(group->device))
+		return 0;
+
+	return !!(group->ring_mask & (1 << ring));
 }
 
 LIBINPUT_EXPORT int
 libinput_tablet_pad_mode_group_has_strip(struct libinput_tablet_pad_mode_group *group,
 					 unsigned int strip)
 {
-	return 1;
+	if ((int)strip >=
+	    libinput_device_tablet_pad_get_num_strips(group->device))
+		return 0;
+
+	return !!(group->strip_mask & (1 << strip));
 }
 
 LIBINPUT_EXPORT int
 libinput_tablet_pad_mode_group_button_is_toggle(struct libinput_tablet_pad_mode_group *group,
 						unsigned int button)
 {
-	return 0;
+	if ((int)button >=
+	    libinput_device_tablet_pad_get_num_buttons(group->device))
+		return 0;
+
+	return !!(group->toggle_button_mask & (1 << button));
 }
 
 LIBINPUT_EXPORT struct libinput_tablet_pad_mode_group *
@@ -2911,7 +2959,7 @@ libinput_tablet_pad_mode_group_unref(
 		return group;
 
 	list_remove(&group->link);
-	free(group);
+	group->destroy(group);
 	return NULL;
 }
 
-- 
2.7.4



More information about the wayland-devel mailing list