9848a32a1ef4c61c3226c7fd8ee78d8cfb54fbb6
[platform/upstream/libinput.git] / src / evdev-mt-touchpad-buttons.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 <errno.h>
24 #include <limits.h>
25 #include <math.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include "linux/input.h"
29
30 #include "evdev-mt-touchpad.h"
31
32 #define DEFAULT_BUTTON_MOTION_THRESHOLD 0.02 /* 2% of size */
33 #define DEFAULT_BUTTON_ENTER_TIMEOUT 100 /* ms */
34 #define DEFAULT_BUTTON_LEAVE_TIMEOUT 300 /* ms */
35
36 /*****************************************
37  * BEFORE YOU EDIT THIS FILE, look at the state diagram in
38  * doc/touchpad-softbutton-state-machine.svg, or online at
39  * https://drive.google.com/file/d/0B1NwWmji69nocUs1cVJTbkdwMFk/edit?usp=sharing
40  * (it's a http://draw.io diagram)
41  *
42  * Any changes in this file must be represented in the diagram.
43  *
44  * The state machine only affects the soft button area code.
45  */
46
47 #define CASE_RETURN_STRING(a) case a: return #a;
48
49 static inline const char*
50 button_state_to_str(enum button_state state) {
51         switch(state) {
52         CASE_RETURN_STRING(BUTTON_STATE_NONE);
53         CASE_RETURN_STRING(BUTTON_STATE_AREA);
54         CASE_RETURN_STRING(BUTTON_STATE_BOTTOM);
55         CASE_RETURN_STRING(BUTTON_STATE_BOTTOM_NEW);
56         CASE_RETURN_STRING(BUTTON_STATE_BOTTOM_TO_AREA);
57         CASE_RETURN_STRING(BUTTON_STATE_TOP);
58         CASE_RETURN_STRING(BUTTON_STATE_TOP_NEW);
59         CASE_RETURN_STRING(BUTTON_STATE_TOP_TO_IGNORE);
60         CASE_RETURN_STRING(BUTTON_STATE_IGNORE);
61         }
62         return NULL;
63 }
64
65 static inline const char*
66 button_event_to_str(enum button_event event) {
67         switch(event) {
68         CASE_RETURN_STRING(BUTTON_EVENT_IN_BOTTOM_R);
69         CASE_RETURN_STRING(BUTTON_EVENT_IN_BOTTOM_L);
70         CASE_RETURN_STRING(BUTTON_EVENT_IN_TOP_R);
71         CASE_RETURN_STRING(BUTTON_EVENT_IN_TOP_M);
72         CASE_RETURN_STRING(BUTTON_EVENT_IN_TOP_L);
73         CASE_RETURN_STRING(BUTTON_EVENT_IN_AREA);
74         CASE_RETURN_STRING(BUTTON_EVENT_UP);
75         CASE_RETURN_STRING(BUTTON_EVENT_PRESS);
76         CASE_RETURN_STRING(BUTTON_EVENT_RELEASE);
77         CASE_RETURN_STRING(BUTTON_EVENT_TIMEOUT);
78         }
79         return NULL;
80 }
81
82 static inline bool
83 is_inside_bottom_button_area(struct tp_dispatch *tp, struct tp_touch *t)
84 {
85         return t->y >= tp->buttons.bottom_area.top_edge;
86 }
87
88 static inline bool
89 is_inside_bottom_right_area(struct tp_dispatch *tp, struct tp_touch *t)
90 {
91         return is_inside_bottom_button_area(tp, t) &&
92                t->x > tp->buttons.bottom_area.rightbutton_left_edge;
93 }
94
95 static inline bool
96 is_inside_bottom_left_area(struct tp_dispatch *tp, struct tp_touch *t)
97 {
98         return is_inside_bottom_button_area(tp, t) &&
99                !is_inside_bottom_right_area(tp, t);
100 }
101
102 static inline bool
103 is_inside_top_button_area(struct tp_dispatch *tp, struct tp_touch *t)
104 {
105         return t->y <= tp->buttons.top_area.bottom_edge;
106 }
107
108 static inline bool
109 is_inside_top_right_area(struct tp_dispatch *tp, struct tp_touch *t)
110 {
111         return is_inside_top_button_area(tp, t) &&
112                t->x > tp->buttons.top_area.rightbutton_left_edge;
113 }
114
115 static inline bool
116 is_inside_top_left_area(struct tp_dispatch *tp, struct tp_touch *t)
117 {
118         return is_inside_top_button_area(tp, t) &&
119                t->x < tp->buttons.top_area.leftbutton_right_edge;
120 }
121
122 static inline bool
123 is_inside_top_middle_area(struct tp_dispatch *tp, struct tp_touch *t)
124 {
125         return is_inside_top_button_area(tp, t) &&
126                t->x >= tp->buttons.top_area.leftbutton_right_edge &&
127                t->x <= tp->buttons.top_area.rightbutton_left_edge;
128 }
129
130 static void
131 tp_button_set_enter_timer(struct tp_dispatch *tp, struct tp_touch *t)
132 {
133         libinput_timer_set(&t->button.timer,
134                            t->millis + DEFAULT_BUTTON_ENTER_TIMEOUT);
135 }
136
137 static void
138 tp_button_set_leave_timer(struct tp_dispatch *tp, struct tp_touch *t)
139 {
140         libinput_timer_set(&t->button.timer,
141                            t->millis + DEFAULT_BUTTON_LEAVE_TIMEOUT);
142 }
143
144 /*
145  * tp_button_set_state, change state and implement on-entry behavior
146  * as described in the state machine diagram.
147  */
148 static void
149 tp_button_set_state(struct tp_dispatch *tp, struct tp_touch *t,
150                     enum button_state new_state, enum button_event event)
151 {
152         libinput_timer_cancel(&t->button.timer);
153
154         t->button.state = new_state;
155         switch (t->button.state) {
156         case BUTTON_STATE_NONE:
157                 t->button.curr = 0;
158                 break;
159         case BUTTON_STATE_AREA:
160                 t->button.curr = BUTTON_EVENT_IN_AREA;
161                 tp_set_pointer(tp, t);
162                 break;
163         case BUTTON_STATE_BOTTOM:
164                 break;
165         case BUTTON_STATE_BOTTOM_NEW:
166                 t->button.curr = event;
167                 tp_button_set_enter_timer(tp, t);
168                 break;
169         case BUTTON_STATE_BOTTOM_TO_AREA:
170                 tp_button_set_leave_timer(tp, t);
171                 break;
172         case BUTTON_STATE_TOP:
173                 break;
174         case BUTTON_STATE_TOP_NEW:
175                 t->button.curr = event;
176                 tp_button_set_enter_timer(tp, t);
177                 break;
178         case BUTTON_STATE_TOP_TO_IGNORE:
179                 tp_button_set_leave_timer(tp, t);
180                 break;
181         case BUTTON_STATE_IGNORE:
182                 t->button.curr = 0;
183                 break;
184         }
185 }
186
187 static void
188 tp_button_none_handle_event(struct tp_dispatch *tp,
189                             struct tp_touch *t,
190                             enum button_event event)
191 {
192         switch (event) {
193         case BUTTON_EVENT_IN_BOTTOM_R:
194         case BUTTON_EVENT_IN_BOTTOM_L:
195                 tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW, event);
196                 break;
197         case BUTTON_EVENT_IN_TOP_R:
198         case BUTTON_EVENT_IN_TOP_M:
199         case BUTTON_EVENT_IN_TOP_L:
200                 tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW, event);
201                 break;
202         case BUTTON_EVENT_IN_AREA:
203                 tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
204                 break;
205         case BUTTON_EVENT_UP:
206                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
207                 break;
208         case BUTTON_EVENT_PRESS:
209         case BUTTON_EVENT_RELEASE:
210         case BUTTON_EVENT_TIMEOUT:
211                 break;
212         }
213 }
214
215 static void
216 tp_button_area_handle_event(struct tp_dispatch *tp,
217                             struct tp_touch *t,
218                             enum button_event event)
219 {
220         switch (event) {
221         case BUTTON_EVENT_IN_BOTTOM_R:
222         case BUTTON_EVENT_IN_BOTTOM_L:
223         case BUTTON_EVENT_IN_TOP_R:
224         case BUTTON_EVENT_IN_TOP_M:
225         case BUTTON_EVENT_IN_TOP_L:
226         case BUTTON_EVENT_IN_AREA:
227                 break;
228         case BUTTON_EVENT_UP:
229                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
230                 break;
231         case BUTTON_EVENT_PRESS:
232         case BUTTON_EVENT_RELEASE:
233         case BUTTON_EVENT_TIMEOUT:
234                 break;
235         }
236 }
237
238 static void
239 tp_button_bottom_handle_event(struct tp_dispatch *tp,
240                             struct tp_touch *t,
241                             enum button_event event)
242 {
243         switch (event) {
244         case BUTTON_EVENT_IN_BOTTOM_R:
245         case BUTTON_EVENT_IN_BOTTOM_L:
246                 if (event != t->button.curr)
247                         tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW,
248                                             event);
249                 break;
250         case BUTTON_EVENT_IN_TOP_R:
251         case BUTTON_EVENT_IN_TOP_M:
252         case BUTTON_EVENT_IN_TOP_L:
253         case BUTTON_EVENT_IN_AREA:
254                 tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_TO_AREA, event);
255                 break;
256         case BUTTON_EVENT_UP:
257                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
258                 break;
259         case BUTTON_EVENT_PRESS:
260         case BUTTON_EVENT_RELEASE:
261         case BUTTON_EVENT_TIMEOUT:
262                 break;
263         }
264 }
265
266 static void
267 tp_button_bottom_new_handle_event(struct tp_dispatch *tp,
268                                 struct tp_touch *t,
269                                 enum button_event event)
270 {
271         switch(event) {
272         case BUTTON_EVENT_IN_BOTTOM_R:
273         case BUTTON_EVENT_IN_BOTTOM_L:
274                 if (event != t->button.curr)
275                         tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW,
276                                             event);
277                 break;
278         case BUTTON_EVENT_IN_TOP_R:
279         case BUTTON_EVENT_IN_TOP_M:
280         case BUTTON_EVENT_IN_TOP_L:
281         case BUTTON_EVENT_IN_AREA:
282                 tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
283                 break;
284         case BUTTON_EVENT_UP:
285                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
286                 break;
287         case BUTTON_EVENT_PRESS:
288                 tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, event);
289                 break;
290         case BUTTON_EVENT_RELEASE:
291                 break;
292         case BUTTON_EVENT_TIMEOUT:
293                 tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, event);
294                 break;
295         }
296 }
297
298 static void
299 tp_button_bottom_to_area_handle_event(struct tp_dispatch *tp,
300                                       struct tp_touch *t,
301                                       enum button_event event)
302 {
303         switch(event) {
304         case BUTTON_EVENT_IN_BOTTOM_R:
305         case BUTTON_EVENT_IN_BOTTOM_L:
306                 if (event == t->button.curr)
307                         tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM,
308                                             event);
309                 else
310                         tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW,
311                                             event);
312                 break;
313         case BUTTON_EVENT_IN_TOP_R:
314         case BUTTON_EVENT_IN_TOP_M:
315         case BUTTON_EVENT_IN_TOP_L:
316         case BUTTON_EVENT_IN_AREA:
317                 break;
318         case BUTTON_EVENT_UP:
319                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
320                 break;
321         case BUTTON_EVENT_PRESS:
322         case BUTTON_EVENT_RELEASE:
323                 break;
324         case BUTTON_EVENT_TIMEOUT:
325                 tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
326                 break;
327         }
328 }
329
330 static void
331 tp_button_top_handle_event(struct tp_dispatch *tp,
332                             struct tp_touch *t,
333                             enum button_event event)
334 {
335         switch (event) {
336         case BUTTON_EVENT_IN_BOTTOM_R:
337         case BUTTON_EVENT_IN_BOTTOM_L:
338                 tp_button_set_state(tp, t, BUTTON_STATE_TOP_TO_IGNORE, event);
339                 break;
340         case BUTTON_EVENT_IN_TOP_R:
341         case BUTTON_EVENT_IN_TOP_M:
342         case BUTTON_EVENT_IN_TOP_L:
343                 if (event != t->button.curr)
344                         tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW,
345                                             event);
346                 break;
347         case BUTTON_EVENT_IN_AREA:
348                 tp_button_set_state(tp, t, BUTTON_STATE_TOP_TO_IGNORE, event);
349                 break;
350         case BUTTON_EVENT_UP:
351                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
352                 break;
353         case BUTTON_EVENT_PRESS:
354         case BUTTON_EVENT_RELEASE:
355         case BUTTON_EVENT_TIMEOUT:
356                 break;
357         }
358 }
359
360 static void
361 tp_button_top_new_handle_event(struct tp_dispatch *tp,
362                                 struct tp_touch *t,
363                                 enum button_event event)
364 {
365         switch(event) {
366         case BUTTON_EVENT_IN_BOTTOM_R:
367         case BUTTON_EVENT_IN_BOTTOM_L:
368                 tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
369                 break;
370         case BUTTON_EVENT_IN_TOP_R:
371         case BUTTON_EVENT_IN_TOP_M:
372         case BUTTON_EVENT_IN_TOP_L:
373                 if (event != t->button.curr)
374                         tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW,
375                                             event);
376                 break;
377         case BUTTON_EVENT_IN_AREA:
378                 tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
379                 break;
380         case BUTTON_EVENT_UP:
381                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
382                 break;
383         case BUTTON_EVENT_PRESS:
384                 tp_button_set_state(tp, t, BUTTON_STATE_TOP, event);
385                 break;
386         case BUTTON_EVENT_RELEASE:
387                 break;
388         case BUTTON_EVENT_TIMEOUT:
389                 tp_button_set_state(tp, t, BUTTON_STATE_TOP, event);
390                 break;
391         }
392 }
393
394 static void
395 tp_button_top_to_ignore_handle_event(struct tp_dispatch *tp,
396                                       struct tp_touch *t,
397                                       enum button_event event)
398 {
399         switch(event) {
400         case BUTTON_EVENT_IN_TOP_R:
401         case BUTTON_EVENT_IN_TOP_M:
402         case BUTTON_EVENT_IN_TOP_L:
403                 if (event == t->button.curr)
404                         tp_button_set_state(tp, t, BUTTON_STATE_TOP,
405                                             event);
406                 else
407                         tp_button_set_state(tp, t, BUTTON_STATE_TOP_NEW,
408                                             event);
409                 break;
410         case BUTTON_EVENT_IN_BOTTOM_R:
411         case BUTTON_EVENT_IN_BOTTOM_L:
412         case BUTTON_EVENT_IN_AREA:
413                 break;
414         case BUTTON_EVENT_UP:
415                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
416                 break;
417         case BUTTON_EVENT_PRESS:
418         case BUTTON_EVENT_RELEASE:
419                 break;
420         case BUTTON_EVENT_TIMEOUT:
421                 tp_button_set_state(tp, t, BUTTON_STATE_IGNORE, event);
422                 break;
423         }
424 }
425
426 static void
427 tp_button_ignore_handle_event(struct tp_dispatch *tp,
428                             struct tp_touch *t,
429                             enum button_event event)
430 {
431         switch (event) {
432         case BUTTON_EVENT_IN_BOTTOM_R:
433         case BUTTON_EVENT_IN_BOTTOM_L:
434         case BUTTON_EVENT_IN_TOP_R:
435         case BUTTON_EVENT_IN_TOP_M:
436         case BUTTON_EVENT_IN_TOP_L:
437         case BUTTON_EVENT_IN_AREA:
438                 break;
439         case BUTTON_EVENT_UP:
440                 tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
441                 break;
442         case BUTTON_EVENT_PRESS:
443         case BUTTON_EVENT_RELEASE:
444         case BUTTON_EVENT_TIMEOUT:
445                 break;
446         }
447 }
448
449 static void
450 tp_button_handle_event(struct tp_dispatch *tp,
451                        struct tp_touch *t,
452                        enum button_event event,
453                        uint64_t time)
454 {
455         struct libinput *libinput = tp->device->base.seat->libinput;
456         enum button_state current = t->button.state;
457
458         switch(t->button.state) {
459         case BUTTON_STATE_NONE:
460                 tp_button_none_handle_event(tp, t, event);
461                 break;
462         case BUTTON_STATE_AREA:
463                 tp_button_area_handle_event(tp, t, event);
464                 break;
465         case BUTTON_STATE_BOTTOM:
466                 tp_button_bottom_handle_event(tp, t, event);
467                 break;
468         case BUTTON_STATE_BOTTOM_NEW:
469                 tp_button_bottom_new_handle_event(tp, t, event);
470                 break;
471         case BUTTON_STATE_BOTTOM_TO_AREA:
472                 tp_button_bottom_to_area_handle_event(tp, t, event);
473                 break;
474         case BUTTON_STATE_TOP:
475                 tp_button_top_handle_event(tp, t, event);
476                 break;
477         case BUTTON_STATE_TOP_NEW:
478                 tp_button_top_new_handle_event(tp, t, event);
479                 break;
480         case BUTTON_STATE_TOP_TO_IGNORE:
481                 tp_button_top_to_ignore_handle_event(tp, t, event);
482                 break;
483         case BUTTON_STATE_IGNORE:
484                 tp_button_ignore_handle_event(tp, t, event);
485                 break;
486         }
487
488         if (current != t->button.state)
489                 log_debug(libinput,
490                           "button state: from %s, event %s to %s\n",
491                           button_state_to_str(current),
492                           button_event_to_str(event),
493                           button_state_to_str(t->button.state));
494 }
495
496 int
497 tp_button_handle_state(struct tp_dispatch *tp, uint64_t time)
498 {
499         struct tp_touch *t;
500
501         tp_for_each_touch(tp, t) {
502                 if (t->state == TOUCH_NONE)
503                         continue;
504
505                 if (t->state == TOUCH_END) {
506                         tp_button_handle_event(tp, t, BUTTON_EVENT_UP, time);
507                 } else if (t->dirty) {
508                         if (is_inside_bottom_right_area(tp, t))
509                                 tp_button_handle_event(tp, t, BUTTON_EVENT_IN_BOTTOM_R, time);
510                         else if (is_inside_bottom_left_area(tp, t))
511                                 tp_button_handle_event(tp, t, BUTTON_EVENT_IN_BOTTOM_L, time);
512                         else if (is_inside_top_right_area(tp, t))
513                                 tp_button_handle_event(tp, t, BUTTON_EVENT_IN_TOP_R, time);
514                         else if (is_inside_top_middle_area(tp, t))
515                                 tp_button_handle_event(tp, t, BUTTON_EVENT_IN_TOP_M, time);
516                         else if (is_inside_top_left_area(tp, t))
517                                 tp_button_handle_event(tp, t, BUTTON_EVENT_IN_TOP_L, time);
518                         else
519                                 tp_button_handle_event(tp, t, BUTTON_EVENT_IN_AREA, time);
520                 }
521                 if (tp->queued & TOUCHPAD_EVENT_BUTTON_RELEASE)
522                         tp_button_handle_event(tp, t, BUTTON_EVENT_RELEASE, time);
523                 if (tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
524                         tp_button_handle_event(tp, t, BUTTON_EVENT_PRESS, time);
525         }
526
527         return 0;
528 }
529
530 static void
531 tp_button_handle_timeout(uint64_t now, void *data)
532 {
533         struct tp_touch *t = data;
534
535         tp_button_handle_event(t->tp, t, BUTTON_EVENT_TIMEOUT, now);
536 }
537
538 int
539 tp_process_button(struct tp_dispatch *tp,
540                   const struct input_event *e,
541                   uint64_t time)
542 {
543         struct libinput *libinput = tp->device->base.seat->libinput;
544         uint32_t mask = 1 << (e->code - BTN_LEFT);
545
546         /* Ignore other buttons on clickpads */
547         if (tp->buttons.is_clickpad && e->code != BTN_LEFT) {
548                 log_bug_kernel(libinput,
549                                "received %s button event on a clickpad\n",
550                                libevdev_event_code_get_name(EV_KEY, e->code));
551                 return 0;
552         }
553
554         if (e->value) {
555                 tp->buttons.state |= mask;
556                 tp->queued |= TOUCHPAD_EVENT_BUTTON_PRESS;
557         } else {
558                 tp->buttons.state &= ~mask;
559                 tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE;
560         }
561
562         return 0;
563 }
564
565 int
566 tp_init_buttons(struct tp_dispatch *tp,
567                 struct evdev_device *device)
568 {
569         struct libinput *libinput = tp->device->base.seat->libinput;
570         struct tp_touch *t;
571         int width, height;
572         double diagonal;
573         const struct input_absinfo *absinfo_x, *absinfo_y;
574
575         tp->buttons.is_clickpad = libevdev_has_property(device->evdev,
576                                                         INPUT_PROP_BUTTONPAD);
577         tp->buttons.has_topbuttons = libevdev_has_property(device->evdev,
578                                                         INPUT_PROP_TOPBUTTONPAD);
579
580         if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) ||
581             libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) {
582                 if (tp->buttons.is_clickpad)
583                         log_bug_kernel(libinput,
584                                        "%s: clickpad advertising right button\n",
585                                        device->sysname);
586         } else {
587                 if (!tp->buttons.is_clickpad)
588                         log_bug_kernel(libinput,
589                                        "%s: non clickpad without right button?\n",
590                                        device->sysname);
591         }
592
593         absinfo_x = device->abs.absinfo_x;
594         absinfo_y = device->abs.absinfo_y;
595
596         width = abs(absinfo_x->maximum - absinfo_x->minimum);
597         height = abs(absinfo_y->maximum - absinfo_y->minimum);
598         diagonal = sqrt(width*width + height*height);
599
600         tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD;
601
602         if (libevdev_get_id_vendor(device->evdev) == 0x5ac) /* Apple */
603                 tp->buttons.use_clickfinger = true;
604
605         if (tp->buttons.is_clickpad && !tp->buttons.use_clickfinger) {
606                 int xoffset = absinfo_x->minimum,
607                     yoffset = absinfo_y->minimum;
608                 int yres = absinfo_y->resolution;
609
610                 /* button height: 10mm or 15% of the touchpad height,
611                    whichever is smaller */
612                 if (yres > 1 && (height * 0.15/yres) > 10) {
613                         tp->buttons.bottom_area.top_edge =
614                                 absinfo_y->maximum - 10 * yres;
615                 } else {
616                         tp->buttons.bottom_area.top_edge = height * .85 + yoffset;
617                 }
618
619                 tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset;
620
621                 if (tp->buttons.has_topbuttons) {
622                         /* T440s has the top button line 5mm from the top,
623                            make the buttons 6mm high */
624                         if (yres > 1) {
625                                 tp->buttons.top_area.bottom_edge =
626                                         yoffset + 6 * yres;
627                         } else {
628                                 tp->buttons.top_area.bottom_edge = height * .08 + yoffset;
629                         }
630                         tp->buttons.top_area.rightbutton_left_edge = width * .58 + xoffset;
631                         tp->buttons.top_area.leftbutton_right_edge = width * .42 + xoffset;
632                 } else {
633                         tp->buttons.top_area.bottom_edge = INT_MIN;
634                 }
635         } else {
636                 tp->buttons.bottom_area.top_edge = INT_MAX;
637                 tp->buttons.top_area.bottom_edge = INT_MIN;
638         }
639
640         tp_for_each_touch(tp, t) {
641                 t->button.state = BUTTON_STATE_NONE;
642                 libinput_timer_init(&t->button.timer,
643                                     tp->device->base.seat->libinput,
644                                     tp_button_handle_timeout, t);
645         }
646
647         return 0;
648 }
649
650 void
651 tp_destroy_buttons(struct tp_dispatch *tp)
652 {
653         struct tp_touch *t;
654
655         tp_for_each_touch(tp, t)
656                 libinput_timer_cancel(&t->button.timer);
657 }
658
659 static int
660 tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint64_t time)
661 {
662         uint32_t current, old, button;
663         enum libinput_button_state state;
664
665         current = tp->buttons.state;
666         old = tp->buttons.old_state;
667
668         if (current == old)
669                 return 0;
670
671         if (current) {
672                 switch (tp->nfingers_down) {
673                 case 1: button = BTN_LEFT; break;
674                 case 2: button = BTN_RIGHT; break;
675                 case 3: button = BTN_MIDDLE; break;
676                 default:
677                         return 0;
678                 }
679                 tp->buttons.active = button;
680                 state = LIBINPUT_BUTTON_STATE_PRESSED;
681         } else {
682                 button = tp->buttons.active;
683                 tp->buttons.active = 0;
684                 state = LIBINPUT_BUTTON_STATE_RELEASED;
685         }
686
687         if (button)
688                 pointer_notify_button(&tp->device->base,
689                                       time,
690                                       button,
691                                       state);
692         return 1;
693 }
694
695 static int
696 tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time)
697 {
698         uint32_t current, old, button;
699
700         current = tp->buttons.state;
701         old = tp->buttons.old_state;
702         button = BTN_LEFT;
703
704         while (current || old) {
705                 enum libinput_button_state state;
706
707                 if ((current & 0x1) ^ (old & 0x1)) {
708                         if (!!(current & 0x1))
709                                 state = LIBINPUT_BUTTON_STATE_PRESSED;
710                         else
711                                 state = LIBINPUT_BUTTON_STATE_RELEASED;
712
713                         pointer_notify_button(&tp->device->base,
714                                               time,
715                                               button,
716                                               state);
717                 }
718
719                 button++;
720                 current >>= 1;
721                 old >>= 1;
722         }
723
724         return 0;
725 }
726
727 static int
728 tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time)
729 {
730         uint32_t current, old, button;
731         enum libinput_button_state state;
732         enum { AREA = 0x01, LEFT = 0x02, MIDDLE = 0x04, RIGHT = 0x08 };
733
734         current = tp->buttons.state;
735         old = tp->buttons.old_state;
736         button = 0;
737
738         if (!tp->buttons.click_pending && current == old)
739                 return 0;
740
741         if (current) {
742                 struct tp_touch *t;
743
744                 tp_for_each_touch(tp, t) {
745                         switch (t->button.curr) {
746                         case BUTTON_EVENT_IN_AREA:
747                                 button |= AREA;
748                                 break;
749                         case BUTTON_EVENT_IN_BOTTOM_L:
750                         case BUTTON_EVENT_IN_TOP_L:
751                                 button |= LEFT;
752                                 break;
753                         case BUTTON_EVENT_IN_TOP_M:
754                                 button |= MIDDLE;
755                                 break;
756                         case BUTTON_EVENT_IN_BOTTOM_R:
757                         case BUTTON_EVENT_IN_TOP_R:
758                                 button |= RIGHT;
759                                 break;
760                         default:
761                                 break;
762                         }
763                 }
764
765                 if (button == 0) {
766                         /* No touches, wait for a touch before processing */
767                         tp->buttons.click_pending = true;
768                         return 0;
769                 }
770
771                 if ((button & MIDDLE) || ((button & LEFT) && (button & RIGHT)))
772                         button = BTN_MIDDLE;
773                 else if (button & RIGHT)
774                         button = BTN_RIGHT;
775                 else
776                         button = BTN_LEFT;
777
778                 tp->buttons.active = button;
779                 state = LIBINPUT_BUTTON_STATE_PRESSED;
780         } else {
781                 button = tp->buttons.active;
782                 tp->buttons.active = 0;
783                 state = LIBINPUT_BUTTON_STATE_RELEASED;
784         }
785
786         tp->buttons.click_pending = false;
787
788         if (button)
789                 pointer_notify_button(&tp->device->base,
790                                       time,
791                                       button,
792                                       state);
793         return 1;
794 }
795
796 int
797 tp_post_button_events(struct tp_dispatch *tp, uint64_t time)
798 {
799         if (tp->buttons.is_clickpad) {
800                 if (tp->buttons.use_clickfinger)
801                         return tp_post_clickfinger_buttons(tp, time);
802                 else
803                         return tp_post_softbutton_buttons(tp, time);
804         }
805
806         return tp_post_physical_buttons(tp, time);
807 }
808
809 int
810 tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
811 {
812         return t->button.state == BUTTON_STATE_AREA;
813 }