feat: touchgesturebinds

based on lisgd
This commit is contained in:
werapi 2026-03-26 19:30:16 +01:00
parent 545c452136
commit 9d7edec710
3 changed files with 562 additions and 17 deletions

View file

@ -158,6 +158,15 @@ typedef struct {
Arg arg;
} GestureBinding;
typedef struct {
uint32_t swipe;
uint32_t edge;
uint32_t distance;
uint32_t fingers_count;
int32_t (*func)(const Arg *);
Arg arg;
} TouchGestureBinding;
typedef struct {
int32_t id;
char *layout_name;
@ -282,6 +291,14 @@ typedef struct {
double axis_scroll_factor;
double touch_distance_threshold;
double touch_degrees_leniency;
uint32_t touch_timeoutms;
double touch_edge_size_left;
double touch_edge_size_top;
double touch_edge_size_right;
double touch_edge_size_bottom;
int32_t blur;
int32_t blur_layer;
int32_t blur_optimized;
@ -344,6 +361,9 @@ typedef struct {
GestureBinding *gesture_bindings;
int32_t gesture_bindings_count;
TouchGestureBinding *touch_gesture_bindings;
int32_t touch_gesture_bindings_count;
ConfigEnv **env;
int32_t env_count;
@ -532,6 +552,92 @@ int32_t parse_direction(const char *str) {
}
}
int32_t parse_touch_direction(const char *str) {
char lowerStr[11];
int32_t i = 0;
while (str[i] && i < 10) {
lowerStr[i] = tolower(str[i]);
i++;
}
lowerStr[i] = '\0';
if (strcmp(lowerStr, "up") == 0) {
return TOUCH_SWIPE_UP;
} else if (strcmp(lowerStr, "down") == 0) {
return TOUCH_SWIPE_DOWN;
} else if (strcmp(lowerStr, "left") == 0) {
return TOUCH_SWIPE_LEFT;
} else if (strcmp(lowerStr, "right") == 0) {
return TOUCH_SWIPE_RIGHT;
} else if (strcmp(lowerStr, "up_left") == 0) {
return TOUCH_SWIPE_UP_LEFT;
} else if (strcmp(lowerStr, "up_right") == 0) {
return TOUCH_SWIPE_UP_RIGHT;
} else if (strcmp(lowerStr, "down_left") == 0) {
return TOUCH_SWIPE_DOWN_LEFT;
} else if (strcmp(lowerStr, "down_right") == 0) {
return TOUCH_SWIPE_DOWN_RIGHT;
} else {
return TOUCH_SWIPE_NONE;
}
}
int32_t parse_touch_edge(const char *str) {
char lowerStr[13];
int32_t i = 0;
while (str[i] && i < 12) {
lowerStr[i] = tolower(str[i]);
i++;
}
lowerStr[i] = '\0';
if (strcmp(lowerStr, "any") == 0) {
return EDGE_ANY;
} else if (strcmp(lowerStr, "none") == 0) {
return EDGE_NONE;
} else if (strcmp(lowerStr, "left") == 0) {
return EDGE_LEFT;
} else if (strcmp(lowerStr, "right") == 0) {
return EDGE_RIGHT;
} else if (strcmp(lowerStr, "top") == 0) {
return EDGE_TOP;
} else if (strcmp(lowerStr, "bottom") == 0) {
return EDGE_BOTTOM;
} else if (strcmp(lowerStr, "top_left") == 0) {
return CORNER_TOP_LEFT;
} else if (strcmp(lowerStr, "top_right") == 0) {
return CORNER_TOP_RIGHT;
} else if (strcmp(lowerStr, "bottom_left") == 0) {
return CORNER_BOTTOM_LEFT;
} else if (strcmp(lowerStr, "bottom_right") == 0) {
return CORNER_BOTTOM_RIGHT;
} else {
return EDGE_ANY;
}
}
int32_t parse_distance(const char *str) {
char lowerStr[7];
int32_t i = 0;
while (str[i] && i < 6) {
lowerStr[i] = tolower(str[i]);
i++;
}
lowerStr[i] = '\0';
if (strcmp(lowerStr, "any") == 0) {
return DISTANCE_ANY;
} else if (strcmp(lowerStr, "short") == 0) {
return DISTANCE_SHORT;
} else if (strcmp(lowerStr, "medium") == 0) {
return DISTANCE_MEDIUM;
} else if (strcmp(lowerStr, "long") == 0) {
return DISTANCE_LONG;
} else {
return DISTANCE_ANY;
}
}
int32_t parse_fold_state(const char *str) {
// 将输入字符串转换为小写
char lowerStr[10];
@ -1677,6 +1783,20 @@ bool parse_option(Config *config, char *key, char *value) {
config->button_map = atoi(value);
} else if (strcmp(key, "axis_scroll_factor") == 0) {
config->axis_scroll_factor = atof(value);
} else if (strcmp(key, "touch_distance_threshold") == 0) {
config->touch_distance_threshold = atof(value);
} else if (strcmp(key, "touch_degrees_leniency") == 0) {
config->touch_degrees_leniency = atof(value);
} else if (strcmp(key, "touch_timeoutms") == 0) {
config->touch_timeoutms = atoi(value);
} else if (strcmp(key, "touch_edge_size_left") == 0) {
config->touch_edge_size_left = atof(value);
} else if (strcmp(key, "touch_edge_size_top") == 0) {
config->touch_edge_size_top = atof(value);
} else if (strcmp(key, "touch_edge_size_right") == 0) {
config->touch_edge_size_right = atof(value);
} else if (strcmp(key, "touch_edge_size_bottom") == 0) {
config->touch_edge_size_bottom = atof(value);
} else if (strcmp(key, "gappih") == 0) {
config->gappih = atoi(value);
} else if (strcmp(key, "gappiv") == 0) {
@ -2699,6 +2819,91 @@ bool parse_option(Config *config, char *key, char *value) {
config->gesture_bindings_count++;
}
} else if (strncmp(key, "touchgesturebind", 16) == 0) {
config->touch_gesture_bindings =
realloc(config->touch_gesture_bindings,
(config->touch_gesture_bindings_count + 1) *
sizeof(TouchGestureBinding));
if (!config->touch_gesture_bindings) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Failed to allocate "
"memory for axis touchgesturebind\n");
return false;
}
TouchGestureBinding *binding =
&config
->touch_gesture_bindings[config->touch_gesture_bindings_count];
memset(binding, 0, sizeof(TouchGestureBinding));
char swipe_str[256], edge_str[256], distance_str[256],
fingers_count_str[256], func_name[256],
arg_value[256] = "0\0", arg_value2[256] = "0\0",
arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "0\0";
if (sscanf(value,
"%255[^,],%255[^,],%255[^,],%255[^,],%255["
"^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^\n]",
swipe_str, edge_str, distance_str, fingers_count_str,
func_name, arg_value, arg_value2, arg_value3, arg_value4,
arg_value5) < 4) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid touchgesturebind "
"format: %s\n",
value);
return false;
}
trim_whitespace(swipe_str);
trim_whitespace(edge_str);
trim_whitespace(distance_str);
trim_whitespace(fingers_count_str);
trim_whitespace(func_name);
trim_whitespace(arg_value);
trim_whitespace(arg_value2);
trim_whitespace(arg_value3);
trim_whitespace(arg_value4);
trim_whitespace(arg_value5);
binding->swipe = parse_touch_direction(swipe_str);
binding->edge = parse_touch_edge(edge_str);
binding->distance = parse_distance(distance_str);
binding->fingers_count = atoi(fingers_count_str);
binding->arg.i = 0;
binding->arg.i2 = 0;
binding->arg.f = 0.0f;
binding->arg.f2 = 0.0f;
binding->arg.ui = 0;
binding->arg.ui2 = 0;
binding->arg.v = NULL;
binding->arg.v2 = NULL;
binding->arg.v3 = NULL;
binding->func =
parse_func_name(func_name, &binding->arg, arg_value, arg_value2,
arg_value3, arg_value4, arg_value5);
if (!binding->func) {
if (binding->arg.v) {
free(binding->arg.v);
binding->arg.v = NULL;
}
if (binding->arg.v2) {
free(binding->arg.v2);
binding->arg.v2 = NULL;
}
if (binding->arg.v3) {
free(binding->arg.v3);
binding->arg.v3 = NULL;
}
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Unknown "
"dispatch in "
"touchgesturebind: \033[1m\033[31m%s\n",
func_name);
return false;
} else {
config->touch_gesture_bindings_count++;
}
} else if (strncmp(key, "source-optional", 15) == 0) {
parse_config_file(config, value, false);
} else if (strncmp(key, "source", 6) == 0) {
@ -2995,6 +3200,27 @@ void free_config(void) {
config.gesture_bindings_count = 0;
}
// release touch_gesture_bindings
if (config.touch_gesture_bindings) {
for (i = 0; i < config.touch_gesture_bindings_count; i++) {
if (config.touch_gesture_bindings[i].arg.v) {
free((void *)config.touch_gesture_bindings[i].arg.v);
config.touch_gesture_bindings[i].arg.v = NULL;
}
if (config.touch_gesture_bindings[i].arg.v2) {
free((void *)config.touch_gesture_bindings[i].arg.v2);
config.touch_gesture_bindings[i].arg.v2 = NULL;
}
if (config.touch_gesture_bindings[i].arg.v3) {
free((void *)config.touch_gesture_bindings[i].arg.v3);
config.touch_gesture_bindings[i].arg.v3 = NULL;
}
}
free(config.touch_gesture_bindings);
config.touch_gesture_bindings = NULL;
config.touch_gesture_bindings_count = 0;
}
// 释放 tag_rules
if (config.tag_rules) {
for (int32_t i = 0; i < config.tag_rules_count; i++) {
@ -3219,6 +3445,19 @@ void override_config(void) {
config.button_map = CLAMP_INT(config.button_map, 0, 1);
config.axis_scroll_factor =
CLAMP_FLOAT(config.axis_scroll_factor, 0.1f, 10.0f);
config.touch_distance_threshold =
CLAMP_FLOAT(config.touch_distance_threshold, 1.0f, 10000.0f);
config.touch_degrees_leniency =
CLAMP_FLOAT(config.touch_degrees_leniency, 0.0f, 45.0f);
config.touch_timeoutms = CLAMP_INT(config.touch_timeoutms, 1, 60000);
config.touch_edge_size_left =
CLAMP_FLOAT(config.touch_edge_size_left, 1.0f, 10000.0f);
config.touch_edge_size_top =
CLAMP_FLOAT(config.touch_edge_size_top, 1.0f, 10000.0f);
config.touch_edge_size_right =
CLAMP_FLOAT(config.touch_edge_size_right, 1.0f, 10000.0f);
config.touch_edge_size_bottom =
CLAMP_FLOAT(config.touch_edge_size_bottom, 1.0f, 10000.0f);
config.gappih = CLAMP_INT(config.gappih, 0, 1000);
config.gappiv = CLAMP_INT(config.gappiv, 0, 1000);
config.gappoh = CLAMP_INT(config.gappoh, 0, 1000);
@ -3311,6 +3550,13 @@ void set_value_default() {
config.scratchpad_cross_monitor = 0;
config.focus_cross_tag = 0;
config.axis_scroll_factor = 1.0;
config.touch_distance_threshold = 50.0;
config.touch_degrees_leniency = 15.0;
config.touch_timeoutms = 800;
config.touch_edge_size_left = 50.0;
config.touch_edge_size_top = 50.0;
config.touch_edge_size_right = 50.0;
config.touch_edge_size_bottom = 50.0;
config.view_current_to_back = 0;
config.single_scratchpad = 1;
config.xwayland_persistence = 1;
@ -3505,6 +3751,8 @@ bool parse_config(void) {
config.switch_bindings_count = 0;
config.gesture_bindings = NULL;
config.gesture_bindings_count = 0;
config.touch_gesture_bindings = NULL;
config.touch_gesture_bindings_count = 0;
config.env = NULL;
config.env_count = 0;
config.exec = NULL;

237
src/dispatch/gesture.h Normal file
View file

@ -0,0 +1,237 @@
int32_t gesture_calculate_swipe_within_degrees(double gestdegrees,
double wantdegrees) {
return (gestdegrees >= wantdegrees - config.touch_degrees_leniency &&
gestdegrees <= wantdegrees + config.touch_degrees_leniency);
}
uint32_t gesture_calculate_swipe(double x0, double y0, double x1, double y1) {
double t, degrees, distance;
t = atan2(x1 - x0, y0 - y1);
degrees = 57.2957795130823209 * (t < 0 ? t + 6.2831853071795865 : t);
distance = sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2));
wlr_log(WLR_DEBUG, "Swipe distance=[%.2f]; degrees=[%.2f]", distance,
degrees);
if (distance < config.touch_distance_threshold)
return TOUCH_SWIPE_NONE;
else if (gesture_calculate_swipe_within_degrees(degrees, 0))
return TOUCH_SWIPE_UP;
else if (gesture_calculate_swipe_within_degrees(degrees, 45))
return TOUCH_SWIPE_UP_RIGHT;
else if (gesture_calculate_swipe_within_degrees(degrees, 90))
return TOUCH_SWIPE_RIGHT;
else if (gesture_calculate_swipe_within_degrees(degrees, 135))
return TOUCH_SWIPE_DOWN_RIGHT;
else if (gesture_calculate_swipe_within_degrees(degrees, 180))
return TOUCH_SWIPE_DOWN;
else if (gesture_calculate_swipe_within_degrees(degrees, 225))
return TOUCH_SWIPE_DOWN_LEFT;
else if (gesture_calculate_swipe_within_degrees(degrees, 270))
return TOUCH_SWIPE_LEFT;
else if (gesture_calculate_swipe_within_degrees(degrees, 315))
return TOUCH_SWIPE_UP_LEFT;
else if (gesture_calculate_swipe_within_degrees(degrees, 360))
return TOUCH_SWIPE_UP;
return TOUCH_SWIPE_NONE;
}
uint32_t gesture_calculate_distance(Monitor *m, double x0, double y0, double x1,
double y1, int32_t swipe) {
double distance = sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2));
double diag = sqrt(pow(m->m.width, 2) + pow(m->m.height, 2));
switch (swipe) {
case TOUCH_SWIPE_UP:
case TOUCH_SWIPE_DOWN:
if (distance >= m->m.height * 0.66) {
return DISTANCE_LONG;
} else if (distance >= m->m.height * 0.33) {
return DISTANCE_MEDIUM;
} else {
return DISTANCE_SHORT;
}
break;
case TOUCH_SWIPE_RIGHT:
case TOUCH_SWIPE_LEFT:
if (distance >= m->m.width * 0.66) {
return DISTANCE_LONG;
} else if (distance >= m->m.width * 0.33) {
return DISTANCE_MEDIUM;
} else {
return DISTANCE_SHORT;
}
break;
case TOUCH_SWIPE_UP_RIGHT:
case TOUCH_SWIPE_UP_LEFT:
case TOUCH_SWIPE_DOWN_RIGHT:
case TOUCH_SWIPE_DOWN_LEFT:
if (distance >= diag * 0.66) {
return DISTANCE_LONG;
} else if (distance >= diag * 0.33) {
return DISTANCE_MEDIUM;
} else {
return DISTANCE_SHORT;
}
break;
}
return 0; // shouldn't happen
}
uint32_t gesture_calculate_edge(Monitor *m, double x0, double y0, double x1,
double y1) {
uint32_t horizontal = EDGE_NONE;
uint32_t vertical = EDGE_NONE;
if (x0 <= config.touch_edge_size_left) {
horizontal = EDGE_LEFT;
} else if (x0 >= m->m.width - config.touch_edge_size_right) {
horizontal = EDGE_RIGHT;
} else if (x1 <= config.touch_edge_size_left) {
horizontal = EDGE_LEFT;
} else if (x1 >= m->m.width - config.touch_edge_size_right) {
horizontal = EDGE_RIGHT;
}
if (y0 <= config.touch_edge_size_top) {
vertical = EDGE_TOP;
} else if (y0 >= m->m.height - config.touch_edge_size_bottom) {
vertical = EDGE_BOTTOM;
} else if (y1 <= config.touch_edge_size_top) {
vertical = EDGE_TOP;
} else if (y1 >= m->m.height - config.touch_edge_size_bottom) {
vertical = EDGE_BOTTOM;
}
if (horizontal == EDGE_LEFT && vertical == EDGE_TOP) {
return CORNER_TOP_LEFT;
} else if (horizontal == EDGE_RIGHT && vertical == EDGE_TOP) {
return CORNER_TOP_RIGHT;
} else if (horizontal == EDGE_LEFT && vertical == EDGE_BOTTOM) {
return CORNER_BOTTOM_LEFT;
} else if (horizontal == EDGE_RIGHT && vertical == EDGE_BOTTOM) {
return CORNER_BOTTOM_RIGHT;
} else if (horizontal != EDGE_NONE) {
return horizontal;
} else {
return vertical;
}
}
int32_t gesture_execute(int32_t nfingers, uint32_t swipe, uint32_t edge,
uint32_t distance) {
int32_t i;
int32_t handled = 0;
wlr_log(WLR_DEBUG, "f:%d s:%d e:%d d:%d", nfingers, swipe, edge, distance);
TouchGestureBinding *g;
for (i = 0; i < config.touch_gesture_bindings_count; i++) {
g = &config.touch_gesture_bindings[i];
if (swipe == g->swipe && nfingers == g->fingers_count &&
distance >= g->distance &&
(g->edge == EDGE_ANY || edge == g->edge ||
((edge == CORNER_TOP_LEFT || edge == CORNER_TOP_RIGHT) &&
g->edge == EDGE_TOP) ||
((edge == CORNER_BOTTOM_LEFT || edge == CORNER_BOTTOM_RIGHT) &&
g->edge == EDGE_BOTTOM) ||
((edge == CORNER_TOP_LEFT || edge == CORNER_BOTTOM_LEFT) &&
g->edge == EDGE_LEFT) ||
((edge == CORNER_TOP_RIGHT || edge == CORNER_BOTTOM_RIGHT) &&
g->edge == EDGE_RIGHT)) &&
g->func) {
g->func(&g->arg);
handled = 1;
}
}
return handled;
}
void gesture_consume(TouchGroup *tg, TouchPoint *t) {
if (t->consumed_by_gesture)
return;
struct timespec now;
struct wlr_touch_cancel_event *event =
ecalloc(1, sizeof(struct wlr_touch_cancel_event));
clock_gettime(CLOCK_MONOTONIC_RAW, &now);
event->touch_id = t->touch_id;
event->touch = tg->touch;
event->time_msec = now.tv_sec * 1000 + now.tv_nsec / 1000000;
wlr_log(WLR_DEBUG, "gesture_consume id: %d", t->touch_id);
t->consumed_by_gesture = true;
handle_touchcancel(event);
free(event);
}
void gesture_touch_down(TouchGroup *tg, TouchPoint *t, double x, double y) {
wlr_log(WLR_DEBUG, "touch_down id: %d", t->touch_id);
t->start_x = x;
t->start_y = y;
t->end_x = x;
t->end_y = y;
if (wl_list_empty(&tg->touch_points))
clock_gettime(CLOCK_MONOTONIC_RAW, &tg->time_down);
}
void gesture_touch_motion(TouchGroup *tg, TouchPoint *t, double x, double y) {
t->end_x = x;
t->end_y = y;
}
void gesture_touch_up(TouchGroup *tg, TouchPoint *t) {
struct timespec now;
wlr_log(WLR_DEBUG, "touch_up id: %d", t->touch_id);
wlr_log(WLR_DEBUG, "len: %d", wl_list_length(&tg->touch_points));
clock_gettime(CLOCK_MONOTONIC_RAW, &now);
uint32_t swipe =
gesture_calculate_swipe(t->start_x, t->start_y, t->end_x, t->end_y);
if (swipe == TOUCH_SWIPE_NONE) {
goto cleanup;
}
if (tg->touch_points_pending_swipe == 0) {
tg->pending_swipe = swipe;
}
if (tg->pending_swipe != swipe) {
goto cleanup;
}
tg->touch_points_pending_swipe++;
// All fingers up - check if within millisecond limit, exec, & reset
// (we are the last finger)
if (wl_list_length(&tg->touch_points) == 1) {
uint32_t edge = gesture_calculate_edge(tg->m, t->start_x, t->start_y,
t->end_x, t->end_y);
uint32_t distance = gesture_calculate_distance(
tg->m, t->start_x, t->start_y, t->end_x, t->end_y, swipe);
if (config.touch_timeoutms >
((now.tv_sec - tg->time_down.tv_sec) * 1000 +
(now.tv_nsec - tg->time_down.tv_nsec) / 1000000)) {
if (gesture_execute(tg->touch_points_pending_swipe,
tg->pending_swipe, edge, distance))
gesture_consume(tg, t);
tg->touch_points_pending_swipe = 0;
}
return;
}
cleanup:
if (wl_list_length(&tg->touch_points) == 1)
tg->touch_points_pending_swipe = 0;
}

View file

@ -149,6 +149,32 @@ enum { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT };
enum { VERTICAL, HORIZONTAL };
enum { SWIPE_UP, SWIPE_DOWN, SWIPE_LEFT, SWIPE_RIGHT };
enum {
TOUCH_SWIPE_UP,
TOUCH_SWIPE_DOWN,
TOUCH_SWIPE_RIGHT,
TOUCH_SWIPE_LEFT,
TOUCH_SWIPE_UP_RIGHT,
TOUCH_SWIPE_UP_LEFT,
TOUCH_SWIPE_DOWN_LEFT,
TOUCH_SWIPE_DOWN_RIGHT,
TOUCH_SWIPE_NONE
};
enum {
EDGE_ANY,
EDGE_NONE,
EDGE_LEFT,
EDGE_RIGHT,
EDGE_TOP,
EDGE_BOTTOM,
CORNER_TOP_LEFT,
CORNER_TOP_RIGHT,
CORNER_BOTTOM_LEFT,
CORNER_BOTTOM_RIGHT,
};
enum { DISTANCE_ANY, DISTANCE_SHORT, DISTANCE_MEDIUM, DISTANCE_LONG };
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
enum { XDGShell, LayerShell, X11 }; /* client types */
enum { AxisUp, AxisDown, AxisLeft, AxisRight }; // 滚轮滚动的方向
@ -455,12 +481,17 @@ typedef struct {
typedef struct {
struct wl_list link;
int32_t touch_id;
double start_x, start_y, end_x, end_y;
bool consumed_by_gesture;
} TouchPoint;
typedef struct TouchGroup {
struct wl_list link;
struct wlr_touch *touch;
struct wl_list touch_points;
struct timespec time_down;
uint32_t pending_swipe;
uint32_t touch_points_pending_swipe;
Monitor *m;
} TouchGroup;
@ -700,6 +731,7 @@ static void touchup(struct wl_listener *listener, void *data);
static void touchframe(struct wl_listener *listener, void *data);
static void touchmotion(struct wl_listener *listener, void *data);
static void touchcancel(struct wl_listener *listener, void *data);
static void handle_touchcancel(struct wlr_touch_cancel_event *event);
static void unlocksession(struct wl_listener *listener, void *data);
static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
@ -1034,6 +1066,7 @@ static struct wl_event_source *sync_keymap;
#include "animation/layer.h"
#include "animation/tag.h"
#include "dispatch/bind_define.h"
#include "dispatch/gesture.h"
#include "ext-protocol/all.h"
#include "fetch/fetch.h"
#include "layout/arrange.h"
@ -5886,10 +5919,8 @@ void touchdown(struct wl_listener *listener, void *data) {
double dx, dy;
struct wlr_surface *surface;
Client *c = NULL;
Monitor *m;
t->touch_id = event->touch_id;
wl_list_insert(&tg->touch_points, &t->link);
Monitor *m = NULL;
Monitor *m_iter;
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
@ -5899,8 +5930,8 @@ void touchdown(struct wl_listener *listener, void *data) {
// Map the input to the appropriate output, to ensure that rotation is
// handled.
wl_list_for_each(m, &mons, link) {
if (m == NULL || m->wlr_output == NULL) {
wl_list_for_each(m_iter, &mons, link) {
if (m_iter == NULL || m_iter->wlr_output == NULL) {
continue;
}
if (event->touch->output_name != NULL &&
@ -5909,12 +5940,23 @@ void touchdown(struct wl_listener *listener, void *data) {
}
wlr_cursor_map_input_to_output(cursor, &event->touch->base,
m->wlr_output);
m_iter->wlr_output);
m = m_iter;
break;
}
/* ensure touch group has a monitor */
if (!tg->m)
tg->m = m; // TODO: properly handle output_name = null, instead of
// falling back to last monitor in the list;
wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x,
event->y, &lx, &ly);
t->touch_id = event->touch_id;
gesture_touch_down(tg, t, lx, ly);
wl_list_insert(&tg->touch_points, &t->link);
/* Find the client under the pointer and send the event along. */
xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
if (surface != NULL && wlr_surface_accepts_touch(surface, seat)) {
@ -5942,7 +5984,7 @@ void touchdown(struct wl_listener *listener, void *data) {
.time_msec = event->time_msec,
.button = BTN_LEFT,
.state = WL_POINTER_BUTTON_STATE_PRESSED};
buttonpress(listener, &button_event);
buttonpress(NULL, &button_event);
}
}
@ -5960,6 +6002,15 @@ void touchup(struct wl_listener *listener, void *data) {
}
if (!t) // invalid or cancelled
return;
gesture_touch_up(tg, t);
if (t->consumed_by_gesture) {
wl_list_remove(&t->link);
free(t);
return;
}
wl_list_remove(&t->link);
free(t);
@ -5970,7 +6021,7 @@ void touchup(struct wl_listener *listener, void *data) {
.time_msec = event->time_msec,
.button = BTN_LEFT,
.state = WL_POINTER_BUTTON_STATE_RELEASED};
buttonpress(listener, &button_event);
buttonpress(NULL, &button_event);
emulating_pointer_from_touch = false;
}
@ -6017,10 +6068,13 @@ void touchmotion(struct wl_listener *listener, void *data) {
if (!t) // invalid or cancelled
return;
wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x,
event->y, &lx, &ly);
gesture_touch_motion(tg, t, lx, ly);
if (emulating_pointer_from_touch) {
if (emulated_pointer_touch_id == event->touch_id) {
wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base,
event->x, event->y, &lx, &ly);
dx = lx - cursor->x;
dy = ly - cursor->y;
motionnotify(event->time_msec, &event->touch->base, dx, dy, dx, dy);
@ -6034,8 +6088,6 @@ void touchmotion(struct wl_listener *listener, void *data) {
return;
}
wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x,
event->y, &lx, &ly);
surface = p->surface;
if (surface && surface->data) {
tree = surface->data;
@ -6066,9 +6118,6 @@ void touchcancel(struct wl_listener *listener, void *data) {
TouchGroup *tg = event->touch->data;
TouchPoint *t = NULL;
TouchPoint *t_iter;
struct wlr_touch_point *p = NULL;
struct wl_client *client = NULL;
struct wlr_seat_client *seat_client = NULL;
wl_list_for_each(t_iter, &tg->touch_points, link) {
if (t_iter->touch_id == event->touch_id) {
@ -6082,6 +6131,17 @@ void touchcancel(struct wl_listener *listener, void *data) {
wl_list_remove(&t->link);
free(t);
if (wl_list_length(&tg->touch_points) == 0)
tg->touch_points_pending_swipe = 0;
handle_touchcancel(event);
}
void handle_touchcancel(struct wlr_touch_cancel_event *event) {
struct wlr_touch_point *p = NULL;
struct wl_client *client = NULL;
struct wlr_seat_client *seat_client = NULL;
if (emulating_pointer_from_touch) {
if (emulated_pointer_touch_id == event->touch_id) {
struct wlr_pointer_button_event button_event = {
@ -6089,7 +6149,7 @@ void touchcancel(struct wl_listener *listener, void *data) {
.time_msec = event->time_msec,
.button = BTN_LEFT,
.state = WL_POINTER_BUTTON_STATE_RELEASED};
buttonpress(listener, &button_event);
buttonpress(NULL, &button_event);
emulating_pointer_from_touch = false;
}