summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2014-11-24 12:16:06 +0100
committerPeter Hutterer <peter.hutterer@who-t.net>2014-11-25 17:02:30 +1000
commit6a4ceed2b91f5bbd28991d61615b17dc4a707fe3 (patch)
tree3b1159d86816adaa8094ead3c5d760a492903555
parent8b6572bfae15c19fdb9ea0121ed6f397bb3ffead (diff)
downloadlibinput-6a4ceed2b91f5bbd28991d61615b17dc4a707fe3.tar.gz
touchpad: Add edge-scrolling support
Add edge-scrolling support for non multi-touch touchpads as well as for users who prefer edge-scrolling (as long as they don't have a clickpad). Note the percentage to use of the width / height as scroll-edge differs from one manufacturer to the next, the various per model percentages were taken from xf86-input-synaptics. BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=85635 Signed-off-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--doc/touchpad-edge-scrolling-state-machine.svg262
-rw-r--r--src/Makefile.am1
-rw-r--r--src/evdev-mt-touchpad-edge-scroll.c374
-rw-r--r--src/evdev-mt-touchpad.c95
-rw-r--r--src/evdev-mt-touchpad.h46
5 files changed, 767 insertions, 11 deletions
diff --git a/doc/touchpad-edge-scrolling-state-machine.svg b/doc/touchpad-edge-scrolling-state-machine.svg
new file mode 100644
index 00000000..7a82d88c
--- /dev/null
+++ b/doc/touchpad-edge-scrolling-state-machine.svg
@@ -0,0 +1,262 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1490px" height="1399px" version="1.1">
+ <defs/>
+ <g transform="translate(0.5,0.5)">
+ <ellipse cx="261" cy="143" rx="63" ry="45.5" fill="#ccccff" stroke="#000000" stroke-width="2" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="261" y="126">NONE</text>
+ <text x="261" y="140">on-entry:</text>
+ <text x="261" y="154">edge = none</text>
+ <text x="261" y="168">threshold = def</text>
+ </g>
+ <rect x="30" y="386" width="150" height="101" rx="6" ry="6" fill="#ccffcc" stroke="#000000" stroke-width="2" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="105" y="419">EDGE_NEW</text>
+ <text x="105" y="433">on-entry:</text>
+ <text x="105" y="447">edge = get_edge()</text>
+ <text x="105" y="461">set_timer()</text>
+ </g>
+ <rect x="348" y="386" width="130" height="100" rx="6" ry="6" fill="#ccffcc" stroke="#000000" stroke-width="2" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="413" y="419">AREA</text>
+ <text x="413" y="433">on-entry:</text>
+ <text x="413" y="447">edge = none</text>
+ <text x="413" y="461">set_pointer()</text>
+ </g>
+ <path d="M 237 7 C 239 4 243 2 246 2 L 275 2 C 278 2 282 4 284 7 L 301 30 C 301 31 301 33 301 34 L 284 57 C 282 60 278 62 275 62 L 246 62 C 243 62 239 60 237 57 L 220 34 C 220 33 220 31 220 30 L 237 7 Z" fill="#ffd966" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="261" y="36">release</text>
+ </g>
+ <path d="M 237 222 C 239 219 243 217 246 217 L 276 217 C 279 217 283 219 285 222 L 303 245 C 303 246 303 248 303 249 L 285 272 C 283 275 279 277 276 277 L 246 277 C 243 277 239 275 237 272 L 219 249 C 219 248 219 246 219 245 L 237 222 Z" fill="#ffd966" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="261" y="251">touch</text>
+ </g>
+ <path d="M 261 188 L 261 211" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 261 216 L 258 209 L 261 211 L 265 209 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 218 535 C 223 531 229 528 235 528 L 285 528 C 291 528 297 531 302 535 L 331 570 C 332 571 332 574 331 575 L 302 610 C 297 614 291 617 285 617 L 235 617 C 229 617 223 614 218 610 L 189 575 C 188 574 188 571 189 570 L 218 535 Z" fill="#ffd966" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="260" y="563">touch,</text>
+ <text x="260" y="577">edge &amp;= get_edge()</text>
+ </g>
+ <path d="M 220 526 L 158 487" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 224 529 L 217 528 L 220 526 L 220 522 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 105 617 L 105 650" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 105 656 L 101 649 L 105 650 L 108 649 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 478 436 L 498 436 Q 508 436 508 426 L 508 42 Q 508 32 498 32 L 307 32" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 302 32 L 309 29 L 307 32 L 309 36 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 261 62 L 261 71 Q 261 80 261 85 L 261 91" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 261 96 L 257 89 L 261 91 L 264 89 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <ellipse cx="1133" cy="67" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
+ <path d="M 1133 82 L 1133 110 Q 1133 120 1133 130 L 1133 155" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1129 147 L 1133 156 L 1138 147" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <rect x="1083" y="12" width="100" height="40" fill="none" stroke="none" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="1133" y="36">tp_edge_scroll_post_events()</text>
+ </g>
+ <path d="M 1133 212 L 1193 242 L 1133 272 L 1073 242 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="1133" y="246">dirty?</text>
+ </g>
+ <path d="M 1193 242 L 1278 242 Q 1288 242 1298 242 L 1456 242" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1448 247 L 1457 242 L 1448 238" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="1225" y="223" width="18" height="18" stroke-width="0"/>
+ <text x="1226" y="236">no</text>
+ </g>
+ <path d="M 1133 272 L 1133 285 Q 1133 295 1133 305 L 1133 316" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1129 308 L 1133 317 L 1138 308" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="1150" y="292" width="24" height="18" stroke-width="0"/>
+ <text x="1150" y="302">yes</text>
+ </g>
+ <ellipse cx="1473" cy="242" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
+ <ellipse cx="1473" cy="242" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
+ <rect x="1033" y="97" width="200" height="70" rx="28" ry="28" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="1133" y="115">current = buttons.state &amp; 0x01</text>
+ <text x="1133" y="129">old = buttons.old_state &amp; 0x01</text>
+ <text x="1133" y="143">button = 0</text>
+ <text x="1133" y="157">is_top = 0</text>
+ </g>
+ <path d="M 1133 167 L 1133 180 Q 1133 190 1133 200 L 1133 210" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1129 202 L 1133 211 L 1138 202" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <rect x="1237" y="436" width="188" height="50" rx="20" ry="20" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="1331" y="458">notify_axis(last_axis, 0.0)</text>
+ <text x="1331" y="472">last_axis = -1</text>
+ </g>
+ <path d="M 1134 516 L 1194 552 L 1134 587 L 1073 552 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="1134" y="556">edge == right</text>
+ </g>
+ <path d="M 1194 552 L 1268 552 Q 1278 552 1278 553 L 1278 554 Q 1278 554 1268 554 L 1250 554" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1258 550 L 1249 554 L 1258 559" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="1202" y="559" width="24" height="18" stroke-width="0"/>
+ <text x="1203" y="569">yes</text>
+ </g>
+ <rect x="1248" y="534" width="160" height="40" rx="16" ry="16" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="1328" y="551">axis = scroll_vertical</text>
+ <text x="1328" y="565">delta = dy</text>
+ </g>
+ <path d="M 1408 554 L 1468 554 Q 1478 554 1478 564 L 1478 952 Q 1478 962 1468 962 L 1233 962" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1241 958 L 1232 962 L 1241 967" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1133 318 L 1196 352 L 1133 387 L 1071 352 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="1133" y="356">edge == none</text>
+ </g>
+ <path d="M 1134 386 L 1134 441 Q 1134 451 1134 461 L 1134 514" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1129 506 L 1134 515 L 1138 506" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="1135" y="449" width="18" height="18" stroke-width="0"/>
+ <text x="1136" y="458">no</text>
+ </g>
+ <path d="M 1133 657 L 1194 692 L 1133 727 L 1072 692 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="1133" y="696">edge == bottom</text>
+ </g>
+ <path d="M 1194 692 L 1208 692 Q 1218 692 1228 692 L 1249 692" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1241 697 L 1250 692 L 1241 688" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="1213" y="700" width="24" height="18" stroke-width="0"/>
+ <text x="1214" y="709">yes</text>
+ </g>
+ <path d="M 1134 587 L 1133 587 Q 1133 587 1133 597 L 1133 647 Q 1133 657 1133 656 L 1133 655" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1129 647 L 1133 656 L 1138 647" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="1135" y="607" width="18" height="18" stroke-width="0"/>
+ <text x="1135" y="621">no</text>
+ </g>
+ <rect x="1251" y="672" width="160" height="40" rx="16" ry="16" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="1331" y="689">axis = scroll_horizontal</text>
+ <text x="1331" y="703">delta = dx</text>
+ </g>
+ <path d="M 1133 727 L 1133 727 Q 1134 727 1134 737 L 1134 807 Q 1134 817 1134 816 L 1134 815" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1129 807 L 1134 816 L 1138 807" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="1135" y="756" width="18" height="18" stroke-width="0"/>
+ <text x="1136" y="770">no</text>
+ </g>
+ <rect x="1036" y="917" width="195" height="90" rx="36" ry="36" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="1134" y="966">get_delta()</text>
+ </g>
+ <path d="M 1134 1007 L 1134 1037 Q 1134 1047 1134 1057 L 1134 1070" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1129 1062 L 1134 1071 L 1138 1062" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1411 692 L 1468 692 Q 1478 692 1478 702 L 1478 952 Q 1478 962 1468 962 L 1233 962" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1241 958 L 1232 962 L 1241 967" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <rect x="1031" y="1197" width="205" height="90" rx="36" ry="36" fill="#ffffc0" stroke="#ff0000" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="1134" y="1232">notify_axis(axis, delta)</text>
+ <text x="1134" y="1246">last_axis = axis</text>
+ <text x="1134" y="1260">emit(scroll_event_posted)</text>
+ </g>
+ <path d="M 1134 1072 L 1200 1107 L 1134 1142 L 1067 1107 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="1134" y="1111">delta &lt; threshold</text>
+ </g>
+ <path d="M 1200 1107 L 1318 1107 Q 1328 1107 1338 1107 L 1456 1107" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1448 1112 L 1457 1107 L 1448 1103" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="1259" y="1118" width="24" height="18" stroke-width="0"/>
+ <text x="1260" y="1131">yes</text>
+ </g>
+ <path d="M 1134 1142 L 1134 1160 Q 1134 1170 1134 1180 L 1134 1195" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1129 1187 L 1134 1196 L 1138 1187" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="1135" y="1150" width="18" height="18" stroke-width="0"/>
+ <text x="1136" y="1159">no</text>
+ </g>
+ <ellipse cx="1473" cy="1107" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
+ <ellipse cx="1473" cy="1107" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
+ <ellipse cx="1473" cy="352" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
+ <ellipse cx="1473" cy="352" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
+ <path d="M 1331 318 L 1394 352 L 1331 387 L 1269 352 Z" fill="#ffffc0" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="1331" y="356">last_axis != -1</text>
+ </g>
+ <rect x="30" y="657" width="150" height="101" rx="6" ry="6" fill="#ccffcc" stroke="#000000" stroke-width="2" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="105" y="697">EDGE</text>
+ <text x="105" y="711">on-entry:</text>
+ <text x="105" y="725">threshold = 0.01</text>
+ </g>
+ <path d="M 30 707 L 18 707 Q 8 707 8 697 L 8 42 Q 8 32 18 32 L 214 32" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 219 32 L 212 36 L 214 32 L 212 29 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 30 436 L 18 436 Q 8 436 8 426 L 8 42 Q 8 32 18 32 L 214 32" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 219 32 L 212 36 L 214 32 L 212 29 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 64 535 C 68 531 74 528 80 528 L 130 528 C 136 528 142 531 146 535 L 175 570 C 176 571 176 574 175 575 L 146 610 C 142 614 136 617 130 617 L 80 617 C 74 617 68 614 64 610 L 35 575 C 34 574 34 571 35 570 L 64 535 Z" fill="#ffd966" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="105" y="563">timeout ||</text>
+ <text x="105" y="577">scroll_event_posted</text>
+ </g>
+ <path d="M 105 487 L 105 522" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 105 527 L 102 520 L 105 522 L 109 520 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 260 528 L 261 472" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 261 467 L 264 474 L 261 472 L 257 474 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1196 352 L 1222 352 Q 1232 352 1242 352 L 1266 352" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1258 357 L 1267 352 L 1258 348" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="1224" y="360" width="24" height="18" stroke-width="0"/>
+ <text x="1224" y="369">yes</text>
+ </g>
+ <path d="M 1331 387 L 1331 401 Q 1331 411 1331 421 L 1331 434" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1327 426 L 1331 435 L 1336 426" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="1333" y="394" width="24" height="18" stroke-width="0"/>
+ <text x="1333" y="403">yes</text>
+ </g>
+ <path d="M 1394 352 L 1408 352 Q 1418 352 1428 352 L 1456 352" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1448 357 L 1457 352 L 1448 348" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="1417" y="360" width="18" height="18" stroke-width="0"/>
+ <text x="1418" y="369">no</text>
+ </g>
+ <ellipse cx="1473" cy="461" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
+ <ellipse cx="1473" cy="461" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
+ <path d="M 1425 461 L 1438 461 Q 1448 461 1452 461 L 1456 461" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1448 466 L 1457 461 L 1448 457" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <ellipse cx="1134" cy="832" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
+ <ellipse cx="1134" cy="832" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
+ <ellipse cx="1134" cy="1382" rx="11" ry="11" fill="#000000" stroke="#ff0000" pointer-events="none"/>
+ <ellipse cx="1134" cy="1382" rx="15" ry="15" fill="transparent" stroke="#ff0000" pointer-events="none"/>
+ <path d="M 1134 1287 L 1134 1365" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1130 1359 L 1134 1366 L 1137 1359" fill="none" stroke="#ff0000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 261 277 L 261 299" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 261 304 L 258 297 L 261 299 L 265 297 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 208 337 L 115 337 Q 105 337 105 347 L 105 376 Q 105 386 105 382 L 105 378" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 105 385 L 100 376 L 105 378 L 109 376 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="174" y="345" width="24" height="18" stroke-width="0"/>
+ <text x="175" y="354">yes</text>
+ </g>
+ <path d="M 314 337 L 403 337 Q 413 337 413 347 L 413 376 Q 413 386 413 382 L 413 378" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 413 385 L 408 376 L 413 378 L 417 376 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="350" y="345" width="18" height="18" stroke-width="0"/>
+ <text x="350" y="354">no</text>
+ </g>
+ <path d="M 261 305 L 314 337 L 261 369 L 208 337 Z" fill="#ffd966" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="261" y="341">get_edge()</text>
+ </g>
+ <path d="M 261 406 L 309 436 L 261 466 L 213 436 Z" fill="#ffd966" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="261" y="440">edge</text>
+ </g>
+ <path d="M 309 436 L 319 436 Q 328 436 334 436 L 340 436" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 347 436 L 338 441 L 340 436 L 338 432 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="311" y="444" width="18" height="18" stroke-width="0"/>
+ <text x="311" y="453">no</text>
+ </g>
+ <path d="M 213 436 L 211 436 Q 208 436 198 436 L 188 436" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 181 436 L 190 432 L 188 436 L 190 441 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" font-size="11px">
+ <rect fill="#ffffff" stroke="none" x="189" y="444" width="24" height="18" stroke-width="0"/>
+ <text x="190" y="453">yes</text>
+ </g>
+ </g>
+</svg>
diff --git a/src/Makefile.am b/src/Makefile.am
index 5cc52a66..027e08ca 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,6 +15,7 @@ libinput_la_SOURCES = \
evdev-mt-touchpad.h \
evdev-mt-touchpad-tap.c \
evdev-mt-touchpad-buttons.c \
+ evdev-mt-touchpad-edge-scroll.c \
filter.c \
filter.h \
filter-private.h \
diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c
new file mode 100644
index 00000000..1dca0eab
--- /dev/null
+++ b/src/evdev-mt-touchpad-edge-scroll.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright © 2014 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 <errno.h>
+#include <limits.h>
+#include <math.h>
+#include <string.h>
+#include <unistd.h>
+#include "linux/input.h"
+
+#include "evdev-mt-touchpad.h"
+
+#define DEFAULT_SCROLL_LOCK_TIMEOUT 300 /* ms */
+/* Use a reasonably large threshold until locked into scrolling mode, to
+ avoid accidentally locking in scrolling mode when trying to use the entire
+ touchpad to move the pointer. The user can wait for the timeout to trigger
+ to do a small scroll. */
+/* In mm for touchpads with valid resolution, see tp_init_accel() */
+#define DEFAULT_SCROLL_THRESHOLD 10.0
+
+enum scroll_event {
+ SCROLL_EVENT_TOUCH,
+ SCROLL_EVENT_MOTION,
+ SCROLL_EVENT_RELEASE,
+ SCROLL_EVENT_TIMEOUT,
+ SCROLL_EVENT_POSTED,
+};
+
+static uint32_t
+tp_touch_get_edge(struct tp_dispatch *tp, struct tp_touch *touch)
+{
+ uint32_t edge = EDGE_NONE;
+
+ if (tp->scroll.method != LIBINPUT_CONFIG_SCROLL_EDGE)
+ return EDGE_NONE;
+
+ if (touch->x > tp->scroll.right_edge)
+ edge |= EDGE_RIGHT;
+
+ if (touch->y > tp->scroll.bottom_edge)
+ edge |= EDGE_BOTTOM;
+
+ return edge;
+}
+
+static void
+tp_edge_scroll_set_state(struct tp_dispatch *tp,
+ struct tp_touch *t,
+ enum tp_edge_scroll_touch_state state)
+{
+ libinput_timer_cancel(&t->scroll.timer);
+
+ t->scroll.state = state;
+
+ switch (state) {
+ case EDGE_SCROLL_TOUCH_STATE_NONE:
+ t->scroll.edge = EDGE_NONE;
+ t->scroll.threshold = DEFAULT_SCROLL_THRESHOLD;
+ break;
+ case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW:
+ t->scroll.edge = tp_touch_get_edge(tp, t);
+ libinput_timer_set(&t->scroll.timer,
+ t->millis + DEFAULT_SCROLL_LOCK_TIMEOUT);
+ break;
+ case EDGE_SCROLL_TOUCH_STATE_EDGE:
+ t->scroll.threshold = 0.01; /* Do not allow 0.0 events */
+ break;
+ case EDGE_SCROLL_TOUCH_STATE_AREA:
+ t->scroll.edge = EDGE_NONE;
+ tp_set_pointer(tp, t);
+ break;
+ }
+}
+
+static void
+tp_edge_scroll_handle_none(struct tp_dispatch *tp,
+ struct tp_touch *t,
+ enum scroll_event event)
+{
+ struct libinput *libinput = tp->device->base.seat->libinput;
+
+ switch (event) {
+ case SCROLL_EVENT_TOUCH:
+ if (tp_touch_get_edge(tp, t)) {
+ tp_edge_scroll_set_state(tp, t,
+ EDGE_SCROLL_TOUCH_STATE_EDGE_NEW);
+ } else {
+ tp_edge_scroll_set_state(tp, t,
+ EDGE_SCROLL_TOUCH_STATE_AREA);
+ }
+ break;
+ case SCROLL_EVENT_MOTION:
+ case SCROLL_EVENT_RELEASE:
+ case SCROLL_EVENT_TIMEOUT:
+ case SCROLL_EVENT_POSTED:
+ log_bug_libinput(libinput,
+ "unexpect scroll event in none state\n");
+ break;
+ }
+}
+
+static void
+tp_edge_scroll_handle_edge_new(struct tp_dispatch *tp,
+ struct tp_touch *t,
+ enum scroll_event event)
+{
+ struct libinput *libinput = tp->device->base.seat->libinput;
+
+ switch (event) {
+ case SCROLL_EVENT_TOUCH:
+ log_bug_libinput(libinput,
+ "unexpect scroll event in edge new state\n");
+ break;
+ case SCROLL_EVENT_MOTION:
+ t->scroll.edge &= tp_touch_get_edge(tp, t);
+ if (!t->scroll.edge)
+ tp_edge_scroll_set_state(tp, t,
+ EDGE_SCROLL_TOUCH_STATE_AREA);
+ break;
+ case SCROLL_EVENT_RELEASE:
+ tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_NONE);
+ break;
+ case SCROLL_EVENT_TIMEOUT:
+ case SCROLL_EVENT_POSTED:
+ tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_EDGE);
+ break;
+ }
+}
+
+static void
+tp_edge_scroll_handle_edge(struct tp_dispatch *tp,
+ struct tp_touch *t,
+ enum scroll_event event)
+{
+ struct libinput *libinput = tp->device->base.seat->libinput;
+
+ switch (event) {
+ case SCROLL_EVENT_TOUCH:
+ case SCROLL_EVENT_TIMEOUT:
+ log_bug_libinput(libinput,
+ "unexpect scroll event in edge state\n");
+ break;
+ case SCROLL_EVENT_MOTION:
+ /* If started at the bottom right, decide in which dir to scroll */
+ if (t->scroll.edge == (EDGE_RIGHT | EDGE_BOTTOM)) {
+ t->scroll.edge &= tp_touch_get_edge(tp, t);
+ if (!t->scroll.edge)
+ tp_edge_scroll_set_state(tp, t,
+ EDGE_SCROLL_TOUCH_STATE_AREA);
+ }
+ break;
+ case SCROLL_EVENT_RELEASE:
+ tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_NONE);
+ break;
+ case SCROLL_EVENT_POSTED:
+ break;
+ }
+}
+
+static void
+tp_edge_scroll_handle_area(struct tp_dispatch *tp,
+ struct tp_touch *t,
+ enum scroll_event event)
+{
+ struct libinput *libinput = tp->device->base.seat->libinput;
+
+ switch (event) {
+ case SCROLL_EVENT_TOUCH:
+ case SCROLL_EVENT_TIMEOUT:
+ case SCROLL_EVENT_POSTED:
+ log_bug_libinput(libinput,
+ "unexpect scroll event in area state\n");
+ break;
+ case SCROLL_EVENT_MOTION:
+ break;
+ case SCROLL_EVENT_RELEASE:
+ tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_NONE);
+ break;
+ }
+}
+
+static void
+tp_edge_scroll_handle_event(struct tp_dispatch *tp,
+ struct tp_touch *t,
+ enum scroll_event event)
+{
+ switch (t->scroll.state) {
+ case EDGE_SCROLL_TOUCH_STATE_NONE:
+ tp_edge_scroll_handle_none(tp, t, event);
+ break;
+ case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW:
+ tp_edge_scroll_handle_edge_new(tp, t, event);
+ break;
+ case EDGE_SCROLL_TOUCH_STATE_EDGE:
+ tp_edge_scroll_handle_edge(tp, t, event);
+ break;
+ case EDGE_SCROLL_TOUCH_STATE_AREA:
+ tp_edge_scroll_handle_area(tp, t, event);
+ break;
+ }
+}
+
+static void
+tp_edge_scroll_handle_timeout(uint64_t now, void *data)
+{
+ struct tp_touch *t = data;
+
+ tp_edge_scroll_handle_event(t->tp, t, SCROLL_EVENT_TIMEOUT);
+}
+
+int
+tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device)
+{
+ struct tp_touch *t;
+ int width, height;
+ int edge_width, edge_height;
+
+ width = device->abs.absinfo_x->maximum - device->abs.absinfo_x->minimum;
+ height = device->abs.absinfo_y->maximum - device->abs.absinfo_y->minimum;
+
+ switch (tp->model) {
+ case MODEL_ALPS:
+ edge_width = width * .15;
+ edge_height = height * .15;
+ break;
+ case MODEL_APPLETOUCH: /* unibody are all clickpads, so N/A */
+ edge_width = width * .085;
+ edge_height = height * .085;
+ break;
+ default:
+ /* For elantech and synaptics, note for lenovo #40 series,
+ * e.g. the T440s min/max are the absolute edges, not the
+ * recommended ones as usual with synaptics. But these are
+ * clickpads, so N/A.
+ */
+ edge_width = width * .04;
+ edge_height = height * .054;
+ }
+
+ 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;
+ t->scroll.threshold = DEFAULT_SCROLL_THRESHOLD;
+ libinput_timer_init(&t->scroll.timer,
+ device->base.seat->libinput,
+ tp_edge_scroll_handle_timeout, t);
+ }
+
+ return 0;
+}
+
+void
+tp_destroy_edge_scroll(struct tp_dispatch *tp)
+{
+ struct tp_touch *t;
+
+ tp_for_each_touch(tp, t)
+ libinput_timer_cancel(&t->scroll.timer);
+}
+
+void
+tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time)
+{
+ struct tp_touch *t;
+
+ tp_for_each_touch(tp, t) {
+ if (!t->dirty)
+ continue;
+
+ switch (t->state) {
+ case TOUCH_NONE:
+ break;
+ case TOUCH_BEGIN:
+ tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_TOUCH);
+ break;
+ case TOUCH_UPDATE:
+ tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_MOTION);
+ break;
+ case TOUCH_END:
+ tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_RELEASE);
+ break;
+ }
+ }
+}
+
+int
+tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
+{
+ struct libinput_device *device = &tp->device->base;
+ struct tp_touch *t;
+ enum libinput_pointer_axis axis;
+ double dx, dy, *delta;
+
+ tp_for_each_touch(tp, t) {
+ if (!t->dirty)
+ continue;
+
+ switch (t->scroll.edge) {
+ case EDGE_NONE:
+ if (t->scroll.direction != -1) {
+ /* Send stop scroll event */
+ pointer_notify_axis(device, time,
+ t->scroll.direction, 0.0);
+ t->scroll.direction = -1;
+ }
+ continue;
+ case EDGE_RIGHT:
+ axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
+ delta = &dy;
+ break;
+ case EDGE_BOTTOM:
+ axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
+ delta = &dx;
+ break;
+ default: /* EDGE_RIGHT | EDGE_BOTTOM */
+ continue; /* Don't know direction yet, skip */
+ }
+
+ tp_get_delta(t, &dx, &dy);
+ tp_filter_motion(tp, &dx, &dy, time);
+
+ if (fabs(*delta) < t->scroll.threshold)
+ continue;
+
+ pointer_notify_axis(device, time, axis, *delta);
+ t->scroll.direction = axis;
+
+ tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_POSTED);
+ }
+
+ return 0; /* Edge touches are suppressed by edge_scroll_touch_active */
+}
+
+void
+tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time)
+{
+ struct libinput_device *device = &tp->device->base;
+ struct tp_touch *t;
+
+ tp_for_each_touch(tp, t) {
+ if (t->scroll.direction != -1) {
+ pointer_notify_axis(device, time,
+ t->scroll.direction, 0.0);
+ t->scroll.direction = -1;
+ }
+ }
+}
+
+int
+tp_edge_scroll_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
+{
+ return t->scroll.state == EDGE_SCROLL_TOUCH_STATE_AREA;
+}
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index 6d4b5835..8f76ddb8 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -56,7 +56,7 @@ tp_motion_history_offset(struct tp_touch *t, int offset)
return &t->history.samples[offset_index];
}
-static void
+void
tp_filter_motion(struct tp_dispatch *tp,
double *dx, double *dy, uint64_t time)
{
@@ -339,7 +339,9 @@ tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
{
return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
!t->palm.is_palm &&
- !t->pinned.is_pinned && tp_button_touch_active(tp, t);
+ !t->pinned.is_pinned &&
+ tp_button_touch_active(tp, t) &&
+ tp_edge_scroll_touch_active(tp, t);
}
void
@@ -430,15 +432,12 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
}
static int
-tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
+tp_twofinger_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
{
struct tp_touch *t;
int nfingers_down = 0;
- if (tp->scroll.method != LIBINPUT_CONFIG_SCROLL_2FG)
- return 0;
-
- /* No scrolling during tap-n-drag */
+ /* No 2fg scrolling during tap-n-drag */
if (tp_tap_dragging(tp))
return 0;
@@ -458,6 +457,60 @@ tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
}
static void
+tp_scroll_handle_state(struct tp_dispatch *tp, uint64_t time)
+{
+ /* Note this must be always called, so that it knows the state of
+ * touches when the scroll-mode changes.
+ */
+ tp_edge_scroll_handle_state(tp, time);
+}
+
+static int
+tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
+{
+ struct libinput *libinput = tp->device->base.seat->libinput;
+
+ switch (tp->scroll.method) {
+ case LIBINPUT_CONFIG_SCROLL_NO_SCROLL:
+ break;
+ case LIBINPUT_CONFIG_SCROLL_2FG:
+ return tp_twofinger_scroll_post_events(tp, time);
+ case LIBINPUT_CONFIG_SCROLL_EDGE:
+ return tp_edge_scroll_post_events(tp, time);
+ case LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN:
+ log_bug_libinput(libinput, "Unexpected scroll mode\n");
+ break;
+ }
+ return 0;
+}
+
+static void
+tp_stop_scroll_events(struct tp_dispatch *tp, uint64_t time)
+{
+ struct libinput *libinput = tp->device->base.seat->libinput;
+
+ switch (tp->scroll.method) {
+ case LIBINPUT_CONFIG_SCROLL_NO_SCROLL:
+ break;
+ case LIBINPUT_CONFIG_SCROLL_2FG:
+ evdev_stop_scroll(tp->device, time);
+ break;
+ case LIBINPUT_CONFIG_SCROLL_EDGE:
+ tp_edge_scroll_stop_events(tp, time);
+ break;
+ case LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN:
+ log_bug_libinput(libinput, "Unexpected scroll mode\n");
+ break;
+ }
+}
+
+static void
+tp_destroy_scroll(struct tp_dispatch *tp)
+{
+ tp_destroy_edge_scroll(tp);
+}
+
+static void
tp_process_state(struct tp_dispatch *tp, uint64_t time)
{
struct tp_touch *t;
@@ -490,6 +543,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
}
tp_button_handle_state(tp, time);
+ tp_scroll_handle_state(tp, time);
/*
* We have a physical button down event on a clickpad. To avoid
@@ -525,6 +579,7 @@ tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
tp->queued = TOUCHPAD_EVENT_NONE;
}
+
static void
tp_post_events(struct tp_dispatch *tp, uint64_t time)
{
@@ -542,7 +597,7 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time)
filter_motion |= tp_post_button_events(tp, time);
if (filter_motion || tp->sendevents.trackpoint_active) {
- evdev_stop_scroll(tp->device, time);
+ tp_stop_scroll_events(tp, time);
return;
}
@@ -621,6 +676,7 @@ tp_destroy(struct evdev_dispatch *dispatch)
tp_destroy_tap(tp);
tp_destroy_buttons(tp);
tp_destroy_sendevents(tp);
+ tp_destroy_scroll(tp);
free(tp->touches);
free(tp);
@@ -912,6 +968,9 @@ tp_scroll_config_scroll_method_get_methods(struct libinput_device *device)
if (tp->ntouches >= 2)
methods |= LIBINPUT_CONFIG_SCROLL_2FG;
+ if (!tp->buttons.is_clickpad)
+ methods |= LIBINPUT_CONFIG_SCROLL_EDGE;
+
return methods;
}
@@ -925,7 +984,7 @@ tp_scroll_config_scroll_method_set_method(struct libinput_device *device,
if (method == tp->scroll.method)
return LIBINPUT_CONFIG_STATUS_SUCCESS;
- evdev_stop_scroll(evdev, libinput_now(device->seat->libinput));
+ tp_stop_scroll_events(tp, libinput_now(device->seat->libinput));
tp->scroll.method = method;
return LIBINPUT_CONFIG_STATUS_SUCCESS;
@@ -941,14 +1000,28 @@ tp_scroll_config_scroll_method_get_method(struct libinput_device *device)
}
static enum libinput_config_scroll_method
+tp_scroll_get_default_method(struct tp_dispatch *tp)
+{
+ if (tp->ntouches >= 2)
+ return LIBINPUT_CONFIG_SCROLL_2FG;
+ else
+ return LIBINPUT_CONFIG_SCROLL_EDGE;
+}
+
+static enum libinput_config_scroll_method
tp_scroll_config_scroll_method_get_default_method(struct libinput_device *device)
{
- return LIBINPUT_CONFIG_SCROLL_2FG;
+ struct evdev_device *evdev = (struct evdev_device*)device;
+ struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
+
+ return tp_scroll_get_default_method(tp);
}
static int
tp_init_scroll(struct tp_dispatch *tp, struct evdev_device *device)
{
+ if (tp_edge_scroll_init(tp, device) != 0)
+ return -1;
evdev_init_natural_scroll(device);
@@ -956,7 +1029,7 @@ tp_init_scroll(struct tp_dispatch *tp, struct evdev_device *device)
tp->scroll.config_method.set_method = tp_scroll_config_scroll_method_set_method;
tp->scroll.config_method.get_method = tp_scroll_config_scroll_method_get_method;
tp->scroll.config_method.get_default_method = tp_scroll_config_scroll_method_get_default_method;
- tp->scroll.method = tp_scroll_config_scroll_method_get_default_method(&tp->device->base);
+ tp->scroll.method = tp_scroll_get_default_method(tp);
tp->device->base.config.scroll_method = &tp->scroll.config_method;
/* In mm for touchpads with valid resolution, see tp_init_accel() */
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 7f3ce493..b2603b44 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -103,6 +103,20 @@ enum tp_tap_touch_state {
TAP_TOUCH_STATE_DEAD, /**< exceeded motion/timeout */
};
+/* For edge scrolling, so we only care about right and bottom */
+enum tp_edge {
+ EDGE_NONE = 0,
+ EDGE_RIGHT = (1 << 0),
+ EDGE_BOTTOM = (1 << 1),
+};
+
+enum tp_edge_scroll_touch_state {
+ EDGE_SCROLL_TOUCH_STATE_NONE,
+ EDGE_SCROLL_TOUCH_STATE_EDGE_NEW,
+ EDGE_SCROLL_TOUCH_STATE_EDGE,
+ EDGE_SCROLL_TOUCH_STATE_AREA,
+};
+
struct tp_motion {
int32_t x;
int32_t y;
@@ -151,6 +165,14 @@ struct tp_touch {
} tap;
struct {
+ enum tp_edge_scroll_touch_state state;
+ uint32_t edge;
+ int direction;
+ double threshold;
+ struct libinput_timer timer;
+ } scroll;
+
+ struct {
bool is_palm;
int32_t x, y; /* first coordinates if is_palm == true */
uint32_t time; /* first timestamp if is_palm == true */
@@ -214,6 +236,8 @@ struct tp_dispatch {
struct {
struct libinput_device_config_scroll_method config_method;
enum libinput_config_scroll_method method;
+ int32_t right_edge;
+ int32_t bottom_edge;
} scroll;
enum touchpad_event queued;
@@ -250,6 +274,10 @@ tp_get_delta(struct tp_touch *t, double *dx, double *dy);
void
tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t);
+void
+tp_filter_motion(struct tp_dispatch *tp,
+ double *dx, double *dy, uint64_t time);
+
int
tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time);
@@ -304,4 +332,22 @@ tp_tap_resume(struct tp_dispatch *tp, uint64_t time);
bool
tp_tap_dragging(struct tp_dispatch *tp);
+int
+tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device);
+
+void
+tp_destroy_edge_scroll(struct tp_dispatch *tp);
+
+void
+tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time);
+
+int
+tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time);
+
+void
+tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time);
+
+int
+tp_edge_scroll_touch_active(struct tp_dispatch *tp, struct tp_touch *t);
+
#endif