touchpad: check calloc result
[platform/upstream/libinput.git] / src / evdev-mt-touchpad.c
1 /*
2  * Copyright © 2014 Red Hat, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of the copyright holders not be used in
9  * advertising or publicity pertaining to distribution of the software
10  * without specific, written prior permission.  The copyright holders make
11  * no representations about the suitability of this software for any
12  * purpose.  It is provided "as is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22
23 #include "config.h"
24
25 #include <assert.h>
26 #include <math.h>
27 #include <stdbool.h>
28
29 #include "evdev-mt-touchpad.h"
30
31 #define DEFAULT_CONSTANT_ACCEL_NUMERATOR 50
32 #define DEFAULT_MIN_ACCEL_FACTOR 0.16
33 #define DEFAULT_MAX_ACCEL_FACTOR 1.0
34 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
35
36 static inline int
37 tp_hysteresis(int in, int center, int margin)
38 {
39         int diff = in - center;
40         if (abs(diff) <= margin)
41                 return center;
42
43         if (diff > margin)
44                 return center + diff - margin;
45         else if (diff < -margin)
46                 return center + diff + margin;
47         return center + diff;
48 }
49
50 static double
51 tp_accel_profile(struct motion_filter *filter,
52                  void *data,
53                  double velocity,
54                  uint32_t time)
55 {
56         struct tp_dispatch *tp =
57                 (struct tp_dispatch *) data;
58
59         double accel_factor;
60
61         accel_factor = velocity * tp->accel.constant_factor;
62
63         if (accel_factor > tp->accel.max_factor)
64                 accel_factor = tp->accel.max_factor;
65         else if (accel_factor < tp->accel.min_factor)
66                 accel_factor = tp->accel.min_factor;
67
68         return accel_factor;
69 }
70
71 static inline struct tp_motion *
72 tp_motion_history_offset(struct tp_touch *t, int offset)
73 {
74         int offset_index =
75                 (t->history.index - offset + TOUCHPAD_HISTORY_LENGTH) %
76                 TOUCHPAD_HISTORY_LENGTH;
77
78         return &t->history.samples[offset_index];
79 }
80
81 static void
82 tp_filter_motion(struct tp_dispatch *tp,
83                  double *dx, double *dy, uint32_t time)
84 {
85         struct motion_params motion;
86
87         motion.dx = *dx;
88         motion.dy = *dy;
89
90         filter_dispatch(tp->filter, &motion, tp, time);
91
92         *dx = motion.dx;
93         *dy = motion.dy;
94 }
95
96 static inline void
97 tp_motion_history_push(struct tp_touch *t)
98 {
99         int motion_index = (t->history.index + 1) % TOUCHPAD_HISTORY_LENGTH;
100
101         if (t->history.count < TOUCHPAD_HISTORY_LENGTH)
102                 t->history.count++;
103
104         t->history.samples[motion_index].x = t->x;
105         t->history.samples[motion_index].y = t->y;
106         t->history.index = motion_index;
107 }
108
109 static inline void
110 tp_motion_hysteresis(struct tp_dispatch *tp,
111                      struct tp_touch *t)
112 {
113         int x = t->x,
114             y = t->y;
115
116         if (t->history.count == 0) {
117                 t->hysteresis.center_x = t->x;
118                 t->hysteresis.center_y = t->y;
119         } else {
120                 x = tp_hysteresis(x,
121                                   t->hysteresis.center_x,
122                                   tp->hysteresis.margin_x);
123                 y = tp_hysteresis(y,
124                                   t->hysteresis.center_y,
125                                   tp->hysteresis.margin_y);
126                 t->hysteresis.center_x = x;
127                 t->hysteresis.center_y = y;
128                 t->x = x;
129                 t->y = y;
130         }
131 }
132
133 static inline void
134 tp_motion_history_reset(struct tp_touch *t)
135 {
136         t->history.count = 0;
137 }
138
139 static inline struct tp_touch *
140 tp_current_touch(struct tp_dispatch *tp)
141 {
142         return &tp->touches[min(tp->slot, tp->ntouches)];
143 }
144
145 static inline struct tp_touch *
146 tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
147 {
148         assert(slot < tp->ntouches);
149         return &tp->touches[slot];
150 }
151
152 static inline void
153 tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t)
154 {
155         struct tp_touch *tmp = NULL;
156
157         if (t->state != TOUCH_UPDATE) {
158                 tp_motion_history_reset(t);
159                 t->dirty = true;
160                 t->state = TOUCH_BEGIN;
161                 tp->nfingers_down++;
162                 assert(tp->nfingers_down >= 1);
163                 tp->queued |= TOUCHPAD_EVENT_MOTION;
164
165                 tp_for_each_touch(tp, tmp) {
166                         if (tmp->is_pointer)
167                                 break;
168                 }
169
170                 if (!tmp->is_pointer) {
171                         t->is_pointer = true;
172                 }
173         }
174 }
175
176 static inline void
177 tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t)
178 {
179         if (t->state == TOUCH_NONE)
180                 return;
181
182         t->dirty = true;
183         t->is_pointer = false;
184         t->state = TOUCH_END;
185         assert(tp->nfingers_down >= 1);
186         tp->nfingers_down--;
187         tp->queued |= TOUCHPAD_EVENT_MOTION;
188 }
189
190 static double
191 tp_estimate_delta(int x0, int x1, int x2, int x3)
192 {
193         return (x0 + x1 - x2 - x3) / 4;
194 }
195
196 void
197 tp_get_delta(struct tp_touch *t, double *dx, double *dy)
198 {
199         if (t->history.count < 4) {
200                 *dx = 0;
201                 *dy = 0;
202                 return;
203         }
204
205         *dx = tp_estimate_delta(tp_motion_history_offset(t, 0)->x,
206                                 tp_motion_history_offset(t, 1)->x,
207                                 tp_motion_history_offset(t, 2)->x,
208                                 tp_motion_history_offset(t, 3)->x);
209         *dy = tp_estimate_delta(tp_motion_history_offset(t, 0)->y,
210                                 tp_motion_history_offset(t, 1)->y,
211                                 tp_motion_history_offset(t, 2)->y,
212                                 tp_motion_history_offset(t, 3)->y);
213 }
214
215 static void
216 tp_process_absolute(struct tp_dispatch *tp,
217                     const struct input_event *e,
218                     uint32_t time)
219 {
220         struct tp_touch *t = tp_current_touch(tp);
221
222         switch(e->code) {
223         case ABS_MT_POSITION_X:
224                 t->x = e->value;
225                 t->millis = time;
226                 t->dirty = true;
227                 tp->queued |= TOUCHPAD_EVENT_MOTION;
228                 break;
229         case ABS_MT_POSITION_Y:
230                 t->y = e->value;
231                 t->millis = time;
232                 t->dirty = true;
233                 tp->queued |= TOUCHPAD_EVENT_MOTION;
234                 break;
235         case ABS_MT_SLOT:
236                 tp->slot = e->value;
237                 break;
238         case ABS_MT_TRACKING_ID:
239                 t->millis = time;
240                 if (e->value != -1)
241                         tp_begin_touch(tp, t);
242                 else
243                         tp_end_touch(tp, t);
244         }
245 }
246
247 static void
248 tp_process_absolute_st(struct tp_dispatch *tp,
249                        const struct input_event *e,
250                        uint32_t time)
251 {
252         struct tp_touch *t = tp_current_touch(tp);
253
254         switch(e->code) {
255         case ABS_X:
256                 t->x = e->value;
257                 t->millis = time;
258                 t->dirty = true;
259                 tp->queued |= TOUCHPAD_EVENT_MOTION;
260                 break;
261         case ABS_Y:
262                 t->y = e->value;
263                 t->millis = time;
264                 t->dirty = true;
265                 tp->queued |= TOUCHPAD_EVENT_MOTION;
266                 break;
267         }
268 }
269
270 static void
271 tp_process_fake_touch(struct tp_dispatch *tp,
272                       const struct input_event *e,
273                       uint32_t time)
274 {
275         struct tp_touch *t;
276         unsigned int fake_touches;
277         unsigned int nfake_touches;
278         unsigned int i;
279         unsigned int shift;
280
281         if (e->code != BTN_TOUCH &&
282             (e->code < BTN_TOOL_DOUBLETAP || e->code > BTN_TOOL_QUADTAP))
283                 return;
284
285         shift = e->code == BTN_TOUCH ? 0 : (e->code - BTN_TOOL_DOUBLETAP + 1);
286
287         if (e->value)
288                 tp->fake_touches |= 1 << shift;
289         else
290                 tp->fake_touches &= ~(0x1 << shift);
291
292         fake_touches = tp->fake_touches;
293         nfake_touches = 0;
294         while (fake_touches) {
295                 nfake_touches++;
296                 fake_touches >>= 1;
297         }
298
299         for (i = 0; i < tp->ntouches; i++) {
300                 t = tp_get_touch(tp, i);
301                 if (i >= nfake_touches) {
302                         if (t->state != TOUCH_NONE) {
303                                 tp_end_touch(tp, t);
304                                 t->millis = time;
305                         }
306                 } else if (t->state != TOUCH_UPDATE &&
307                            t->state != TOUCH_BEGIN) {
308                         t->state = TOUCH_NONE;
309                         tp_begin_touch(tp, t);
310                         t->millis = time;
311                         t->fake =true;
312                 }
313         }
314
315         assert(tp->nfingers_down == nfake_touches);
316 }
317
318 static void
319 tp_process_key(struct tp_dispatch *tp,
320                const struct input_event *e,
321                uint32_t time)
322 {
323         uint32_t mask;
324
325         switch (e->code) {
326                 case BTN_LEFT:
327                 case BTN_MIDDLE:
328                 case BTN_RIGHT:
329                         mask = 1 << (e->code - BTN_LEFT);
330                         if (e->value) {
331                                 tp->buttons.state |= mask;
332                                 tp->queued |= TOUCHPAD_EVENT_BUTTON_PRESS;
333                         } else {
334                                 tp->buttons.state &= ~mask;
335                                 tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE;
336                         }
337                         break;
338                 case BTN_TOUCH:
339                 case BTN_TOOL_DOUBLETAP:
340                 case BTN_TOOL_TRIPLETAP:
341                 case BTN_TOOL_QUADTAP:
342                         if (!tp->has_mt)
343                                 tp_process_fake_touch(tp, e, time);
344                         break;
345         }
346 }
347
348 static void
349 tp_unpin_finger(struct tp_dispatch *tp)
350 {
351         struct tp_touch *t;
352         tp_for_each_touch(tp, t) {
353                 if (t->is_pinned) {
354                         t->is_pinned = false;
355
356                         if (t->state != TOUCH_END &&
357                             tp->nfingers_down == 1)
358                                 t->is_pointer = true;
359                         break;
360                 }
361         }
362 }
363
364 static void
365 tp_pin_finger(struct tp_dispatch *tp)
366 {
367         struct tp_touch *t,
368                         *pinned = NULL;
369
370         tp_for_each_touch(tp, t) {
371                 if (t->is_pinned) {
372                         pinned = t;
373                         break;
374                 }
375         }
376
377         assert(!pinned);
378
379         pinned = tp_current_touch(tp);
380
381         if (tp->nfingers_down != 1) {
382                 tp_for_each_touch(tp, t) {
383                         if (t == pinned)
384                                 continue;
385
386                         if (t->y > pinned->y)
387                                 pinned = t;
388                 }
389         }
390
391         pinned->is_pinned = true;
392         pinned->is_pointer = false;
393 }
394
395 static void
396 tp_process_state(struct tp_dispatch *tp, uint32_t time)
397 {
398         struct tp_touch *t;
399         struct tp_touch *first = tp_get_touch(tp, 0);
400
401         tp_for_each_touch(tp, t) {
402                 if (!tp->has_mt && t != first && first->fake) {
403                         t->x = first->x;
404                         t->y = first->y;
405                         if (!t->dirty)
406                                 t->dirty = first->dirty;
407                 } else if (!t->dirty)
408                         continue;
409
410                 tp_motion_hysteresis(tp, t);
411                 tp_motion_history_push(t);
412         }
413
414         /* We have a physical button down event on a clickpad. For drag and
415            drop, this means we try to identify which finger pressed the
416            physical button and "pin" it, i.e. remove pointer-moving
417            capabilities from it.
418          */
419         if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) &&
420             !tp->buttons.has_buttons)
421                 tp_pin_finger(tp);
422 }
423
424 static void
425 tp_post_process_state(struct tp_dispatch *tp, uint32_t time)
426 {
427         struct tp_touch *t;
428
429         tp_for_each_touch(tp, t) {
430                 if (!t->dirty)
431                         continue;
432
433                 if (t->state == TOUCH_END) {
434                         t->state = TOUCH_NONE;
435                         t->fake = false;
436                 } else if (t->state == TOUCH_BEGIN)
437                         t->state = TOUCH_UPDATE;
438
439                 t->dirty = false;
440         }
441
442         tp->buttons.old_state = tp->buttons.state;
443
444         if (tp->queued & TOUCHPAD_EVENT_BUTTON_RELEASE)
445                 tp_unpin_finger(tp);
446
447         tp->queued = TOUCHPAD_EVENT_NONE;
448 }
449
450 static void
451 tp_post_twofinger_scroll(struct tp_dispatch *tp, uint32_t time)
452 {
453         struct tp_touch *t;
454         int nchanged = 0;
455         double dx = 0, dy =0;
456         double tmpx, tmpy;
457
458         tp_for_each_touch(tp, t) {
459                 if (t->dirty) {
460                         nchanged++;
461                         tp_get_delta(t, &tmpx, &tmpy);
462
463                         dx += tmpx;
464                         dy += tmpy;
465                 }
466         }
467
468         if (nchanged == 0)
469                 return;
470
471         dx /= nchanged;
472         dy /= nchanged;
473
474         tp_filter_motion(tp, &dx, &dy, time);
475
476         if (tp->scroll.state == SCROLL_STATE_NONE) {
477                 /* Require at least one px scrolling to start */
478                 if (dx <= -1.0 || dx >= 1.0) {
479                         tp->scroll.state = SCROLL_STATE_SCROLLING;
480                         tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL);
481                 }
482
483                 if (dy <= -1.0 || dy >= 1.0) {
484                         tp->scroll.state = SCROLL_STATE_SCROLLING;
485                         tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL);
486                 }
487
488                 if (tp->scroll.state == SCROLL_STATE_NONE)
489                         return;
490         }
491
492         if (dy != 0.0 &&
493             (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL))) {
494                 pointer_notify_axis(&tp->device->base,
495                                     time,
496                                     LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL,
497                                     li_fixed_from_double(dy));
498         }
499
500         if (dx != 0.0 &&
501             (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL))) {
502                 pointer_notify_axis(&tp->device->base,
503                                     time,
504                                     LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL,
505                                     li_fixed_from_double(dx));
506         }
507 }
508
509 static int
510 tp_post_scroll_events(struct tp_dispatch *tp, uint32_t time)
511 {
512         /* don't scroll if a clickpad is held down */
513         if (!tp->buttons.has_buttons &&
514             (tp->buttons.state || tp->buttons.old_state))
515                 return 0;
516
517         if (tp->nfingers_down != 2) {
518                 /* terminate scrolling with a zero scroll event to notify
519                  * caller that it really ended now */
520                 if (tp->scroll.state != SCROLL_STATE_NONE) {
521                         tp->scroll.state = SCROLL_STATE_NONE;
522                         tp->scroll.direction = 0;
523                         if (tp->scroll.direction & LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL)
524                                 pointer_notify_axis(&tp->device->base,
525                                                     time,
526                                                     LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL,
527                                                     0);
528                         if (tp->scroll.direction & LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL)
529                                 pointer_notify_axis(&tp->device->base,
530                                                     time,
531                                                     LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL,
532                                                     0);
533                 }
534         } else {
535                 tp_post_twofinger_scroll(tp, time);
536                 return 1;
537         }
538         return 0;
539 }
540
541 static int
542 tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint32_t time)
543 {
544         uint32_t current, old, button;
545         enum libinput_pointer_button_state state;
546
547         current = tp->buttons.state;
548         old = tp->buttons.old_state;
549
550         if (current == old)
551                 return 0;
552
553         switch (tp->nfingers_down) {
554                 case 1: button = BTN_LEFT; break;
555                 case 2: button = BTN_RIGHT; break;
556                 case 3: button = BTN_MIDDLE; break;
557                 default:
558                         return 0;
559         }
560
561         if (current)
562                 state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED;
563         else
564                 state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED;
565
566         pointer_notify_button(&tp->device->base,
567                               time,
568                               button,
569                               state);
570         return 1;
571 }
572
573 static int
574 tp_post_physical_buttons(struct tp_dispatch *tp, uint32_t time)
575 {
576         uint32_t current, old, button;
577
578         current = tp->buttons.state;
579         old = tp->buttons.old_state;
580         button = BTN_LEFT;
581
582         while (current || old) {
583                 enum libinput_pointer_button_state state;
584
585                 if ((current & 0x1) ^ (old & 0x1)) {
586                         if (!!(current & 0x1))
587                                 state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED;
588                         else
589                                 state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED;
590
591                         pointer_notify_button(&tp->device->base,
592                                               time,
593                                               button,
594                                               state);
595                 }
596
597                 button++;
598                 current >>= 1;
599                 old >>= 1;
600         }
601
602         return 0;
603 }
604
605 static int
606 tp_post_button_events(struct tp_dispatch *tp, uint32_t time)
607 {
608         int rc;
609
610         if ((tp->queued &
611                 (TOUCHPAD_EVENT_BUTTON_PRESS|TOUCHPAD_EVENT_BUTTON_RELEASE)) == 0)
612                                 return 0;
613
614         if (tp->buttons.has_buttons)
615                 rc = tp_post_physical_buttons(tp, time);
616         else
617                 rc = tp_post_clickfinger_buttons(tp, time);
618
619         return rc;
620 }
621
622 static void
623 tp_post_events(struct tp_dispatch *tp, uint32_t time)
624 {
625         struct tp_touch *t = tp_current_touch(tp);
626         double dx, dy;
627
628         if (tp_post_button_events(tp, time) != 0)
629                 return;
630
631         if (tp_tap_handle_state(tp, time) != 0)
632                 return;
633
634         if (tp_post_scroll_events(tp, time) != 0)
635                 return;
636
637         if (t->history.count >= TOUCHPAD_MIN_SAMPLES) {
638                 if (!t->is_pointer) {
639                         tp_for_each_touch(tp, t) {
640                                 if (t->is_pointer)
641                                         break;
642                         }
643                 }
644
645                 if (!t->is_pointer)
646                         return;
647
648                 tp_get_delta(t, &dx, &dy);
649                 tp_filter_motion(tp, &dx, &dy, time);
650
651                 if (dx != 0 || dy != 0)
652                         pointer_notify_motion(
653                                 &tp->device->base,
654                                 time,
655                                 li_fixed_from_double(dx),
656                                 li_fixed_from_double(dy));
657         }
658 }
659
660 static void
661 tp_process(struct evdev_dispatch *dispatch,
662            struct evdev_device *device,
663            struct input_event *e,
664            uint32_t time)
665 {
666         struct tp_dispatch *tp =
667                 (struct tp_dispatch *)dispatch;
668
669         switch (e->type) {
670         case EV_ABS:
671                 if (tp->has_mt)
672                         tp_process_absolute(tp, e, time);
673                 else
674                         tp_process_absolute_st(tp, e, time);
675                 break;
676         case EV_KEY:
677                 tp_process_key(tp, e, time);
678                 break;
679         case EV_SYN:
680                 tp_process_state(tp, time);
681                 tp_post_events(tp, time);
682                 tp_post_process_state(tp, time);
683                 break;
684         }
685 }
686
687 static void
688 tp_destroy(struct evdev_dispatch *dispatch)
689 {
690         struct tp_dispatch *tp =
691                 (struct tp_dispatch*)dispatch;
692
693         tp_destroy_tap(tp);
694
695         if (tp->filter)
696                 tp->filter->interface->destroy(tp->filter);
697         free(tp->touches);
698         free(tp);
699 }
700
701 static struct evdev_dispatch_interface tp_interface = {
702         tp_process,
703         tp_destroy
704 };
705
706 static int
707 tp_init_slots(struct tp_dispatch *tp,
708               struct evdev_device *device)
709 {
710         const struct input_absinfo *absinfo;
711
712         absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_SLOT);
713         if (absinfo) {
714                 tp->ntouches = absinfo->maximum + 1;
715                 tp->slot = absinfo->value;
716                 tp->has_mt = true;
717         } else {
718                 tp->ntouches = 5; /* FIXME: based on DOUBLETAP, etc. */
719                 tp->slot = 0;
720                 tp->has_mt = false;
721         }
722         tp->touches = calloc(tp->ntouches,
723                              sizeof(struct tp_touch));
724         if (!tp->touches)
725                 return -1;
726
727         return 0;
728 }
729
730 static int
731 tp_init_accel(struct tp_dispatch *touchpad, double diagonal)
732 {
733         struct motion_filter *accel;
734
735         touchpad->accel.constant_factor =
736                 DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal;
737         touchpad->accel.min_factor = DEFAULT_MIN_ACCEL_FACTOR;
738         touchpad->accel.max_factor = DEFAULT_MAX_ACCEL_FACTOR;
739
740         accel = create_pointer_accelator_filter(tp_accel_profile);
741         if (accel == NULL)
742                 return -1;
743
744         touchpad->filter = accel;
745
746         return 0;
747 }
748
749 static int
750 tp_init_scroll(struct tp_dispatch *tp)
751 {
752         tp->scroll.direction = 0;
753         tp->scroll.state = SCROLL_STATE_NONE;
754
755         return 0;
756 }
757
758 static int
759 tp_init(struct tp_dispatch *tp,
760         struct evdev_device *device)
761 {
762         int width, height;
763         double diagonal;
764
765         tp->base.interface = &tp_interface;
766         tp->device = device;
767         tp->tap.timer_fd = -1;
768
769         if (tp_init_slots(tp, device) != 0)
770                 return -1;
771
772         width = abs(device->abs.max_x - device->abs.min_x);
773         height = abs(device->abs.max_y - device->abs.min_y);
774         diagonal = sqrt(width*width + height*height);
775
776         tp->hysteresis.margin_x =
777                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
778         tp->hysteresis.margin_y =
779                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
780
781         if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) ||
782             libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT))
783                 tp->buttons.has_buttons = true;
784
785         if (tp_init_scroll(tp) != 0)
786                 return -1;
787
788         if (tp_init_accel(tp, diagonal) != 0)
789                 return -1;
790
791         if (tp_init_tap(tp) != 0)
792                 return -1;
793
794         return 0;
795 }
796
797 struct evdev_dispatch *
798 evdev_mt_touchpad_create(struct evdev_device *device)
799 {
800         struct tp_dispatch *tp;
801
802         tp = zalloc(sizeof *tp);
803         if (!tp)
804                 return NULL;
805
806         if (tp_init(tp, device) != 0) {
807                 tp_destroy(&tp->base);
808                 return NULL;
809         }
810
811         return  &tp->base;
812 }