mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-16 22:05:21 -05:00
parent
4a73828911
commit
d2fcb5343f
12 changed files with 364 additions and 22 deletions
|
|
@ -55,8 +55,10 @@
|
|||
release, to foot.
|
||||
* Support for the new `cursor-shape-v1` Wayland protocol, i.e. server
|
||||
side cursor shapes ([#1379][1379]).
|
||||
* Support for touchscreen input ([#517][517]).
|
||||
|
||||
[1379]: https://codeberg.org/dnkl/foot/issues/1379
|
||||
[517]: https://codeberg.org/dnkl/foot/issues/517
|
||||
|
||||
|
||||
### Changed
|
||||
|
|
|
|||
12
README.md
12
README.md
|
|
@ -22,6 +22,7 @@ The fast, lightweight and minimalistic Wayland terminal emulator.
|
|||
1. [Normal mode](#normal-mode)
|
||||
1. [Scrollback search](#scrollback-search)
|
||||
1. [Mouse](#mouse)
|
||||
1. [Touchscreen](#touchscreen)
|
||||
1. [Server (daemon) mode](#server-daemon-mode)
|
||||
1. [URLs](#urls)
|
||||
1. [Shell integration](#shell-integration)
|
||||
|
|
@ -246,6 +247,17 @@ These are the default shortcuts. See `man foot.ini` and the example
|
|||
: Scroll up/down in history
|
||||
|
||||
|
||||
### Touchscreen
|
||||
|
||||
<kbd>tap</kbd>
|
||||
: Emulates mouse left button click.
|
||||
|
||||
<kbd>drag</kbd>
|
||||
: Scrolls up/down in history.
|
||||
: Holding for a while before dragging (time delay can be configured)
|
||||
emulates mouse dragging with left button held.
|
||||
|
||||
|
||||
## Server (daemon) mode
|
||||
|
||||
When run normally, **foot** is a single-window application; if you
|
||||
|
|
|
|||
20
config.c
20
config.c
|
|
@ -2475,6 +2475,20 @@ parse_section_tweak(struct context *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_section_touch(struct context *ctx) {
|
||||
struct config *conf = ctx->conf;
|
||||
const char *key = ctx->key;
|
||||
|
||||
if (strcmp(key, "long-press-delay") == 0)
|
||||
return value_to_uint32(ctx, 10, &conf->touch.long_press_delay);
|
||||
|
||||
else {
|
||||
LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_key_value(char *kv, const char **section, const char **key, const char **value)
|
||||
{
|
||||
|
|
@ -2554,6 +2568,7 @@ enum section {
|
|||
SECTION_TEXT_BINDINGS,
|
||||
SECTION_ENVIRONMENT,
|
||||
SECTION_TWEAK,
|
||||
SECTION_TOUCH,
|
||||
SECTION_COUNT,
|
||||
};
|
||||
|
||||
|
|
@ -2579,6 +2594,7 @@ static const struct {
|
|||
[SECTION_TEXT_BINDINGS] = {&parse_section_text_bindings, "text-bindings"},
|
||||
[SECTION_ENVIRONMENT] = {&parse_section_environment, "environment"},
|
||||
[SECTION_TWEAK] = {&parse_section_tweak, "tweak"},
|
||||
[SECTION_TOUCH] = {&parse_section_touch, "touch"},
|
||||
};
|
||||
|
||||
static_assert(ALEN(section_info) == SECTION_COUNT, "section info array size mismatch");
|
||||
|
|
@ -3026,6 +3042,10 @@ config_load(struct config *conf, const char *conf_path,
|
|||
.sixel = true,
|
||||
},
|
||||
|
||||
.touch = {
|
||||
.long_press_delay = 400,
|
||||
},
|
||||
|
||||
.env_vars = tll_init(),
|
||||
#if defined(UTMP_DEFAULT_HELPER_PATH)
|
||||
.utmp_helper_path = ((strlen(UTMP_DEFAULT_HELPER_PATH) > 0 &&
|
||||
|
|
|
|||
4
config.h
4
config.h
|
|
@ -347,6 +347,10 @@ struct config {
|
|||
bool sixel;
|
||||
} tweak;
|
||||
|
||||
struct {
|
||||
uint32_t long_press_delay;
|
||||
} touch;
|
||||
|
||||
user_notifications_t notifications;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -283,6 +283,18 @@ default) available; see *foot.ini*(5).
|
|||
*wheel*
|
||||
Scroll up/down in history
|
||||
|
||||
## TOUCHSCREEN
|
||||
|
||||
*tap*
|
||||
Emulates mouse left button click.
|
||||
|
||||
*drag*
|
||||
Scrolls up/down in history.
|
||||
|
||||
Holding for a while before dragging (time delay can be configured)
|
||||
emulates mouse dragging with left button held.
|
||||
|
||||
|
||||
# FONT FORMAT
|
||||
|
||||
The font is specified in FontConfig syntax. That is, a colon-separated
|
||||
|
|
|
|||
|
|
@ -535,6 +535,14 @@ applications can change these at runtime.
|
|||
|
||||
Default: _yes_.
|
||||
|
||||
# SECTION: touch
|
||||
|
||||
*long-press-delay*
|
||||
Number of milliseconds to distinguish between a short press and
|
||||
a long press on the touchscreen.
|
||||
|
||||
Default: _400_.
|
||||
|
||||
# SECTION: colors
|
||||
|
||||
This section controls the 16 ANSI colors, the default foreground and
|
||||
|
|
|
|||
3
foot.ini
3
foot.ini
|
|
@ -70,6 +70,9 @@
|
|||
# hide-when-typing=no
|
||||
# alternate-scroll-mode=yes
|
||||
|
||||
[touch]
|
||||
# long-press-delay=400
|
||||
|
||||
[colors]
|
||||
# alpha=1.0
|
||||
# background=002b36
|
||||
|
|
|
|||
266
input.c
266
input.c
|
|
@ -1721,6 +1721,36 @@ xcursor_for_csd_border(struct terminal *term, int x, int y)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mouse_button_state_reset(struct seat *seat)
|
||||
{
|
||||
tll_free(seat->mouse.buttons);
|
||||
seat->mouse.count = 0;
|
||||
seat->mouse.last_released_button = 0;
|
||||
memset(&seat->mouse.last_time, 0, sizeof(seat->mouse.last_time));
|
||||
}
|
||||
|
||||
static void
|
||||
mouse_coord_pixel_to_cell(struct seat *seat, const struct terminal *term,
|
||||
int x, int y)
|
||||
{
|
||||
/*
|
||||
* Translate x,y pixel coordinate to a cell coordinate, or -1
|
||||
* if the cursor is outside the grid. I.e. if it is inside the
|
||||
* margins.
|
||||
*/
|
||||
|
||||
if (x < term->margins.left || x >= term->width - term->margins.right)
|
||||
seat->mouse.col = -1;
|
||||
else
|
||||
seat->mouse.col = (x - term->margins.left) / term->cell_width;
|
||||
|
||||
if (y < term->margins.top || y >= term->height - term->margins.bottom)
|
||||
seat->mouse.row = -1;
|
||||
else
|
||||
seat->mouse.row = (y - term->margins.top) / term->cell_height;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t serial, struct wl_surface *surface,
|
||||
|
|
@ -1733,6 +1763,24 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
|
|||
}
|
||||
|
||||
struct seat *seat = data;
|
||||
|
||||
if (seat->wl_touch != NULL) {
|
||||
switch (seat->touch.state) {
|
||||
case TOUCH_STATE_IDLE:
|
||||
mouse_button_state_reset(seat);
|
||||
seat->touch.state = TOUCH_STATE_INHIBITED;
|
||||
break;
|
||||
|
||||
case TOUCH_STATE_INHIBITED:
|
||||
break;
|
||||
|
||||
case TOUCH_STATE_HELD:
|
||||
case TOUCH_STATE_DRAGGING:
|
||||
case TOUCH_STATE_SCROLLING:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct wl_window *win = wl_surface_get_user_data(surface);
|
||||
struct terminal *term = win->term;
|
||||
|
||||
|
|
@ -1759,22 +1807,7 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
|
|||
|
||||
switch (term->active_surface) {
|
||||
case TERM_SURF_GRID: {
|
||||
/*
|
||||
* Translate x,y pixel coordinate to a cell coordinate, or -1
|
||||
* if the cursor is outside the grid. I.e. if it is inside the
|
||||
* margins.
|
||||
*/
|
||||
|
||||
if (x < term->margins.left || x >= term->width - term->margins.right)
|
||||
seat->mouse.col = -1;
|
||||
else
|
||||
seat->mouse.col = (x - term->margins.left) / term->cell_width;
|
||||
|
||||
if (y < term->margins.top || y >= term->height - term->margins.bottom)
|
||||
seat->mouse.row = -1;
|
||||
else
|
||||
seat->mouse.row = (y - term->margins.top) / term->cell_height;
|
||||
|
||||
mouse_coord_pixel_to_cell(seat, term, x, y);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1802,6 +1835,14 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
|
|||
uint32_t serial, struct wl_surface *surface)
|
||||
{
|
||||
struct seat *seat = data;
|
||||
|
||||
if (seat->wl_touch != NULL) {
|
||||
if (seat->touch.state != TOUCH_STATE_INHIBITED) {
|
||||
return;
|
||||
}
|
||||
seat->touch.state = TOUCH_STATE_IDLE;
|
||||
}
|
||||
|
||||
struct terminal *old_moused = seat->mouse_focus;
|
||||
|
||||
LOG_DBG(
|
||||
|
|
@ -1824,10 +1865,7 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
|
|||
/* Reset mouse state */
|
||||
seat->mouse.x = seat->mouse.y = 0;
|
||||
seat->mouse.col = seat->mouse.row = 0;
|
||||
tll_free(seat->mouse.buttons);
|
||||
seat->mouse.count = 0;
|
||||
seat->mouse.last_released_button = 0;
|
||||
memset(&seat->mouse.last_time, 0, sizeof(seat->mouse.last_time));
|
||||
mouse_button_state_reset(seat);
|
||||
for (size_t i = 0; i < ALEN(seat->mouse.aggregated); i++)
|
||||
seat->mouse.aggregated[i] = 0.0;
|
||||
seat->mouse.have_discrete = false;
|
||||
|
|
@ -1879,6 +1917,11 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
|
|||
uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
|
||||
{
|
||||
struct seat *seat = data;
|
||||
|
||||
/* Touch-emulated pointer events have wl_pointer == NULL. */
|
||||
if (wl_pointer != NULL && seat->touch.state != TOUCH_STATE_INHIBITED)
|
||||
return;
|
||||
|
||||
struct wayland *wayl = seat->wayl;
|
||||
struct terminal *term = seat->mouse_focus;
|
||||
|
||||
|
|
@ -2102,6 +2145,11 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
|||
xassert(serial != 0);
|
||||
|
||||
struct seat *seat = data;
|
||||
|
||||
/* Touch-emulated pointer events have wl_pointer == NULL. */
|
||||
if (wl_pointer != NULL && seat->touch.state != TOUCH_STATE_INHIBITED)
|
||||
return;
|
||||
|
||||
struct wayland *wayl = seat->wayl;
|
||||
struct terminal *term = seat->mouse_focus;
|
||||
|
||||
|
|
@ -2559,6 +2607,9 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
|
|||
{
|
||||
struct seat *seat = data;
|
||||
|
||||
if (seat->touch.state != TOUCH_STATE_INHIBITED)
|
||||
return;
|
||||
|
||||
if (seat->mouse.have_discrete)
|
||||
return;
|
||||
|
||||
|
|
@ -2588,6 +2639,10 @@ wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
|
|||
uint32_t axis, int32_t discrete)
|
||||
{
|
||||
struct seat *seat = data;
|
||||
|
||||
if (seat->touch.state != TOUCH_STATE_INHIBITED)
|
||||
return;
|
||||
|
||||
seat->mouse.have_discrete = true;
|
||||
|
||||
int amount = discrete;
|
||||
|
|
@ -2604,6 +2659,10 @@ static void
|
|||
wl_pointer_frame(void *data, struct wl_pointer *wl_pointer)
|
||||
{
|
||||
struct seat *seat = data;
|
||||
|
||||
if (seat->touch.state != TOUCH_STATE_INHIBITED)
|
||||
return;
|
||||
|
||||
seat->mouse.have_discrete = false;
|
||||
}
|
||||
|
||||
|
|
@ -2619,6 +2678,9 @@ wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
|
|||
{
|
||||
struct seat *seat = data;
|
||||
|
||||
if (seat->touch.state != TOUCH_STATE_INHIBITED)
|
||||
return;
|
||||
|
||||
xassert(axis < ALEN(seat->mouse.aggregated));
|
||||
seat->mouse.aggregated[axis] = 0.;
|
||||
}
|
||||
|
|
@ -2634,3 +2696,167 @@ const struct wl_pointer_listener pointer_listener = {
|
|||
.axis_stop = wl_pointer_axis_stop,
|
||||
.axis_discrete = wl_pointer_axis_discrete,
|
||||
};
|
||||
|
||||
static bool
|
||||
touch_to_scroll(struct seat *seat, struct terminal *term,
|
||||
wl_fixed_t surface_x, wl_fixed_t surface_y)
|
||||
{
|
||||
bool coord_updated = false;
|
||||
|
||||
int y = wl_fixed_to_int(surface_y) * term->scale;
|
||||
int rows = (y - seat->mouse.y) / term->cell_height;
|
||||
if (rows != 0) {
|
||||
mouse_scroll(seat, -rows, WL_POINTER_AXIS_VERTICAL_SCROLL);
|
||||
seat->mouse.y += rows * term->cell_height;
|
||||
coord_updated = true;
|
||||
}
|
||||
|
||||
int x = wl_fixed_to_int(surface_x) * term->scale;
|
||||
int cols = (x - seat->mouse.x) / term->cell_width;
|
||||
if (cols != 0) {
|
||||
mouse_scroll(seat, -cols, WL_POINTER_AXIS_HORIZONTAL_SCROLL);
|
||||
seat->mouse.x += cols * term->cell_width;
|
||||
coord_updated = true;
|
||||
}
|
||||
|
||||
return coord_updated;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial,
|
||||
uint32_t time, struct wl_surface *surface, int32_t id,
|
||||
wl_fixed_t surface_x, wl_fixed_t surface_y)
|
||||
{
|
||||
struct seat *seat = data;
|
||||
|
||||
if (seat->touch.state != TOUCH_STATE_IDLE)
|
||||
return;
|
||||
|
||||
struct wl_window *win = wl_surface_get_user_data(surface);
|
||||
struct terminal *term = win->term;
|
||||
|
||||
term->active_surface = term_surface_kind(term, surface);
|
||||
if (term->active_surface != TERM_SURF_GRID)
|
||||
return;
|
||||
|
||||
LOG_DBG("touch_down: touch=%p, x=%d, y=%d", (void *)wl_touch,
|
||||
wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y));
|
||||
|
||||
int x = wl_fixed_to_int(surface_x) * term->scale;
|
||||
int y = wl_fixed_to_int(surface_y) * term->scale;
|
||||
|
||||
seat->mouse.x = x;
|
||||
seat->mouse.y = y;
|
||||
mouse_coord_pixel_to_cell(seat, term, x, y);
|
||||
|
||||
seat->touch.state = TOUCH_STATE_HELD;
|
||||
seat->touch.serial = serial;
|
||||
seat->touch.time = time + term->conf->touch.long_press_delay;
|
||||
seat->touch.surface = surface;
|
||||
seat->touch.id = id;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial,
|
||||
uint32_t time, int32_t id)
|
||||
{
|
||||
struct seat *seat = data;
|
||||
|
||||
if (seat->touch.state <= TOUCH_STATE_IDLE || id != seat->touch.id)
|
||||
return;
|
||||
|
||||
LOG_DBG("touch_up: touch=%p", (void *)wl_touch);
|
||||
|
||||
struct wl_window *win = wl_surface_get_user_data(seat->touch.surface);
|
||||
struct terminal *term = win->term;
|
||||
|
||||
seat->mouse_focus = term;
|
||||
|
||||
switch (seat->touch.state) {
|
||||
case TOUCH_STATE_HELD:
|
||||
wl_pointer_button(seat, NULL, seat->touch.serial, time, BTN_LEFT,
|
||||
WL_POINTER_BUTTON_STATE_PRESSED);
|
||||
/* fallthrough */
|
||||
case TOUCH_STATE_DRAGGING:
|
||||
wl_pointer_button(seat, NULL, serial, time, BTN_LEFT,
|
||||
WL_POINTER_BUTTON_STATE_RELEASED);
|
||||
/* fallthrough */
|
||||
case TOUCH_STATE_SCROLLING:
|
||||
seat->touch.state = TOUCH_STATE_IDLE;
|
||||
break;
|
||||
|
||||
case TOUCH_STATE_INHIBITED:
|
||||
case TOUCH_STATE_IDLE:
|
||||
BUG("Bad touch state: %d", seat->touch.state);
|
||||
break;
|
||||
}
|
||||
|
||||
seat->mouse_focus = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_touch_motion(void *data, struct wl_touch *wl_touch, uint32_t time,
|
||||
int32_t id, wl_fixed_t surface_x, wl_fixed_t surface_y)
|
||||
{
|
||||
struct seat *seat = data;
|
||||
if (seat->touch.state <= TOUCH_STATE_IDLE || id != seat->touch.id)
|
||||
return;
|
||||
|
||||
LOG_DBG("touch_motion: touch=%p, x=%d, y=%d", (void *)wl_touch,
|
||||
wl_fixed_to_int(surface_x), wl_fixed_to_int(surface_y));
|
||||
|
||||
struct wl_window *win = wl_surface_get_user_data(seat->touch.surface);
|
||||
struct terminal *term = win->term;
|
||||
|
||||
seat->mouse_focus = term;
|
||||
|
||||
switch (seat->touch.state) {
|
||||
case TOUCH_STATE_HELD:
|
||||
if (time <= seat->touch.time) {
|
||||
if (touch_to_scroll(seat, term, surface_x, surface_y))
|
||||
seat->touch.state = TOUCH_STATE_SCROLLING;
|
||||
break;
|
||||
} else {
|
||||
wl_pointer_button(seat, NULL, seat->touch.serial, time, BTN_LEFT,
|
||||
WL_POINTER_BUTTON_STATE_PRESSED);
|
||||
seat->touch.state = TOUCH_STATE_DRAGGING;
|
||||
/* fallthrough */
|
||||
}
|
||||
case TOUCH_STATE_DRAGGING:
|
||||
wl_pointer_motion(seat, NULL, time, surface_x, surface_y);
|
||||
break;
|
||||
case TOUCH_STATE_SCROLLING:
|
||||
touch_to_scroll(seat, term, surface_x, surface_y);
|
||||
break;
|
||||
|
||||
case TOUCH_STATE_INHIBITED:
|
||||
case TOUCH_STATE_IDLE:
|
||||
BUG("Bad touch state: %d", seat->touch.state);
|
||||
break;
|
||||
}
|
||||
|
||||
seat->mouse_focus = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_touch_frame(void *data, struct wl_touch *wl_touch)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wl_touch_cancel(void *data, struct wl_touch *wl_touch)
|
||||
{
|
||||
struct seat *seat = data;
|
||||
if (seat->touch.state == TOUCH_STATE_INHIBITED)
|
||||
return;
|
||||
|
||||
seat->touch.state = TOUCH_STATE_IDLE;
|
||||
}
|
||||
|
||||
const struct wl_touch_listener touch_listener = {
|
||||
.down = wl_touch_down,
|
||||
.up = wl_touch_up,
|
||||
.motion = wl_touch_motion,
|
||||
.frame = wl_touch_frame,
|
||||
.cancel = wl_touch_cancel,
|
||||
};
|
||||
|
|
|
|||
1
input.h
1
input.h
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
extern const struct wl_keyboard_listener keyboard_listener;
|
||||
extern const struct wl_pointer_listener pointer_listener;
|
||||
extern const struct wl_touch_listener touch_listener;
|
||||
|
||||
void input_repeat(struct seat *seat, uint32_t key);
|
||||
|
||||
|
|
|
|||
|
|
@ -662,6 +662,21 @@ test_section_mouse(void)
|
|||
config_free(&conf);
|
||||
}
|
||||
|
||||
static void
|
||||
test_section_touch(void)
|
||||
{
|
||||
struct config conf = {0};
|
||||
struct context ctx = {
|
||||
.conf = &conf, .section = "touch", .path = "unittest"};
|
||||
|
||||
test_invalid_key(&ctx, &parse_section_touch, "invalid-key");
|
||||
|
||||
test_uint32(&ctx, &parse_section_touch, "long-press-delay",
|
||||
&conf.touch.long_press_delay);
|
||||
|
||||
config_free(&conf);
|
||||
}
|
||||
|
||||
static void
|
||||
test_section_colors(void)
|
||||
{
|
||||
|
|
@ -1347,6 +1362,7 @@ main(int argc, const char *const *argv)
|
|||
test_section_url();
|
||||
test_section_cursor();
|
||||
test_section_mouse();
|
||||
test_section_touch();
|
||||
test_section_colors();
|
||||
test_section_csd();
|
||||
test_section_key_bindings();
|
||||
|
|
|
|||
23
wayland.c
23
wayland.c
|
|
@ -222,6 +222,8 @@ seat_destroy(struct seat *seat)
|
|||
wl_keyboard_release(seat->wl_keyboard);
|
||||
if (seat->wl_pointer != NULL)
|
||||
wl_pointer_release(seat->wl_pointer);
|
||||
if (seat->wl_touch != NULL)
|
||||
wl_touch_release(seat->wl_touch);
|
||||
|
||||
#if defined(FOOT_IME_ENABLED) && FOOT_IME_ENABLED
|
||||
if (seat->wl_text_input != NULL)
|
||||
|
|
@ -284,9 +286,10 @@ seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
|||
struct seat *seat = data;
|
||||
xassert(seat->wl_seat == wl_seat);
|
||||
|
||||
LOG_DBG("%s: keyboard=%s, pointer=%s", seat->name,
|
||||
LOG_DBG("%s: keyboard=%s, pointer=%s, touch=%s", seat->name,
|
||||
(caps & WL_SEAT_CAPABILITY_KEYBOARD) ? "yes" : "no",
|
||||
(caps & WL_SEAT_CAPABILITY_POINTER) ? "yes" : "no");
|
||||
(caps & WL_SEAT_CAPABILITY_POINTER) ? "yes" : "no",
|
||||
(caps & WL_SEAT_CAPABILITY_TOUCH) ? "yes" : "no");
|
||||
|
||||
if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
|
||||
if (seat->wl_keyboard == NULL) {
|
||||
|
|
@ -359,6 +362,22 @@ seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
|||
seat->pointer.cursor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (caps & WL_SEAT_CAPABILITY_TOUCH) {
|
||||
if (seat->wl_touch == NULL) {
|
||||
seat->wl_touch = wl_seat_get_touch(wl_seat);
|
||||
wl_touch_add_listener(seat->wl_touch, &touch_listener, seat);
|
||||
|
||||
seat->touch.state = TOUCH_STATE_IDLE;
|
||||
}
|
||||
} else {
|
||||
if (seat->wl_touch != NULL) {
|
||||
wl_touch_release(seat->wl_touch);
|
||||
seat->wl_touch = NULL;
|
||||
}
|
||||
|
||||
seat->touch.state = TOUCH_STATE_INHIBITED;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
19
wayland.h
19
wayland.h
|
|
@ -47,6 +47,14 @@ enum data_offer_mime_type {
|
|||
DATA_OFFER_MIME_TEXT_UTF8_STRING,
|
||||
};
|
||||
|
||||
enum touch_state {
|
||||
TOUCH_STATE_INHIBITED = -1,
|
||||
TOUCH_STATE_IDLE,
|
||||
TOUCH_STATE_HELD,
|
||||
TOUCH_STATE_DRAGGING,
|
||||
TOUCH_STATE_SCROLLING,
|
||||
};
|
||||
|
||||
struct wayl_surface {
|
||||
struct wl_surface *surf;
|
||||
#if defined(HAVE_FRACTIONAL_SCALE)
|
||||
|
|
@ -165,6 +173,17 @@ struct seat {
|
|||
bool xcursor_pending;
|
||||
} pointer;
|
||||
|
||||
/* Touch state */
|
||||
struct wl_touch *wl_touch;
|
||||
struct {
|
||||
enum touch_state state;
|
||||
|
||||
uint32_t serial;
|
||||
uint32_t time;
|
||||
struct wl_surface *surface;
|
||||
int32_t id;
|
||||
} touch;
|
||||
|
||||
struct {
|
||||
int x;
|
||||
int y;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue