int
tp_init_gesture(struct tp_dispatch *tp)
{
	libinput_timer_init(&tp->gesture.finger_count_switch_timer,
			    tp->device->base.seat->libinput,
			    tp_gesture_finger_count_switch_timeout, tp);
	return 0;
}
int
tp_init_buttons(struct tp_dispatch *tp,
                struct evdev_device *device)
{
    struct libinput *libinput = tp_libinput_context(tp);
    struct tp_touch *t;
    const struct input_absinfo *absinfo_x, *absinfo_y;

    tp->buttons.is_clickpad = libevdev_has_property(device->evdev,
                              INPUT_PROP_BUTTONPAD);
    tp->buttons.has_topbuttons = libevdev_has_property(device->evdev,
                                 INPUT_PROP_TOPBUTTONPAD);

    if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) ||
            libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) {
        if (tp->buttons.is_clickpad)
            log_bug_kernel(libinput,
                           "%s: clickpad advertising right button\n",
                           device->devname);
    } else if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_LEFT) &&
               !tp->buttons.is_clickpad &&
               libevdev_get_id_vendor(device->evdev) != VENDOR_ID_APPLE) {
        log_bug_kernel(libinput,
                       "%s: non clickpad without right button?\n",
                       device->devname);
    }

    absinfo_x = device->abs.absinfo_x;
    absinfo_y = device->abs.absinfo_y;

    /* pinned-finger motion threshold, see tp_unpin_finger. */
    tp->buttons.motion_dist.x_scale_coeff = 1.0/absinfo_x->resolution;
    tp->buttons.motion_dist.y_scale_coeff = 1.0/absinfo_y->resolution;

    tp->buttons.config_method.get_methods = tp_button_config_click_get_methods;
    tp->buttons.config_method.set_method = tp_button_config_click_set_method;
    tp->buttons.config_method.get_method = tp_button_config_click_get_method;
    tp->buttons.config_method.get_default_method = tp_button_config_click_get_default_method;
    tp->device->base.config.click_method = &tp->buttons.config_method;

    tp->buttons.click_method = tp_click_get_default_method(tp);
    tp_switch_click_method(tp);

    tp_init_top_softbuttons(tp, device, 1.0);

    tp_init_middlebutton_emulation(tp, device);

    tp_for_each_touch(tp, t) {
        t->button.state = BUTTON_STATE_NONE;
        libinput_timer_init(&t->button.timer,
                            tp_libinput_context(tp),
                            tp_button_handle_timeout, t);
    }
int
tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device)
{
	struct tp_touch *t;
	int edge_width, edge_height;

	/* 7mm edge size */
	edge_width = device->abs.absinfo_x->resolution * 7;
	edge_height = device->abs.absinfo_y->resolution * 7;

	tp->scroll.right_edge = device->abs.absinfo_x->maximum - edge_width;
	tp->scroll.bottom_edge = device->abs.absinfo_y->maximum - edge_height;

	tp_for_each_touch(tp, t) {
		t->scroll.direction = -1;
		libinput_timer_init(&t->scroll.timer,
				    tp_libinput_context(tp),
				    tp_edge_scroll_handle_timeout, t);
	}
void
evdev_init_middlebutton(struct evdev_device *device,
			bool enable,
			bool want_config)
{
	libinput_timer_init(&device->middlebutton.timer,
			    device->base.seat->libinput,
			    evdev_middlebutton_handle_timeout,
			    device);
	device->middlebutton.enabled_default = enable;
	device->middlebutton.want_enabled = enable;
	device->middlebutton.enabled = enable;

	if (!want_config)
		return;

	device->middlebutton.config.available = evdev_middlebutton_is_available;
	device->middlebutton.config.set = evdev_middlebutton_set;
	device->middlebutton.config.get = evdev_middlebutton_get;
	device->middlebutton.config.get_default = evdev_middlebutton_get_default;
	device->base.config.middle_emulation = &device->middlebutton.config;
}