2 * Copyright © 2012 Jonas Ådahl
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.
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.
28 #include <wayland-util.h>
30 #include "compositor.h"
34 weston_filter_dispatch(struct weston_motion_filter *filter,
35 struct weston_motion_params *motion,
36 void *data, uint32_t time)
38 filter->interface->filter(filter, motion, data, time);
42 * Pointer acceleration filter
45 #define MAX_VELOCITY_DIFF 1.0
46 #define MOTION_TIMEOUT 300 /* (ms) */
47 #define NUM_POINTER_TRACKERS 16
49 struct pointer_tracker {
56 struct pointer_accelerator;
57 struct pointer_accelerator {
58 struct weston_motion_filter base;
60 accel_profile_func_t profile;
67 struct pointer_tracker *trackers;
80 UNDEFINED_DIRECTION = 0xff
84 get_direction(int dx, int dy)
86 int dir = UNDEFINED_DIRECTION;
90 if (abs(dx) < 2 && abs(dy) < 2) {
93 else if (dx > 0 && dy < 0)
95 else if (dx < 0 && dy > 0)
97 else if (dx < 0 && dy < 0)
109 /* Calculate r within the interval [0 to 8)
111 * r = [0 .. 2π] where 0 is North
112 * d_f = r / 2π ([0 .. 1))
116 r = fmod(r + 2.5*M_PI, 2*M_PI);
119 /* Mark one or two close enough octants */
120 d1 = (int)(r + 0.9) % 8;
121 d2 = (int)(r + 0.1) % 8;
123 dir = (1 << d1) | (1 << d2);
130 feed_trackers(struct pointer_accelerator *accel,
131 double dx, double dy,
135 struct pointer_tracker *trackers = accel->trackers;
137 for (i = 0; i < NUM_POINTER_TRACKERS; i++) {
138 trackers[i].dx += dx;
139 trackers[i].dy += dy;
142 current = (accel->cur_tracker + 1) % NUM_POINTER_TRACKERS;
143 accel->cur_tracker = current;
145 trackers[current].dx = 0.0;
146 trackers[current].dy = 0.0;
147 trackers[current].time = time;
148 trackers[current].dir = get_direction(dx, dy);
151 static struct pointer_tracker *
152 tracker_by_offset(struct pointer_accelerator *accel, unsigned int offset)
155 (accel->cur_tracker + NUM_POINTER_TRACKERS - offset)
156 % NUM_POINTER_TRACKERS;
157 return &accel->trackers[index];
161 calculate_tracker_velocity(struct pointer_tracker *tracker, uint32_t time)
169 distance = sqrt(dx*dx + dy*dy);
170 return distance / (double)(time - tracker->time);
174 calculate_velocity(struct pointer_accelerator *accel, uint32_t time)
176 struct pointer_tracker *tracker;
179 double initial_velocity;
180 double velocity_diff;
183 unsigned int dir = tracker_by_offset(accel, 0)->dir;
185 /* Find first velocity */
186 for (offset = 1; offset < NUM_POINTER_TRACKERS; offset++) {
187 tracker = tracker_by_offset(accel, offset);
189 if (time <= tracker->time)
192 result = initial_velocity =
193 calculate_tracker_velocity(tracker, time);
194 if (initial_velocity > 0.0)
198 /* Find least recent vector within a timelimit, maximum velocity diff
199 * and direction threshold. */
200 for (; offset < NUM_POINTER_TRACKERS; offset++) {
201 tracker = tracker_by_offset(accel, offset);
203 /* Stop if too far away in time */
204 if (time - tracker->time > MOTION_TIMEOUT ||
205 tracker->time > time)
208 /* Stop if direction changed */
213 velocity = calculate_tracker_velocity(tracker, time);
215 /* Stop if velocity differs too much from initial */
216 velocity_diff = fabs(initial_velocity - velocity);
217 if (velocity_diff > MAX_VELOCITY_DIFF)
227 acceleration_profile(struct pointer_accelerator *accel,
228 void *data, double velocity, uint32_t time)
230 return accel->profile(&accel->base, data, velocity, time);
234 calculate_acceleration(struct pointer_accelerator *accel,
235 void *data, double velocity, uint32_t time)
239 /* Use Simpson's rule to calculate the avarage acceleration between
240 * the previous motion and the most recent. */
241 factor = acceleration_profile(accel, data, velocity, time);
242 factor += acceleration_profile(accel, data, accel->last_velocity, time);
244 acceleration_profile(accel, data,
245 (accel->last_velocity + velocity) / 2,
248 factor = factor / 6.0;
254 soften_delta(double last_delta, double delta)
256 if (delta < -1.0 || delta > 1.0) {
257 if (delta > last_delta)
259 else if (delta < last_delta)
267 apply_softening(struct pointer_accelerator *accel,
268 struct weston_motion_params *motion)
270 motion->dx = soften_delta(accel->last_dx, motion->dx);
271 motion->dy = soften_delta(accel->last_dy, motion->dy);
275 accelerator_filter(struct weston_motion_filter *filter,
276 struct weston_motion_params *motion,
277 void *data, uint32_t time)
279 struct pointer_accelerator *accel =
280 (struct pointer_accelerator *) filter;
284 feed_trackers(accel, motion->dx, motion->dy, time);
285 velocity = calculate_velocity(accel, time);
286 accel_value = calculate_acceleration(accel, data, velocity, time);
288 motion->dx = accel_value * motion->dx;
289 motion->dy = accel_value * motion->dy;
291 apply_softening(accel, motion);
293 accel->last_dx = motion->dx;
294 accel->last_dy = motion->dy;
296 accel->last_velocity = velocity;
300 accelerator_destroy(struct weston_motion_filter *filter)
302 struct pointer_accelerator *accel =
303 (struct pointer_accelerator *) filter;
305 free(accel->trackers);
309 struct weston_motion_filter_interface accelerator_interface = {
314 struct weston_motion_filter *
315 create_pointer_accelator_filter(accel_profile_func_t profile)
317 struct pointer_accelerator *filter;
319 filter = malloc(sizeof *filter);
323 filter->base.interface = &accelerator_interface;
324 wl_list_init(&filter->base.link);
326 filter->profile = profile;
327 filter->last_velocity = 0.0;
332 calloc(NUM_POINTER_TRACKERS, sizeof *filter->trackers);
333 filter->cur_tracker = 0;
335 return &filter->base;