Skip to content

Commit 55a10e3

Browse files
committed
Add option SmoothPanscrollingEnabled
This is a backwards-compatibility option similar to the Pressure2K option. GDK2 applications are effectively limited to 7 axes (value of GDK_AXES_LAST in GDK2) and adding smooth panscrolling gives our device 8 axes total. This can cause issues when the driver, GDK and the application don't agree on the number of axes in the device. This is an application/GDK bug but as for the Pressure2K option we expect there to be applications that cannot be updated easily. To work around this, provide a driver option to disable this new feature altogether and effectively return to 6 axes for the pen device. This is a partial revert of fe923e9 "Implement smooth panscrolling" for the implementation. Minor changes though, the implementation now relies more on local variables than pointers. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
1 parent 815edf6 commit 55a10e3

File tree

6 files changed

+97
-22
lines changed

6 files changed

+97
-22
lines changed

man/wacom.man

+22
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,17 @@ scroll event is generated when using the "pan" action. Smaller values
288288
will require less distance and be more sensitive. Larger values will
289289
require more distance and be less sensitive. Default: 1300 or 2600
290290
depending on tablet resolution (corresponds to 13 mm of distance).
291+
.TP 4
292+
.B Option \fI"SmoothPanscrollingEnabled"\fP \fI"bool"\fP
293+
Allows to disable smooth panscrolling. Default: true.
294+
If disabled, panscrolling sends legacy button events instead.
295+
This option exists for backwards compatibility with
296+
applications that have the number of axes on a device limited to 6.
297+
See section
298+
.B BUGS
299+
for more details. This option should not be used unless the user runs one or
300+
more applications that do not support more than six axes.
301+
291302
.SH "TOUCH GESTURES"
292303
.SS Single finger (1FG)
293304
.LP
@@ -334,6 +345,17 @@ option to reduce the range to 2048 steps. Note that this setting applies to
334345
the device. Once applied, all applications will see the reduced pressure
335346
range. It is not possible to provide this setting on a per-application
336347
basis.
348+
.SS "Smooth panscrolling exceeds the axis limits"
349+
In version 1.2.0, the driver's support for smooth panscrolling added two axes
350+
to the stylus device, bringing the total axis count to eight. The number of
351+
axes is advertised through the X Input Protocol but some applications (notably
352+
GIMP 2.xx) cannot handle more than six axes. This is an application bug but for
353+
backwards-compatibility with such applications, this driver provides the
354+
.B SmoothPanscrollingEnabled
355+
option to disable this feature and thus limit the axis count to six. Note that
356+
this setting applies to the device. Once applied, the driver will not send
357+
smooth panscroll events at all. It is not possible to provide this setting on a
358+
per-application basis.
337359
.SH "SEE ALSO"
338360
__xservername__(1), xorg.conf(5),
339361
xorg.conf.d(5), X(7)

src/wcmCommon.c

+37-5
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,35 @@ Bool wcmDevSwitchModeCall(WacomDevicePtr priv, Bool absolute)
9595
return TRUE;
9696
}
9797

98+
static int wcmButtonPerNotch(WacomDevicePtr priv, int value, int threshold, int btn_positive, int btn_negative)
99+
{
100+
int mode = is_absolute(priv);
101+
int notches = value / threshold;
102+
int button = (notches > 0) ? btn_positive : btn_negative;
103+
int i;
104+
WacomAxisData axes = {0};
105+
106+
for (i = 0; i < abs(notches); i++) {
107+
wcmEmitButton(priv, mode, button, 1, &axes);
108+
wcmEmitButton(priv, mode, button, 0, &axes);
109+
}
110+
111+
return value % threshold;
112+
}
113+
98114
static void wcmPanscroll(WacomDevicePtr priv, const WacomDeviceState *ds, int x, int y)
99115
{
100116
WacomCommonPtr common = priv->common;
101117
int threshold = common->wcmPanscrollThreshold;
102118
int delta_x, delta_y;
119+
bool smooth_scrolling = priv->common->wcmPanscrollIsSmooth;
103120

104-
if (!(priv->flags & SCROLLMODE_FLAG) || !(ds->buttons & 1))
121+
if (!(priv->flags & SCROLLMODE_FLAG) || !(ds->buttons & 1)) {
122+
priv->wcmPanscrollState = *ds;
123+
priv->wcmPanscrollState.x = 0;
124+
priv->wcmPanscrollState.y = 0;
105125
return;
126+
}
106127

107128
/* Tip has gone down down; don't send pan event yet */
108129
if (!(priv->oldState.buttons & 1)) {
@@ -120,10 +141,21 @@ static void wcmPanscroll(WacomDevicePtr priv, const WacomDeviceState *ds, int x,
120141

121142
DBG(6, priv, "pan x = %d, pan y = %d\n", delta_x, delta_y);
122143

123-
WacomAxisData axes = {0};
124-
wcmAxisSet(&axes, WACOM_AXIS_SCROLL_X, -delta_x * PANSCROLL_INCREMENT/threshold);
125-
wcmAxisSet(&axes, WACOM_AXIS_SCROLL_Y, -delta_y * PANSCROLL_INCREMENT/threshold);
126-
wcmEmitMotion(priv, FALSE, &axes);
144+
if (smooth_scrolling) {
145+
WacomAxisData axes = {0};
146+
wcmAxisSet(&axes, WACOM_AXIS_SCROLL_X, -delta_x * PANSCROLL_INCREMENT/threshold);
147+
wcmAxisSet(&axes, WACOM_AXIS_SCROLL_Y, -delta_y * PANSCROLL_INCREMENT/threshold);
148+
wcmEmitMotion(priv, FALSE, &axes);
149+
} else {
150+
int accumulated_x = priv->wcmPanscrollState.x + delta_x;
151+
int accumulated_y = priv->wcmPanscrollState.y + delta_y;
152+
153+
int remainder_x = wcmButtonPerNotch(priv, accumulated_x, threshold, 6, 7);
154+
int remainder_y = wcmButtonPerNotch(priv, accumulated_y, threshold, 4, 5);
155+
156+
priv->wcmPanscrollState.x = remainder_x;
157+
priv->wcmPanscrollState.y = remainder_y;
158+
}
127159
}
128160

129161
void wcmResetButtonAction(WacomDevicePtr priv, int button)

src/wcmConfig.c

+5-4
Original file line numberDiff line numberDiff line change
@@ -1115,7 +1115,7 @@ int wcmDevOpen(WacomDevicePtr priv)
11151115
* Any de-facto defined axis index left unused is initialized with default
11161116
* attributes.
11171117
*/
1118-
static int wcmInitAxes(WacomDevicePtr priv)
1118+
static int wcmInitAxes(WacomDevicePtr priv, Bool use_smooth_panscrolling)
11191119
{
11201120
WacomCommonPtr common = priv->common;
11211121
int min, max, res;
@@ -1220,7 +1220,7 @@ static int wcmInitAxes(WacomDevicePtr priv)
12201220
wcmInitAxis(priv, WACOM_AXIS_RING2, min, max, res);
12211221
}
12221222

1223-
if (IsPen(priv)) {
1223+
if (use_smooth_panscrolling && IsPen(priv)) {
12241224
/* seventh valuator: scroll_x */
12251225
wcmInitAxis(priv, WACOM_AXIS_SCROLL_X, -1, -1, 0);
12261226

@@ -1235,6 +1235,7 @@ Bool wcmDevInit(WacomDevicePtr priv)
12351235
{
12361236
WacomCommonPtr common = priv->common;
12371237
int nbaxes, nbbuttons;
1238+
Bool use_smooth_panscrolling = priv->common->wcmPanscrollIsSmooth;
12381239

12391240
/* Detect tablet configuration, if possible */
12401241
if (priv->common->wcmModel->DetectConfig)
@@ -1249,7 +1250,7 @@ Bool wcmDevInit(WacomDevicePtr priv)
12491250
nbaxes = priv->naxes = nbaxes + 1; /* ABS wheel 2 */
12501251

12511252
/* For smooth scrolling we set up two additional axes */
1252-
if (IsPen(priv))
1253+
if (use_smooth_panscrolling && IsPen(priv))
12531254
nbaxes = priv->naxes = nbaxes + 2; /* Scroll X and Y */
12541255

12551256
/* if more than 3 buttons, offset by the four scroll buttons,
@@ -1287,7 +1288,7 @@ Bool wcmDevInit(WacomDevicePtr priv)
12871288
}
12881289
}
12891290

1290-
if (!wcmInitAxes(priv))
1291+
if (!wcmInitAxes(priv, use_smooth_panscrolling))
12911292
return FALSE;
12921293

12931294
return TRUE;

src/wcmValidateDevice.c

+4
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,10 @@ Bool wcmPreInitParseOptions(WacomDevicePtr priv, Bool is_primary,
589589

590590
common->wcmPanscrollThreshold = wcmOptGetInt(priv, "PanScrollThreshold",
591591
common->wcmPanscrollThreshold);
592+
common->wcmPanscrollIsSmooth = wcmOptGetBool(priv, "SmoothPanscrollingEnabled",
593+
TRUE);
594+
wcmLog(priv, W_CONFIG, "Smooth panscrolling is %s\n",
595+
common->wcmPanscrollIsSmooth ? "enabled" : "disabled");
592596

593597
/* The first device doesn't need to add any tools/areas as it
594598
* will be the first anyway. So if different, add tool

src/xf86WacomDefs.h

+1
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ struct _WacomCommonRec
465465
int wcmPressureRecalibration; /* Determine if pressure recalibration of
466466
worn pens should be performed */
467467
int wcmPanscrollThreshold; /* distance pen must move to send a panscroll event */
468+
int wcmPanscrollIsSmooth; /* nonzero if smooth panscrolling is enabled */
468469

469470
int bufpos; /* position with buffer */
470471
unsigned char buffer[BUFFER_SIZE]; /* data read from device */

test/test_wacom.py

+28-13
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717

1818
from typing import Dict
19-
from . import Device, Monitor, Ev, Sev, Proximity, PenId
19+
from . import Button, Device, Monitor, Ev, Sev, Proximity, PenId
2020

2121
import pytest
2222
import logging
@@ -327,13 +327,15 @@ def test_axis_updates_wheel(mainloop, opts, stylus_type):
327327
assert first_wheel == current_wheel
328328

329329

330+
@pytest.mark.parametrize("smooth", (True, False))
330331
@pytest.mark.parametrize("vertical", (True, False))
331-
def test_scroll(mainloop, opts, vertical):
332+
def test_scroll(mainloop, opts, vertical, smooth):
332333
"""
333334
Check panscrolling works correctly
334335
"""
335336
dev = Device.from_name("PTH660", "Pen")
336337
opts["PanScrollThreshold"] = "150"
338+
opts["SmoothPanscrollingEnabled"] = "true" if smooth else "false"
337339

338340
prox_in = [
339341
Sev("ABS_X", 50),
@@ -379,17 +381,30 @@ def test_scroll(mainloop, opts, vertical):
379381
monitor.write_events(prox_out)
380382

381383
mainloop.run()
382-
have_we_scrolled = False
383-
for event in monitor.events:
384-
if vertical:
385-
if event.axes.scroll_y != 0:
386-
assert event.axes.scroll_y == -808265
387-
have_we_scrolled = True
388-
else:
389-
if event.axes.scroll_x != 0:
390-
assert event.axes.scroll_x == -1223320
391-
have_we_scrolled = True
392-
assert have_we_scrolled
384+
if smooth:
385+
have_we_scrolled = False
386+
for event in monitor.events:
387+
if vertical:
388+
if event.axes.scroll_y != 0:
389+
assert event.axes.scroll_y == -808265
390+
have_we_scrolled = True
391+
else:
392+
if event.axes.scroll_x != 0:
393+
assert event.axes.scroll_x == -1223320
394+
have_we_scrolled = True
395+
assert have_we_scrolled
396+
else:
397+
have_button_events = False
398+
for event in monitor.events:
399+
if isinstance(event, Button):
400+
print(event.button)
401+
if vertical:
402+
if event.button == 4: # we're moving bottom-to-top
403+
have_button_events = True
404+
else:
405+
if event.button == 6: # we're moving right-to-left
406+
have_button_events = True
407+
assert have_button_events
393408

394409

395410
# vim: set expandtab tabstop=4 shiftwidth=4:

0 commit comments

Comments
 (0)