time + FORCED_PROXOUT_TIMEOUT);
}
-static void
+static bool
tablet_update_tool_state(struct tablet_dispatch *tablet,
struct evdev_device *device,
uint64_t time)
enum libinput_tablet_tool_type type;
uint32_t changed;
int state;
+ uint32_t doubled_up_new_tool_bit = 0;
/* We need to emulate a BTN_TOOL_PEN if we get an axis event (i.e.
* stylus is def. in proximity) and:
}
if (tablet->tool_state == tablet->prev_tool_state)
- return;
+ return false;
/* Kernel tools are supposed to be mutually exclusive, if we have
- * two set discard the most recent one. */
+ * two, we force a proximity out for the older tool and handle the
+ * new tool as separate proximity in event.
+ */
if (tablet->tool_state & (tablet->tool_state - 1)) {
- evdev_log_bug_kernel(device,
- "Multiple tools active simultaneously (%#x)\n",
- tablet->tool_state);
- tablet->tool_state = tablet->prev_tool_state;
- goto out;
+ /* tool_state has 2 bits set. We set the current tool state
+ * to zero, thus setting everything up for a prox out on the
+ * tool. Once that is set up, we change the tool state to be
+ * the new one we just got so when we re-process this
+ * function we now get the new tool as prox in.
+ * Importantly, we basically rely on nothing else happening
+ * in the meantime.
+ */
+ doubled_up_new_tool_bit = tablet->tool_state ^ tablet->prev_tool_state;
+ tablet->tool_state = 0;
}
changed = tablet->tool_state ^ tablet->prev_tool_state;
}
}
-out:
tablet->prev_tool_state = tablet->tool_state;
+ if (doubled_up_new_tool_bit) {
+ tablet->tool_state = doubled_up_new_tool_bit;
+ return true; /* need to re-process */
+ }
+ return false;
}
static struct libinput_tablet_tool *
uint64_t time)
{
struct libinput_tablet_tool *tool;
+ bool process_tool_twice;
- tablet_update_tool_state(tablet, device, time);
+reprocess:
+ process_tool_twice = tablet_update_tool_state(tablet, device, time);
tool = tablet_get_current_tool(tablet);
if (!tool)
}
tablet_send_events(tablet, tool, device, time);
+
+ if (process_tool_twice)
+ goto reprocess;
}
static inline void
libinput_tablet_tool_ref(tool);
libinput_event_destroy(event);
- /* Direct tool switch after proximity in is ignored */
- litest_disable_log_handler(li);
litest_event(dev, EV_KEY, BTN_TOOL_RUBBER, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
- litest_assert_empty_queue(li);
- litest_restore_log_handler(li);
+ libinput_dispatch(li);
+
+ event = libinput_get_event(li);
+ tev = litest_is_tablet_event(event,
+ LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
+ ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(tev),
+ LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
+ ck_assert_ptr_eq(libinput_event_tablet_tool_get_tool(tev), tool);
+ libinput_event_destroy(event);
+
+ event = libinput_get_event(li);
+ tev = litest_is_tablet_event(event,
+ LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
+ ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(tev),
+ LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
+ ck_assert_ptr_ne(libinput_event_tablet_tool_get_tool(tev), tool);
+ libinput_tablet_tool_unref(tool);
+ tool = libinput_event_tablet_tool_get_tool(tev);
+ libinput_tablet_tool_ref(tool);
+ libinput_event_destroy(event);
litest_tablet_motion(dev, 20, 30, axes);
libinput_dispatch(li);
tool);
libinput_event_destroy(event);
- /* Direct tool switch during sequence in is ignored */
- litest_disable_log_handler(li);
litest_event(dev, EV_KEY, BTN_TOOL_RUBBER, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
- litest_assert_empty_queue(li);
+ libinput_dispatch(li);
+
+ event = libinput_get_event(li);
+ tev = litest_is_tablet_event(event,
+ LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
+ ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(tev),
+ LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
+ ck_assert_ptr_eq(libinput_event_tablet_tool_get_tool(tev),
+ tool);
+ libinput_event_destroy(event);
litest_push_event_frame(dev);
litest_event(dev, EV_KEY, BTN_TOOL_RUBBER, 1);
litest_tablet_motion(dev, 30, 40, axes);
litest_pop_event_frame(dev);
libinput_dispatch(li);
- litest_restore_log_handler(li);
+
+ event = libinput_get_event(li);
+ tev = litest_is_tablet_event(event,
+ LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
+ ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(tev),
+ LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
+ ck_assert_ptr_eq(libinput_event_tablet_tool_get_tool(tev),
+ tool);
+ libinput_event_destroy(event);
+
+ litest_tablet_motion(dev, 40, 30, axes);
+ libinput_dispatch(li);
event = libinput_get_event(li);
tev = litest_is_tablet_event(event,
tool);
libinput_event_destroy(event);
+ litest_push_event_frame(dev);
+ litest_event(dev, EV_KEY, BTN_TOOL_RUBBER, 0);
litest_tablet_proximity_out(dev);
+ litest_pop_event_frame(dev);
libinput_dispatch(li);
litest_timeout_tablet_proxout();
libinput_dispatch(li);