Merge branch 'multi-seat'

Closes #32
This commit is contained in:
Daniel Eklöf 2020-07-11 08:30:47 +02:00
commit ed0cb06b48
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
15 changed files with 895 additions and 709 deletions

View file

@ -22,6 +22,7 @@
* **blink** option to `footrc`; a boolean that lets you control
whether the cursor should blink or not by default. Note that
applications can override this.
* Multi-seat support
### Changed

View file

@ -46,6 +46,7 @@ The fast, lightweight and minimalistic Wayland terminal emulator.
* Scrollback search
* Color emoji support
* Server/daemon mode (one master process, many windows)
* Multi-seat
* [Synchronized Updates](https://gitlab.freedesktop.org/terminal-wg/specifications/-/merge_requests/2) support
* [Sixel image support](https://en.wikipedia.org/wiki/Sixel)

454
input.c
View file

@ -33,8 +33,8 @@
#include "vt.h"
static void
execute_binding(struct terminal *term, enum bind_action_normal action,
uint32_t serial)
execute_binding(struct seat *seat, struct terminal *term,
enum bind_action_normal action, uint32_t serial)
{
switch (action) {
case BIND_ACTION_NONE:
@ -49,16 +49,16 @@ execute_binding(struct terminal *term, enum bind_action_normal action,
break;
case BIND_ACTION_CLIPBOARD_COPY:
selection_to_clipboard(term, serial);
selection_to_clipboard(seat, term, serial);
break;
case BIND_ACTION_CLIPBOARD_PASTE:
selection_from_clipboard(term, serial);
selection_from_clipboard(seat, term, serial);
term_reset_view(term);
break;
case BIND_ACTION_PRIMARY_PASTE:
selection_from_primary(term);
selection_from_primary(seat, term);
break;
case BIND_ACTION_SEARCH_START:
@ -206,57 +206,58 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
LOG_DBG("keyboard_keymap: keyboard=%p (format=%u, size=%u)",
wl_keyboard, format, size);
struct wayland *wayl = data;
struct seat *seat = data;
struct wayland *wayl = seat->wayl;
char *map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
if (wayl->kbd.xkb_compose_state != NULL) {
xkb_compose_state_unref(wayl->kbd.xkb_compose_state);
wayl->kbd.xkb_compose_state = NULL;
if (seat->kbd.xkb_compose_state != NULL) {
xkb_compose_state_unref(seat->kbd.xkb_compose_state);
seat->kbd.xkb_compose_state = NULL;
}
if (wayl->kbd.xkb_compose_table != NULL) {
xkb_compose_table_unref(wayl->kbd.xkb_compose_table);
wayl->kbd.xkb_compose_table = NULL;
if (seat->kbd.xkb_compose_table != NULL) {
xkb_compose_table_unref(seat->kbd.xkb_compose_table);
seat->kbd.xkb_compose_table = NULL;
}
if (wayl->kbd.xkb_keymap != NULL) {
xkb_keymap_unref(wayl->kbd.xkb_keymap);
wayl->kbd.xkb_keymap = NULL;
if (seat->kbd.xkb_keymap != NULL) {
xkb_keymap_unref(seat->kbd.xkb_keymap);
seat->kbd.xkb_keymap = NULL;
}
if (wayl->kbd.xkb_state != NULL) {
xkb_state_unref(wayl->kbd.xkb_state);
wayl->kbd.xkb_state = NULL;
if (seat->kbd.xkb_state != NULL) {
xkb_state_unref(seat->kbd.xkb_state);
seat->kbd.xkb_state = NULL;
}
if (wayl->kbd.xkb != NULL) {
xkb_context_unref(wayl->kbd.xkb);
wayl->kbd.xkb = NULL;
if (seat->kbd.xkb != NULL) {
xkb_context_unref(seat->kbd.xkb);
seat->kbd.xkb = NULL;
}
tll_foreach(wayl->kbd.bindings.key, it)
tll_foreach(seat->kbd.bindings.key, it)
tll_free(it->item.bind.key_codes);
tll_free(wayl->kbd.bindings.key);
tll_free(seat->kbd.bindings.key);
tll_foreach(wayl->kbd.bindings.search, it)
tll_foreach(seat->kbd.bindings.search, it)
tll_free(it->item.bind.key_codes);
tll_free(wayl->kbd.bindings.search);
tll_free(seat->kbd.bindings.search);
wayl->kbd.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
wayl->kbd.xkb_keymap = xkb_keymap_new_from_string(
wayl->kbd.xkb, map_str, XKB_KEYMAP_FORMAT_TEXT_V1,
seat->kbd.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
seat->kbd.xkb_keymap = xkb_keymap_new_from_string(
seat->kbd.xkb, map_str, XKB_KEYMAP_FORMAT_TEXT_V1,
XKB_KEYMAP_COMPILE_NO_FLAGS);
/* TODO: initialize in enter? */
wayl->kbd.xkb_state = xkb_state_new(wayl->kbd.xkb_keymap);
seat->kbd.xkb_state = xkb_state_new(seat->kbd.xkb_keymap);
wayl->kbd.mod_shift = xkb_keymap_mod_get_index(wayl->kbd.xkb_keymap, "Shift");
wayl->kbd.mod_alt = xkb_keymap_mod_get_index(wayl->kbd.xkb_keymap, "Mod1") ;
wayl->kbd.mod_ctrl = xkb_keymap_mod_get_index(wayl->kbd.xkb_keymap, "Control");
wayl->kbd.mod_meta = xkb_keymap_mod_get_index(wayl->kbd.xkb_keymap, "Mod4");
seat->kbd.mod_shift = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Shift");
seat->kbd.mod_alt = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Mod1") ;
seat->kbd.mod_ctrl = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Control");
seat->kbd.mod_meta = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Mod4");
/* Compose (dead keys) */
wayl->kbd.xkb_compose_table = xkb_compose_table_new_from_locale(
wayl->kbd.xkb, setlocale(LC_CTYPE, NULL), XKB_COMPOSE_COMPILE_NO_FLAGS);
wayl->kbd.xkb_compose_state = xkb_compose_state_new(
wayl->kbd.xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
seat->kbd.xkb_compose_table = xkb_compose_table_new_from_locale(
seat->kbd.xkb, setlocale(LC_CTYPE, NULL), XKB_COMPOSE_COMPILE_NO_FLAGS);
seat->kbd.xkb_compose_state = xkb_compose_state_new(
seat->kbd.xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
munmap(map_str, size);
close(fd);
@ -264,11 +265,11 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
for (enum bind_action_normal i = 0; i < BIND_ACTION_COUNT; i++) {
key_binding_list_t bindings = tll_init();
input_parse_key_binding(
wayl->kbd.xkb_keymap, wayl->conf->bindings.key[i], &bindings);
seat->kbd.xkb_keymap, wayl->conf->bindings.key[i], &bindings);
tll_foreach(bindings, it) {
tll_push_back(
wayl->kbd.bindings.key,
seat->kbd.bindings.key,
((struct key_binding_normal){.bind = it->item, .action = i}));
}
@ -278,11 +279,11 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
for (enum bind_action_search i = 0; i < BIND_ACTION_SEARCH_COUNT; i++) {
key_binding_list_t bindings = tll_init();
input_parse_key_binding(
wayl->kbd.xkb_keymap, wayl->conf->bindings.search[i], &bindings);
seat->kbd.xkb_keymap, wayl->conf->bindings.search[i], &bindings);
tll_foreach(bindings, it) {
tll_push_back(
wayl->kbd.bindings.search,
seat->kbd.bindings.search,
((struct key_binding_search){.bind = it->item, .action = i}));
}
@ -296,28 +297,27 @@ keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
{
assert(surface != NULL);
struct wayland *wayl = data;
struct seat *seat = data;
struct wl_window *win = wl_surface_get_user_data(surface);
struct terminal *term = win->term;
LOG_DBG("keyboard_enter: keyboard=%p, serial=%u, surface=%p",
wl_keyboard, serial, surface);
wayl->kbd_focus = term;
wayl->input_serial = serial;
term_kbd_focus_in(wayl->kbd_focus);
term_kbd_focus_in(term);
seat->kbd_focus = term;
seat->kbd.serial = serial;
}
static bool
start_repeater(struct wayland *wayl, uint32_t key)
start_repeater(struct seat *seat, uint32_t key)
{
if (wayl->kbd.repeat.dont_re_repeat)
if (seat->kbd.repeat.dont_re_repeat)
return true;
struct itimerspec t = {
.it_value = {.tv_sec = 0, .tv_nsec = wayl->kbd.repeat.delay * 1000000},
.it_interval = {.tv_sec = 0, .tv_nsec = 1000000000 / wayl->kbd.repeat.rate},
.it_value = {.tv_sec = 0, .tv_nsec = seat->kbd.repeat.delay * 1000000},
.it_interval = {.tv_sec = 0, .tv_nsec = 1000000000 / seat->kbd.repeat.rate},
};
if (t.it_value.tv_nsec >= 1000000000) {
@ -328,23 +328,23 @@ start_repeater(struct wayland *wayl, uint32_t key)
t.it_interval.tv_sec += t.it_interval.tv_nsec / 1000000000;
t.it_interval.tv_nsec %= 1000000000;
}
if (timerfd_settime(wayl->kbd.repeat.fd, 0, &t, NULL) < 0) {
LOG_ERRNO("failed to arm keyboard repeat timer");
if (timerfd_settime(seat->kbd.repeat.fd, 0, &t, NULL) < 0) {
LOG_ERRNO("%s: failed to arm keyboard repeat timer", seat->name);
return false;
}
wayl->kbd.repeat.key = key;
seat->kbd.repeat.key = key;
return true;
}
static bool
stop_repeater(struct wayland *wayl, uint32_t key)
stop_repeater(struct seat *seat, uint32_t key)
{
if (key != -1 && key != wayl->kbd.repeat.key)
if (key != -1 && key != seat->kbd.repeat.key)
return true;
if (timerfd_settime(wayl->kbd.repeat.fd, 0, &(struct itimerspec){}, NULL) < 0) {
LOG_ERRNO("failed to disarm keyboard repeat timer");
if (timerfd_settime(seat->kbd.repeat.fd, 0, &(struct itimerspec){}, NULL) < 0) {
LOG_ERRNO("%s: failed to disarm keyboard repeat timer", seat->name);
return false;
}
@ -355,26 +355,26 @@ static void
keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
struct wl_surface *surface)
{
struct wayland *wayl = data;
struct seat *seat = data;
LOG_DBG("keyboard_leave: keyboard=%p, serial=%u, surface=%p",
wl_keyboard, serial, surface);
assert(
wayl->kbd_focus == NULL ||
seat->kbd_focus == NULL ||
surface == NULL || /* Seen on Sway 1.2 */
((const struct wl_window *)wl_surface_get_user_data(surface))->term == wayl->kbd_focus
((const struct wl_window *)wl_surface_get_user_data(surface))->term == seat->kbd_focus
);
struct terminal *old_focused = wayl->kbd_focus;
wayl->kbd_focus = NULL;
struct terminal *old_focused = seat->kbd_focus;
seat->kbd_focus = NULL;
stop_repeater(wayl, -1);
wayl->kbd.shift = false;;
wayl->kbd.alt = false;;
wayl->kbd.ctrl = false;;
wayl->kbd.meta = false;;
xkb_compose_state_reset(wayl->kbd.xkb_compose_state);
stop_repeater(seat, -1);
seat->kbd.shift = false;
seat->kbd.alt = false;
seat->kbd.ctrl = false;
seat->kbd.meta = false;
xkb_compose_state_reset(seat->kbd.xkb_compose_state);
if (old_focused != NULL)
term_kbd_focus_out(old_focused);
@ -508,24 +508,24 @@ static void
keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
uint32_t time, uint32_t key, uint32_t state)
{
struct wayland *wayl = data;
struct terminal *term = wayl->kbd_focus;
struct seat *seat = data;
struct terminal *term = seat->kbd_focus;
assert(term != NULL);
const xkb_mod_mask_t ctrl = 1 << wayl->kbd.mod_ctrl;
const xkb_mod_mask_t alt = 1 << wayl->kbd.mod_alt;
const xkb_mod_mask_t shift = 1 << wayl->kbd.mod_shift;
const xkb_mod_mask_t meta = 1 << wayl->kbd.mod_meta;
const xkb_mod_mask_t ctrl = 1 << seat->kbd.mod_ctrl;
const xkb_mod_mask_t alt = 1 << seat->kbd.mod_alt;
const xkb_mod_mask_t shift = 1 << seat->kbd.mod_shift;
const xkb_mod_mask_t meta = 1 << seat->kbd.mod_meta;
if (state == XKB_KEY_UP) {
stop_repeater(wayl, key);
stop_repeater(seat, key);
return;
}
key += 8;
bool should_repeat = xkb_keymap_key_repeats(wayl->kbd.xkb_keymap, key);
xkb_keysym_t sym = xkb_state_key_get_one_sym(wayl->kbd.xkb_state, key);
bool should_repeat = xkb_keymap_key_repeats(seat->kbd.xkb_keymap, key);
xkb_keysym_t sym = xkb_state_key_get_one_sym(seat->kbd.xkb_state, key);
#if 0
char foo[100];
@ -533,9 +533,9 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
LOG_INFO("%s", foo);
#endif
xkb_compose_state_feed(wayl->kbd.xkb_compose_state, sym);
xkb_compose_state_feed(seat->kbd.xkb_compose_state, sym);
enum xkb_compose_status compose_status = xkb_compose_state_get_status(
wayl->kbd.xkb_compose_state);
seat->kbd.xkb_compose_state);
if (compose_status == XKB_COMPOSE_COMPOSING) {
/* TODO: goto maybe_repeat? */
@ -543,23 +543,23 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
}
xkb_mod_mask_t mods = xkb_state_serialize_mods(
wayl->kbd.xkb_state, XKB_STATE_MODS_DEPRESSED);
//xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods(wayl->kbd.xkb_state, key);
seat->kbd.xkb_state, XKB_STATE_MODS_DEPRESSED);
//xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods(seat->kbd.xkb_state, key);
xkb_mod_mask_t consumed = 0x0;
xkb_mod_mask_t significant = ctrl | alt | shift | meta;
xkb_mod_mask_t effective_mods = mods & ~consumed & significant;
if (term->is_searching) {
if (should_repeat)
start_repeater(wayl, key - 8);
search_input(term, key, sym, effective_mods, serial);
start_repeater(seat, key - 8);
search_input(seat, term, key, sym, effective_mods, serial);
return;
}
#if 0
for (size_t i = 0; i < 32; i++) {
if (mods & (1 << i)) {
LOG_INFO("%s", xkb_keymap_mod_get_name(wayl->kbd.xkb_keymap, i));
LOG_INFO("%s", xkb_keymap_mod_get_name(seat->kbd.xkb_keymap, i));
}
}
#endif
@ -573,20 +573,20 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
/*
* User configurable bindings
*/
tll_foreach(wayl->kbd.bindings.key, it) {
tll_foreach(seat->kbd.bindings.key, it) {
if (it->item.bind.mods != effective_mods)
continue;
/* Match symbol */
if (it->item.bind.sym == sym) {
execute_binding(term, it->item.action, serial);
execute_binding(seat, term, it->item.action, serial);
goto maybe_repeat;
}
/* Match raw key code */
tll_foreach(it->item.bind.key_codes, code) {
if (code->item == key) {
execute_binding(term, it->item.action, serial);
execute_binding(seat, term, it->item.action, serial);
goto maybe_repeat;
}
}
@ -597,10 +597,10 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
*/
enum modifier keymap_mods = MOD_NONE;
keymap_mods |= wayl->kbd.shift ? MOD_SHIFT : MOD_NONE;
keymap_mods |= wayl->kbd.alt ? MOD_ALT : MOD_NONE;
keymap_mods |= wayl->kbd.ctrl ? MOD_CTRL : MOD_NONE;
keymap_mods |= wayl->kbd.meta ? MOD_META : MOD_NONE;
keymap_mods |= seat->kbd.shift ? MOD_SHIFT : MOD_NONE;
keymap_mods |= seat->kbd.alt ? MOD_ALT : MOD_NONE;
keymap_mods |= seat->kbd.ctrl ? MOD_CTRL : MOD_NONE;
keymap_mods |= seat->kbd.meta ? MOD_META : MOD_NONE;
const struct key_data *keymap = keymap_lookup(term, sym, keymap_mods);
if (keymap != NULL) {
@ -620,13 +620,13 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
if (compose_status == XKB_COMPOSE_COMPOSED) {
count = xkb_compose_state_get_utf8(
wayl->kbd.xkb_compose_state, (char *)buf, sizeof(buf));
xkb_compose_state_reset(wayl->kbd.xkb_compose_state);
seat->kbd.xkb_compose_state, (char *)buf, sizeof(buf));
xkb_compose_state_reset(seat->kbd.xkb_compose_state);
} else if (compose_status == XKB_COMPOSE_CANCELLED) {
goto maybe_repeat;
} else {
count = xkb_state_key_get_utf8(
wayl->kbd.xkb_state, key, (char *)buf, sizeof(buf));
seat->kbd.xkb_state, key, (char *)buf, sizeof(buf));
}
if (count == 0)
@ -720,7 +720,7 @@ maybe_repeat:
term->wl->presentation_clock_id, &term->render.input_time);
if (should_repeat)
start_repeater(wayl, key - 8);
start_repeater(seat, key - 8);
}
@ -729,36 +729,36 @@ keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
uint32_t mods_depressed, uint32_t mods_latched,
uint32_t mods_locked, uint32_t group)
{
struct wayland *wayl = data;
struct seat *seat = data;
LOG_DBG("modifiers: depressed=0x%x, latched=0x%x, locked=0x%x, group=%u",
mods_depressed, mods_latched, mods_locked, group);
xkb_state_update_mask(
wayl->kbd.xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
seat->kbd.xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
/* Update state of modifiers we're interrested in for e.g mouse events */
wayl->kbd.shift = xkb_state_mod_index_is_active(
wayl->kbd.xkb_state, wayl->kbd.mod_shift, XKB_STATE_MODS_DEPRESSED);
wayl->kbd.alt = xkb_state_mod_index_is_active(
wayl->kbd.xkb_state, wayl->kbd.mod_alt, XKB_STATE_MODS_DEPRESSED);
wayl->kbd.ctrl = xkb_state_mod_index_is_active(
wayl->kbd.xkb_state, wayl->kbd.mod_ctrl, XKB_STATE_MODS_DEPRESSED);
wayl->kbd.meta = xkb_state_mod_index_is_active(
wayl->kbd.xkb_state, wayl->kbd.mod_meta, XKB_STATE_MODS_DEPRESSED);
seat->kbd.shift = xkb_state_mod_index_is_active(
seat->kbd.xkb_state, seat->kbd.mod_shift, XKB_STATE_MODS_DEPRESSED);
seat->kbd.alt = xkb_state_mod_index_is_active(
seat->kbd.xkb_state, seat->kbd.mod_alt, XKB_STATE_MODS_DEPRESSED);
seat->kbd.ctrl = xkb_state_mod_index_is_active(
seat->kbd.xkb_state, seat->kbd.mod_ctrl, XKB_STATE_MODS_DEPRESSED);
seat->kbd.meta = xkb_state_mod_index_is_active(
seat->kbd.xkb_state, seat->kbd.mod_meta, XKB_STATE_MODS_DEPRESSED);
if (wayl->kbd_focus && wayl->kbd_focus->active_surface == TERM_SURF_GRID)
term_xcursor_update(wayl->kbd_focus);
if (seat->kbd_focus && seat->kbd_focus->active_surface == TERM_SURF_GRID)
term_xcursor_update(seat->kbd_focus);
}
static void
keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
int32_t rate, int32_t delay)
{
struct wayland *wayl = data;
struct seat *seat = data;
LOG_DBG("keyboard repeat: rate=%d, delay=%d", rate, delay);
wayl->kbd.repeat.rate = rate;
wayl->kbd.repeat.delay = delay;
seat->kbd.repeat.rate = rate;
seat->kbd.repeat.delay = delay;
}
const struct wl_keyboard_listener keyboard_listener = {
@ -771,9 +771,9 @@ const struct wl_keyboard_listener keyboard_listener = {
};
void
input_repeat(struct wayland *wayl, uint32_t key)
input_repeat(struct seat *seat, uint32_t key)
{
keyboard_key(wayl, NULL, wayl->input_serial, 0, key, XKB_KEY_DOWN);
keyboard_key(seat, NULL, seat->kbd.serial, 0, key, XKB_KEY_DOWN);
}
static bool
@ -817,14 +817,14 @@ is_bottom_right(const struct terminal *term, int x, int y)
static const char *
xcursor_for_csd_border(struct terminal *term, int x, int y)
{
if (is_top_left(term, x, y)) return "top_left_corner";
else if (is_top_right(term, x, y)) return "top_right_corner";
else if (is_bottom_left(term, x, y)) return "bottom_left_corner";
else if (is_bottom_right(term, x, y)) return "bottom_right_corner";
else if (term->active_surface == TERM_SURF_BORDER_LEFT) return "left_side";
else if (term->active_surface == TERM_SURF_BORDER_RIGHT) return "right_side";
else if (term->active_surface == TERM_SURF_BORDER_TOP) return "top_side";
else if (term->active_surface == TERM_SURF_BORDER_BOTTOM) return"bottom_side";
if (is_top_left(term, x, y)) return XCURSOR_TOP_LEFT_CORNER;
else if (is_top_right(term, x, y)) return XCURSOR_TOP_RIGHT_CORNER;
else if (is_bottom_left(term, x, y)) return XCURSOR_BOTTOM_LEFT_CORNER;
else if (is_bottom_right(term, x, y)) return XCURSOR_BOTTOM_RIGHT_CORNER;
else if (term->active_surface == TERM_SURF_BORDER_LEFT) return XCURSOR_LEFT_SIDE;
else if (term->active_surface == TERM_SURF_BORDER_RIGHT) return XCURSOR_RIGHT_SIDE;
else if (term->active_surface == TERM_SURF_BORDER_TOP) return XCURSOR_TOP_SIDE;
else if (term->active_surface == TERM_SURF_BORDER_BOTTOM) return XCURSOR_BOTTOM_SIDE;
else {
assert(false);
return NULL;
@ -838,44 +838,46 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
{
assert(surface != NULL);
struct wayland *wayl = data;
struct seat *seat = data;
struct wl_window *win = wl_surface_get_user_data(surface);
struct terminal *term = win->term;
seat->pointer.serial = serial;
LOG_DBG("pointer-enter: pointer=%p, serial=%u, surface = %p, new-moused = %p",
wl_pointer, serial, surface, term);
wayl->mouse_focus = term;
/* Scale may have changed */
wayl_reload_xcursor_theme(seat, term->scale);
seat->mouse_focus = term;
int x = wl_fixed_to_int(surface_x) * term->scale;
int y = wl_fixed_to_int(surface_y) * term->scale;
switch ((term->active_surface = term_surface_kind(term, surface))) {
case TERM_SURF_GRID:
wayl->mouse.col = x / term->cell_width;
wayl->mouse.row = y / term->cell_height;
seat->mouse.col = x / term->cell_width;
seat->mouse.row = y / term->cell_height;
term_xcursor_update(term);
break;
case TERM_SURF_SEARCH:
case TERM_SURF_TITLE:
term->xcursor = "left_ptr";
render_xcursor_set(term);
render_xcursor_set(seat, term, XCURSOR_LEFT_PTR);
break;
case TERM_SURF_BORDER_LEFT:
case TERM_SURF_BORDER_RIGHT:
case TERM_SURF_BORDER_TOP:
case TERM_SURF_BORDER_BOTTOM:
term->xcursor = xcursor_for_csd_border(term, x, y);
render_xcursor_set(term);
render_xcursor_set(seat, term, xcursor_for_csd_border(term, x, y));
break;
case TERM_SURF_BUTTON_MINIMIZE:
case TERM_SURF_BUTTON_MAXIMIZE:
case TERM_SURF_BUTTON_CLOSE:
term->xcursor = "left_ptr";
render_xcursor_set(term);
render_xcursor_set(seat, term, XCURSOR_LEFT_PTR);
render_refresh_csd(term);
break;
@ -889,25 +891,25 @@ static void
wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *surface)
{
struct wayland *wayl = data;
struct terminal *old_moused = wayl->mouse_focus;
struct seat *seat = data;
struct terminal *old_moused = seat->mouse_focus;
LOG_DBG(
"pointer-leave: pointer=%p, serial=%u, surface = %p, old-moused = %p",
wl_pointer, serial, surface, old_moused);
if (wayl->pointer.xcursor_callback != NULL) {
if (seat->pointer.xcursor_callback != NULL) {
/* A cursor frame callback may never be called if the pointer leaves our surface */
wl_callback_destroy(wayl->pointer.xcursor_callback);
wayl->pointer.xcursor_callback = NULL;
wayl->pointer.pending_terminal = NULL;
wayl->pointer.xcursor = NULL;
wl_callback_destroy(seat->pointer.xcursor_callback);
seat->pointer.xcursor_callback = NULL;
seat->pointer.xcursor_pending = false;
seat->pointer.xcursor = NULL;
}
/* Reset mouse state */
memset(&wayl->mouse, 0, sizeof(wayl->mouse));
memset(&seat->mouse, 0, sizeof(seat->mouse));
wayl->mouse_focus = NULL;
seat->mouse_focus = NULL;
if (old_moused == NULL) {
LOG_WARN(
"compositor sent pointer_leave event without a pointer_enter "
@ -953,8 +955,9 @@ static void
wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
{
struct wayland *wayl = data;
struct terminal *term = wayl->mouse_focus;
struct seat *seat = data;
struct wayland *wayl = seat->wayl;
struct terminal *term = seat->mouse_focus;
struct wl_window *win = term->window;
LOG_DBG("pointer_motion: pointer=%p, x=%d, y=%d", wl_pointer,
@ -965,8 +968,8 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
int x = wl_fixed_to_int(surface_x) * term->scale;
int y = wl_fixed_to_int(surface_y) * term->scale;
wayl->mouse.x = x;
wayl->mouse.y = y;
seat->mouse.x = x;
seat->mouse.y = y;
switch (term->active_surface) {
case TERM_SURF_NONE:
@ -980,10 +983,10 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
/* We've started a 'move' timer, but user started dragging
* right away - abort the timer and initiate the actual move
* right away */
if (wayl->mouse.button == BTN_LEFT && win->csd.move_timeout_fd != -1) {
if (seat->mouse.button == BTN_LEFT && win->csd.move_timeout_fd != -1) {
fdm_del(wayl->fdm, win->csd.move_timeout_fd);
win->csd.move_timeout_fd = -1;
xdg_toplevel_move(win->xdg_toplevel, wayl->seat, win->csd.serial);
xdg_toplevel_move(win->xdg_toplevel, seat->wl_seat, win->csd.serial);
}
break;
@ -991,8 +994,7 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
case TERM_SURF_BORDER_RIGHT:
case TERM_SURF_BORDER_TOP:
case TERM_SURF_BORDER_BOTTOM:
term->xcursor = xcursor_for_csd_border(term, x, y);
render_xcursor_set(term);
render_xcursor_set(seat, term, xcursor_for_csd_border(term, x, y));
break;
case TERM_SURF_GRID: {
@ -1002,23 +1004,26 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
if (col < 0 || row < 0 || col >= term->cols || row >= term->rows)
return;
bool update_selection = wayl->mouse.button == BTN_LEFT;
bool update_selection = seat->mouse.button == BTN_LEFT;
bool update_selection_early = term->selection.end.row == -1;
if (update_selection && update_selection_early)
selection_update(term, col, row);
if (col == wayl->mouse.col && row == wayl->mouse.row)
if (col == seat->mouse.col && row == seat->mouse.row)
break;
wayl->mouse.col = col;
wayl->mouse.row = row;
seat->mouse.col = col;
seat->mouse.row = row;
if (update_selection && !update_selection_early)
selection_update(term, col, row);
term_mouse_motion(
term, wayl->mouse.button, wayl->mouse.row, wayl->mouse.col);
if (!term_mouse_grabbed(term, seat)) {
term_mouse_motion(
term, seat->mouse.button, seat->mouse.row, seat->mouse.col,
seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl);
}
break;
}
}
@ -1027,13 +1032,20 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
static bool
fdm_csd_move(struct fdm *fdm, int fd, int events, void *data)
{
struct wl_window *win = data;
struct wayland *wayl = win->term->wl;
struct seat *seat = data;
fdm_del(fdm, fd);
win->csd.move_timeout_fd = -1;
xdg_toplevel_move(win->xdg_toplevel, wayl->seat, win->csd.serial);
if (seat->mouse_focus == NULL) {
LOG_WARN(
"%s: CSD move timeout triggered, but seat's has no mouse focused terminal",
seat->name);
return true;
}
struct wl_window *win = seat->mouse_focus->window;
win->csd.move_timeout_fd = -1;
xdg_toplevel_move(win->xdg_toplevel, seat->wl_seat, win->csd.serial);
return true;
}
@ -1044,8 +1056,9 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
LOG_DBG("BUTTON: pointer=%p, serial=%u, button=%x, state=%u",
wl_pointer, serial, button, state);
struct wayland *wayl = data;
struct terminal *term = wayl->mouse_focus;
struct seat *seat = data;
struct wayland *wayl = seat->wayl;
struct terminal *term = seat->mouse_focus;
assert(term != NULL);
@ -1054,22 +1067,22 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
/* Time since last click */
struct timeval now, since_last;
gettimeofday(&now, NULL);
timersub(&now, &wayl->mouse.last_time, &since_last);
timersub(&now, &seat->mouse.last_time, &since_last);
/* Double- or triple click? */
if (button == wayl->mouse.last_button &&
if (button == seat->mouse.last_button &&
since_last.tv_sec == 0 &&
since_last.tv_usec <= 300 * 1000)
{
wayl->mouse.count++;
seat->mouse.count++;
} else
wayl->mouse.count = 1;
seat->mouse.count = 1;
wayl->mouse.button = button; /* For motion events */
wayl->mouse.last_button = button;
wayl->mouse.last_time = now;
seat->mouse.button = button; /* For motion events */
seat->mouse.last_button = button;
seat->mouse.last_time = now;
} else
wayl->mouse.button = 0; /* For motion events */
seat->mouse.button = 0; /* For motion events */
switch (term->active_surface) {
case TERM_SURF_TITLE:
@ -1078,7 +1091,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
struct wl_window *win = term->window;
/* Toggle maximized state on double-click */
if (button == BTN_LEFT && wayl->mouse.count == 2) {
if (button == BTN_LEFT && seat->mouse.count == 2) {
if (win->is_maximized)
xdg_toplevel_unset_maximized(win->xdg_toplevel);
else
@ -1093,7 +1106,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
if (fd >= 0 &&
timerfd_settime(fd, 0, &timeout, NULL) == 0 &&
fdm_add(wayl->fdm, fd, EPOLLIN, &fdm_csd_move, win))
fdm_add(wayl->fdm, fd, EPOLLIN, &fdm_csd_move, seat))
{
win->csd.move_timeout_fd = fd;
win->csd.serial = serial;
@ -1127,8 +1140,8 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) {
enum xdg_toplevel_resize_edge resize_type;
int x = wayl->mouse.x;
int y = wayl->mouse.y;
int x = seat->mouse.x;
int y = seat->mouse.y;
if (is_top_left(term, x, y))
resize_type = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
@ -1142,7 +1155,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
resize_type = map[term->active_surface];
xdg_toplevel_resize(
term->window->xdg_toplevel, term->wl->seat, serial, resize_type);
term->window->xdg_toplevel, seat->wl_seat, serial, resize_type);
}
return;
}
@ -1174,32 +1187,35 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
switch (state) {
case WL_POINTER_BUTTON_STATE_PRESSED: {
if (button == BTN_LEFT && wayl->mouse.count <= 3) {
if (button == BTN_LEFT && seat->mouse.count <= 3) {
selection_cancel(term);
if (selection_enabled(term)) {
switch (wayl->mouse.count) {
if (selection_enabled(term, seat)) {
switch (seat->mouse.count) {
case 1:
selection_start(
term, wayl->mouse.col, wayl->mouse.row,
wayl->kbd.ctrl ? SELECTION_BLOCK : SELECTION_NORMAL);
term, seat->mouse.col, seat->mouse.row,
seat->kbd.ctrl ? SELECTION_BLOCK : SELECTION_NORMAL);
break;
case 2:
selection_mark_word(term, wayl->mouse.col, wayl->mouse.row,
wayl->kbd.ctrl, serial);
selection_mark_word(
seat, term, seat->mouse.col, seat->mouse.row,
seat->kbd.ctrl, serial);
break;
case 3:
selection_mark_row(term, wayl->mouse.row, serial);
selection_mark_row(seat, term, seat->mouse.row, serial);
break;
}
}
}
else if (button == BTN_RIGHT && wayl->mouse.count == 1) {
if (selection_enabled(term))
selection_extend(term, wayl->mouse.col, wayl->mouse.row, serial);
else if (button == BTN_RIGHT && seat->mouse.count == 1) {
if (selection_enabled(term, seat)) {
selection_extend(
seat, term, seat->mouse.col, seat->mouse.row, serial);
}
}
else {
@ -1212,25 +1228,33 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
continue;
}
if (binding->count != wayl->mouse.count) {
if (binding->count != seat->mouse.count) {
/* Not correct click count */
continue;
}
execute_binding(term, binding->action, serial);
execute_binding(seat, term, binding->action, serial);
break;
}
}
term_mouse_down(term, button, wayl->mouse.row, wayl->mouse.col);
if (!term_mouse_grabbed(term, seat)) {
term_mouse_down(
term, button, seat->mouse.row, seat->mouse.col,
seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl);
}
break;
}
case WL_POINTER_BUTTON_STATE_RELEASED:
if (button == BTN_LEFT && term->selection.end.col != -1)
selection_finalize(term, serial);
selection_finalize(seat, term, serial);
term_mouse_up(term, button, wayl->mouse.row, wayl->mouse.col);
if (!term_mouse_grabbed(term, seat)) {
term_mouse_up(
term, button, seat->mouse.row, seat->mouse.col,
seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl);
}
break;
}
break;
@ -1244,9 +1268,9 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
}
static void
mouse_scroll(struct wayland *wayl, int amount)
mouse_scroll(struct seat *seat, int amount)
{
struct terminal *term = wayl->mouse_focus;
struct terminal *term = seat->mouse_focus;
assert(term != NULL);
int button = amount < 0 ? BTN_BACK : BTN_FORWARD;
@ -1268,20 +1292,26 @@ mouse_scroll(struct wayland *wayl, int amount)
static xkb_keycode_t key_arrow_down = 0;
if (key_arrow_up == 0) {
key_arrow_up = xkb_keymap_key_by_name(wayl->kbd.xkb_keymap, "UP");
key_arrow_down = xkb_keymap_key_by_name(wayl->kbd.xkb_keymap, "DOWN");
key_arrow_up = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "UP");
key_arrow_down = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "DOWN");
}
xkb_keycode_t key = button == BTN_BACK ? key_arrow_up : key_arrow_down;
for (int i = 0; i < amount; i++)
keyboard_key(wayl, NULL, wayl->input_serial, 0, key - 8, XKB_KEY_DOWN);
keyboard_key(wayl, NULL, wayl->input_serial, 0, key - 8, XKB_KEY_UP);
keyboard_key(seat, NULL, seat->kbd.serial, 0, key - 8, XKB_KEY_DOWN);
keyboard_key(seat, NULL, seat->kbd.serial, 0, key - 8, XKB_KEY_UP);
} else {
for (int i = 0; i < amount; i++)
term_mouse_down(term, button, wayl->mouse.row, wayl->mouse.col);
term_mouse_up(term, button, wayl->mouse.row, wayl->mouse.col);
if (!term_mouse_grabbed(term, seat)) {
for (int i = 0; i < amount; i++) {
term_mouse_down(
term, button, seat->mouse.row, seat->mouse.col,
seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl);
}
term_mouse_up(
term, button, seat->mouse.row, seat->mouse.col,
seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl);
}
scrollback(term, amount);
}
}
@ -1293,9 +1323,9 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
return;
struct wayland *wayl = data;
struct seat *seat = data;
if (wayl->mouse.have_discrete)
if (seat->mouse.have_discrete)
return;
/*
@ -1304,11 +1334,11 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
* Without this, very slow scrolling will never actually scroll
* anything.
*/
wayl->mouse.axis_aggregated += wl_fixed_to_double(value);
seat->mouse.axis_aggregated += wl_fixed_to_double(value);
if (fabs(wayl->mouse.axis_aggregated) >= 1.) {
mouse_scroll(wayl, round(wayl->mouse.axis_aggregated));
wayl->mouse.axis_aggregated = 0.;
if (fabs(seat->mouse.axis_aggregated) >= 1.) {
mouse_scroll(seat, round(seat->mouse.axis_aggregated));
seat->mouse.axis_aggregated = 0.;
}
}
@ -1319,16 +1349,16 @@ wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
return;
struct wayland *wayl = data;
wayl->mouse.have_discrete = true;
mouse_scroll(wayl, discrete);
struct seat *seat = data;
seat->mouse.have_discrete = true;
mouse_scroll(seat, discrete);
}
static void
wl_pointer_frame(void *data, struct wl_pointer *wl_pointer)
{
struct wayland *wayl = data;
wayl->mouse.have_discrete = false;
struct seat *seat = data;
seat->mouse.have_discrete = false;
}
static void
@ -1344,8 +1374,8 @@ wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
return;
struct wayland *wayl = data;
wayl->mouse.axis_aggregated = 0.;
struct seat *seat = data;
seat->mouse.axis_aggregated = 0.;
}
const struct wl_pointer_listener pointer_listener = {

View file

@ -8,7 +8,7 @@
extern const struct wl_keyboard_listener keyboard_listener;
extern const struct wl_pointer_listener pointer_listener;
void input_repeat(struct wayland *wayl, uint32_t key);
void input_repeat(struct seat *seat, uint32_t key);
bool input_parse_key_binding(struct xkb_keymap *keymap, const char *combos,
key_binding_list_t *bindings);

41
osc.c
View file

@ -52,15 +52,29 @@ osc_to_clipboard(struct terminal *term, const char *target,
}
}
/* Find a seat in which the terminal has focus */
struct seat *seat = NULL;
tll_foreach(term->wl->seats, it) {
if (it->item.kbd_focus == term) {
seat = &it->item;
break;
}
}
if (seat == NULL) {
LOG_WARN("OSC52: client tried to write to clipboard data while window was unfocused");
return;
}
if (to_clipboard) {
char *copy = strdup(decoded);
if (!text_to_clipboard(term, copy, term->wl->input_serial))
if (!text_to_clipboard(seat, term, copy, seat->kbd.serial))
free(copy);
}
if (to_primary) {
char *copy = strdup(decoded);
if (!text_to_primary(term, copy, term->wl->input_serial))
if (!text_to_primary(seat, term, copy, seat->kbd.serial))
free(copy);
}
@ -68,6 +82,7 @@ osc_to_clipboard(struct terminal *term, const char *target,
}
struct clip_context {
struct seat *seat;
struct terminal *term;
uint8_t buf[3];
int idx;
@ -151,23 +166,37 @@ osc_from_clipboard(struct terminal *term, const char *source)
if (src == 0)
return;
/* Find a seat in which the terminal has focus */
struct seat *seat = NULL;
tll_foreach(term->wl->seats, it) {
if (it->item.kbd_focus == term) {
seat = &it->item;
break;
}
}
if (seat == NULL) {
LOG_WARN("OSC52: client tried to read clipboard data while window was unfocused");
return;
}
term_to_slave(term, "\033]52;", 5);
term_to_slave(term, &src, 1);
term_to_slave(term, ";", 1);
struct clip_context *ctx = malloc(sizeof(*ctx));
*ctx = (struct clip_context) {.term = term};
*ctx = (struct clip_context) {.seat = seat, .term = term};
switch (src) {
case 'c':
text_from_clipboard(
term, term->wl->input_serial,
&from_clipboard_cb, &from_clipboard_done, ctx);
seat, term, &from_clipboard_cb, &from_clipboard_done, ctx);
break;
case 's':
case 'p':
text_from_primary(term, &from_clipboard_cb, &from_clipboard_done, ctx);
text_from_primary(
seat, term, &from_clipboard_cb, &from_clipboard_done, ctx);
break;
}
}

View file

@ -1941,62 +1941,60 @@ render_resize_force(struct terminal *term, int width, int height)
static void xcursor_callback(
void *data, struct wl_callback *wl_callback, uint32_t callback_data);
static const struct wl_callback_listener xcursor_listener = {
.done = &xcursor_callback,
};
static void
render_xcursor_update(struct wayland *wayl, const struct terminal *term)
render_xcursor_update(struct seat *seat)
{
/* If called from a frame callback, we may no longer have mouse focus */
if (wayl->mouse_focus != term)
if (!seat->mouse_focus)
return;
wayl->pointer.cursor = wl_cursor_theme_get_cursor(wayl->pointer.theme, term->xcursor);
if (wayl->pointer.cursor == NULL) {
LOG_ERR("%s: failed to load xcursor pointer '%s'",
wayl->pointer.theme_name, term->xcursor);
seat->pointer.cursor = wl_cursor_theme_get_cursor(
seat->pointer.theme, seat->pointer.xcursor);
if (seat->pointer.cursor == NULL) {
LOG_ERR("failed to load xcursor pointer '%s'", seat->pointer.xcursor);
return;
}
wayl->pointer.xcursor = term->xcursor;
const int scale = term->scale;
struct wl_cursor_image *image = wayl->pointer.cursor->images[0];
const int scale = seat->pointer.scale;
struct wl_cursor_image *image = seat->pointer.cursor->images[0];
wl_surface_attach(
wayl->pointer.surface, wl_cursor_image_get_buffer(image), 0, 0);
seat->pointer.surface, wl_cursor_image_get_buffer(image), 0, 0);
wl_pointer_set_cursor(
wayl->pointer.pointer, wayl->pointer.serial,
wayl->pointer.surface,
seat->wl_pointer, seat->pointer.serial,
seat->pointer.surface,
image->hotspot_x / scale, image->hotspot_y / scale);
wl_surface_damage_buffer(
wayl->pointer.surface, 0, 0, INT32_MAX, INT32_MAX);
seat->pointer.surface, 0, 0, INT32_MAX, INT32_MAX);
wl_surface_set_buffer_scale(wayl->pointer.surface, scale);
wl_surface_set_buffer_scale(seat->pointer.surface, scale);
assert(wayl->pointer.xcursor_callback == NULL);
wayl->pointer.xcursor_callback = wl_surface_frame(wayl->pointer.surface);
wl_callback_add_listener(wayl->pointer.xcursor_callback, &xcursor_listener, wayl);
assert(seat->pointer.xcursor_callback == NULL);
seat->pointer.xcursor_callback = wl_surface_frame(seat->pointer.surface);
wl_callback_add_listener(seat->pointer.xcursor_callback, &xcursor_listener, seat);
wl_surface_commit(wayl->pointer.surface);
wl_surface_commit(seat->pointer.surface);
}
static void
xcursor_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_data)
{
struct wayland *wayl = data;
struct seat *seat = data;
assert(wayl->pointer.xcursor_callback == wl_callback);
assert(seat->pointer.xcursor_callback == wl_callback);
wl_callback_destroy(wl_callback);
wayl->pointer.xcursor_callback = NULL;
seat->pointer.xcursor_callback = NULL;
if (wayl->pointer.pending_terminal != NULL) {
render_xcursor_update(wayl, wayl->pointer.pending_terminal);
wayl->pointer.pending_terminal = NULL;
if (seat->pointer.xcursor_pending) {
render_xcursor_update(seat);
seat->pointer.xcursor_pending = false;
}
}
@ -2061,12 +2059,14 @@ fdm_hook_refresh_pending_terminals(struct fdm *fdm, void *data)
}
}
if (wayl->pointer.pending_terminal != NULL) {
if (wayl->pointer.xcursor_callback == NULL) {
render_xcursor_update(wayl, wayl->pointer.pending_terminal);
wayl->pointer.pending_terminal = NULL;
} else {
/* Frame callback will call render_xcursor_update() */
tll_foreach(wayl->seats, it) {
if (it->item.pointer.xcursor_pending) {
if (it->item.pointer.xcursor_callback == NULL) {
render_xcursor_update(&it->item);
it->item.pointer.xcursor_pending = false;
} else {
/* Frame callback will call render_xcursor_update() */
}
}
}
}
@ -2098,28 +2098,26 @@ render_refresh_search(struct terminal *term)
}
bool
render_xcursor_set(struct terminal *term)
render_xcursor_set(struct seat *seat, struct terminal *term, const char *xcursor)
{
struct wayland *wayl = term->wl;
if (wayl->pointer.theme == NULL)
if (seat->pointer.theme == NULL)
return false;
if (wayl->mouse_focus == NULL) {
wayl->pointer.xcursor = NULL;
wayl->pointer.pending_terminal = NULL;
if (seat->mouse_focus == NULL) {
seat->pointer.xcursor = NULL;
return true;
}
if (wayl->mouse_focus != term) {
if (seat->mouse_focus != term) {
/* This terminal doesn't have mouse focus */
return true;
}
if (wayl->pointer.xcursor == term->xcursor)
if (seat->pointer.xcursor == xcursor)
return true;
/* FDM hook takes care of actual rendering */
wayl->pointer.pending_terminal = term;
seat->pointer.xcursor_pending = true;
seat->pointer.xcursor = xcursor;
return true;
}

View file

@ -16,7 +16,7 @@ void render_refresh(struct terminal *term);
void render_refresh_csd(struct terminal *term);
void render_refresh_search(struct terminal *term);
void render_refresh_title(struct terminal *term);
bool render_xcursor_set(struct terminal *term);
bool render_xcursor_set(struct seat *seat, struct terminal *term, const char *xcursor);
struct render_worker_context {
int my_id;

View file

@ -429,8 +429,10 @@ execute_binding(struct terminal *term, enum bind_action_search action,
return true;
case BIND_ACTION_SEARCH_COMMIT:
#if 0
selection_finalize(term, term->wl->input_serial);
search_cancel_keep_selection(term);
#endif
return true;
case BIND_ACTION_SEARCH_FIND_PREV:
@ -567,16 +569,16 @@ execute_binding(struct terminal *term, enum bind_action_search action,
}
void
search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym,
xkb_mod_mask_t mods, uint32_t serial)
search_input(struct seat *seat, struct terminal *term, uint32_t key,
xkb_keysym_t sym, xkb_mod_mask_t mods, uint32_t serial)
{
LOG_DBG("search: input: sym=%d/0x%x, mods=0x%08x", sym, sym, mods);
enum xkb_compose_status compose_status = xkb_compose_state_get_status(
term->wl->kbd.xkb_compose_state);
seat->kbd.xkb_compose_state);
/* Key bindings */
tll_foreach(term->wl->kbd.bindings.search, it) {
tll_foreach(seat->kbd.bindings.search, it) {
if (it->item.bind.mods != mods)
continue;
@ -602,13 +604,13 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym,
if (compose_status == XKB_COMPOSE_COMPOSED) {
count = xkb_compose_state_get_utf8(
term->wl->kbd.xkb_compose_state, (char *)buf, sizeof(buf));
xkb_compose_state_reset(term->wl->kbd.xkb_compose_state);
seat->kbd.xkb_compose_state, (char *)buf, sizeof(buf));
xkb_compose_state_reset(seat->kbd.xkb_compose_state);
} else if (compose_status == XKB_COMPOSE_CANCELLED) {
count = 0;
} else {
count = xkb_state_key_get_utf8(
term->wl->kbd.xkb_state, key, (char *)buf, sizeof(buf));
seat->kbd.xkb_state, key, (char *)buf, sizeof(buf));
}
const char *src = (const char *)buf;

View file

@ -5,5 +5,5 @@
void search_begin(struct terminal *term);
void search_cancel(struct terminal *term);
void search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym, xkb_mod_mask_t mods,
uint32_t serial);
void search_input(struct seat *seat, struct terminal *term, uint32_t key,
xkb_keysym_t sym, xkb_mod_mask_t mods, uint32_t serial);

View file

@ -21,11 +21,11 @@
#include "vt.h"
bool
selection_enabled(const struct terminal *term)
selection_enabled(const struct terminal *term, struct seat *seat)
{
return
term->mouse_tracking == MOUSE_NONE ||
term_mouse_grabbed(term) ||
term_mouse_grabbed(term, seat) ||
term->is_searching;
}
@ -591,7 +591,8 @@ selection_extend_block(struct terminal *term, int col, int row, uint32_t serial)
}
void
selection_extend(struct terminal *term, int col, int row, uint32_t serial)
selection_extend(struct seat *seat, struct terminal *term,
int col, int row, uint32_t serial)
{
if (term->selection.start.row < 0 || term->selection.end.row < 0) {
/* No existing selection */
@ -621,13 +622,13 @@ selection_extend(struct terminal *term, int col, int row, uint32_t serial)
break;
}
selection_to_primary(term, serial);
selection_to_primary(seat, term, serial);
}
static const struct zwp_primary_selection_source_v1_listener primary_selection_source_listener;
//static const struct zwp_primary_selection_source_v1_listener primary_selection_source_listener;
void
selection_finalize(struct terminal *term, uint32_t serial)
selection_finalize(struct seat *seat, struct terminal *term, uint32_t serial)
{
if (term->selection.start.row < 0 || term->selection.end.row < 0)
return;
@ -645,7 +646,7 @@ selection_finalize(struct terminal *term, uint32_t serial)
}
assert(term->selection.start.row <= term->selection.end.row);
selection_to_primary(term, serial);
selection_to_primary(seat, term, serial);
}
void
@ -668,8 +669,8 @@ selection_cancel(struct terminal *term)
}
void
selection_mark_word(struct terminal *term, int col, int row, bool spaces_only,
uint32_t serial)
selection_mark_word(struct seat *seat, struct terminal *term, int col, int row,
bool spaces_only, uint32_t serial)
{
selection_cancel(term);
@ -730,17 +731,19 @@ selection_mark_word(struct terminal *term, int col, int row, bool spaces_only,
selection_start(term, start.col, start.row, SELECTION_NORMAL);
selection_update(term, end.col, end.row);
selection_finalize(term, serial);
selection_finalize(seat, term, serial);
}
void
selection_mark_row(struct terminal *term, int row, uint32_t serial)
selection_mark_row(
struct seat *seat, struct terminal *term, int row, uint32_t serial)
{
selection_start(term, 0, row, SELECTION_NORMAL);
selection_update(term, term->cols - 1, row);
selection_finalize(term, serial);
selection_finalize(seat, term, serial);
}
static void
target(void *data, struct wl_data_source *wl_data_source, const char *mime_type)
{
@ -786,8 +789,8 @@ static void
send(void *data, struct wl_data_source *wl_data_source, const char *mime_type,
int32_t fd)
{
struct wayland *wayl = data;
const struct wl_clipboard *clipboard = &wayl->clipboard;
struct seat *seat = data;
const struct wl_clipboard *clipboard = &seat->clipboard;
assert(clipboard != NULL);
assert(clipboard->text != NULL);
@ -815,7 +818,7 @@ send(void *data, struct wl_data_source *wl_data_source, const char *mime_type,
.idx = async_idx,
};
if (fdm_add(wayl->fdm, fd, EPOLLOUT, &fdm_send, ctx))
if (fdm_add(seat->wayl->fdm, fd, EPOLLOUT, &fdm_send, ctx))
return;
free(ctx->data);
@ -839,8 +842,8 @@ send(void *data, struct wl_data_source *wl_data_source, const char *mime_type,
static void
cancelled(void *data, struct wl_data_source *wl_data_source)
{
struct wayland *wayl = data;
struct wl_clipboard *clipboard = &wayl->clipboard;
struct seat *seat = data;
struct wl_clipboard *clipboard = &seat->clipboard;
assert(clipboard->data_source == wl_data_source);
wl_data_source_destroy(clipboard->data_source);
@ -880,8 +883,8 @@ primary_send(void *data,
struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1,
const char *mime_type, int32_t fd)
{
struct wayland *wayl = data;
const struct wl_primary *primary = &wayl->primary;
struct seat *seat = data;
const struct wl_primary *primary = &seat->primary;
assert(primary != NULL);
assert(primary->text != NULL);
@ -907,7 +910,7 @@ primary_send(void *data,
.idx = async_idx,
};
if (fdm_add(wayl->fdm, fd, EPOLLOUT, &fdm_send, ctx))
if (fdm_add(seat->wayl->fdm, fd, EPOLLOUT, &fdm_send, ctx))
return;
free(ctx->data);
@ -932,8 +935,8 @@ static void
primary_cancelled(void *data,
struct zwp_primary_selection_source_v1 *zwp_primary_selection_source_v1)
{
struct wayland *wayl = data;
struct wl_primary *primary = &wayl->primary;
struct seat *seat = data;
struct wl_primary *primary = &seat->primary;
zwp_primary_selection_source_v1_destroy(primary->data_source);
primary->data_source = NULL;
@ -949,14 +952,14 @@ static const struct zwp_primary_selection_source_v1_listener primary_selection_s
};
bool
text_to_clipboard(struct terminal *term, char *text, uint32_t serial)
text_to_clipboard(struct seat *seat, struct terminal *term, char *text, uint32_t serial)
{
struct wl_clipboard *clipboard = &term->wl->clipboard;
struct wl_clipboard *clipboard = &seat->clipboard;
if (clipboard->data_source != NULL) {
/* Kill previous data source */
assert(clipboard->serial != 0);
wl_data_device_set_selection(term->wl->data_device, NULL, clipboard->serial);
wl_data_device_set_selection(seat->data_device, NULL, clipboard->serial);
wl_data_source_destroy(clipboard->data_source);
free(clipboard->text);
@ -976,8 +979,8 @@ text_to_clipboard(struct terminal *term, char *text, uint32_t serial)
/* Configure source */
wl_data_source_offer(clipboard->data_source, "text/plain;charset=utf-8");
wl_data_source_add_listener(clipboard->data_source, &data_source_listener, term->wl);
wl_data_device_set_selection(term->wl->data_device, clipboard->data_source, serial);
wl_data_source_add_listener(clipboard->data_source, &data_source_listener, seat);
wl_data_device_set_selection(seat->data_device, clipboard->data_source, serial);
/* Needed when sending the selection to other client */
assert(serial != 0);
@ -986,14 +989,14 @@ text_to_clipboard(struct terminal *term, char *text, uint32_t serial)
}
void
selection_to_clipboard(struct terminal *term, uint32_t serial)
selection_to_clipboard(struct seat *seat, struct terminal *term, uint32_t serial)
{
if (term->selection.start.row < 0 || term->selection.end.row < 0)
return;
/* Get selection as a string */
char *text = extract_selection(term);
if (!text_to_clipboard(term, text, serial))
if (!text_to_clipboard(seat, term, text, serial))
free(text);
}
@ -1004,6 +1007,7 @@ struct clipboard_receive {
void *user;
};
static bool
fdm_receive(struct fdm *fdm, int fd, int events, void *data)
{
@ -1083,11 +1087,11 @@ begin_receive_clipboard(struct terminal *term, int read_fd,
}
void
text_from_clipboard(struct terminal *term, uint32_t serial,
text_from_clipboard(struct seat *seat, struct terminal *term,
void (*cb)(const char *data, size_t size, void *user),
void (*done)(void *user), void *user)
{
struct wl_clipboard *clipboard = &term->wl->clipboard;
struct wl_clipboard *clipboard = &seat->clipboard;
if (clipboard->data_offer == NULL)
return done(user);
@ -1128,9 +1132,9 @@ from_clipboard_done(void *user)
}
void
selection_from_clipboard(struct terminal *term, uint32_t serial)
selection_from_clipboard(struct seat *seat, struct terminal *term, uint32_t serial)
{
struct wl_clipboard *clipboard = &term->wl->clipboard;
struct wl_clipboard *clipboard = &seat->clipboard;
if (clipboard->data_offer == NULL)
return;
@ -1138,24 +1142,24 @@ selection_from_clipboard(struct terminal *term, uint32_t serial)
term_to_slave(term, "\033[200~", 6);
text_from_clipboard(
term, serial, &from_clipboard_cb, &from_clipboard_done, term);
seat, term, &from_clipboard_cb, &from_clipboard_done, term);
}
bool
text_to_primary(struct terminal *term, char *text, uint32_t serial)
text_to_primary(struct seat *seat, struct terminal *term, char *text, uint32_t serial)
{
if (term->wl->primary_selection_device_manager == NULL)
return false;
struct wl_primary *primary = &term->wl->primary;
struct wl_primary *primary = &seat->primary;
/* TODO: somehow share code with the clipboard equivalent */
if (term->wl->primary.data_source != NULL) {
if (seat->primary.data_source != NULL) {
/* Kill previous data source */
assert(primary->serial != 0);
zwp_primary_selection_device_v1_set_selection(
term->wl->primary_selection_device, NULL, primary->serial);
seat->primary_selection_device, NULL, primary->serial);
zwp_primary_selection_source_v1_destroy(primary->data_source);
free(primary->text);
@ -1177,8 +1181,8 @@ text_to_primary(struct terminal *term, char *text, uint32_t serial)
/* Configure source */
zwp_primary_selection_source_v1_offer(primary->data_source, "text/plain;charset=utf-8");
zwp_primary_selection_source_v1_add_listener(primary->data_source, &primary_selection_source_listener, term->wl);
zwp_primary_selection_device_v1_set_selection(term->wl->primary_selection_device, primary->data_source, serial);
zwp_primary_selection_source_v1_add_listener(primary->data_source, &primary_selection_source_listener, seat);
zwp_primary_selection_device_v1_set_selection(seat->primary_selection_device, primary->data_source, serial);
/* Needed when sending the selection to other client */
primary->serial = serial;
@ -1186,27 +1190,27 @@ text_to_primary(struct terminal *term, char *text, uint32_t serial)
}
void
selection_to_primary(struct terminal *term, uint32_t serial)
selection_to_primary(struct seat *seat, struct terminal *term, uint32_t serial)
{
if (term->wl->primary_selection_device_manager == NULL)
return;
/* Get selection as a string */
char *text = extract_selection(term);
if (!text_to_primary(term, text, serial))
if (!text_to_primary(seat, term, text, serial))
free(text);
}
void
text_from_primary(
struct terminal *term,
struct seat *seat, struct terminal *term,
void (*cb)(const char *data, size_t size, void *user),
void (*done)(void *user), void *user)
{
if (term->wl->primary_selection_device_manager == NULL)
return done(user);
struct wl_primary *primary = &term->wl->primary;
struct wl_primary *primary = &seat->primary;
if (primary->data_offer == NULL)
return done(user);
@ -1231,19 +1235,19 @@ text_from_primary(
}
void
selection_from_primary(struct terminal *term)
selection_from_primary(struct seat *seat, struct terminal *term)
{
if (term->wl->primary_selection_device_manager == NULL)
return;
struct wl_clipboard *clipboard = &term->wl->clipboard;
struct wl_clipboard *clipboard = &seat->clipboard;
if (clipboard->data_offer == NULL)
return;
if (term->bracketed_paste)
term_to_slave(term, "\033[200~", 6);
text_from_primary(term, &from_clipboard_cb, &from_clipboard_done, term);
text_from_primary(seat, term, &from_clipboard_cb, &from_clipboard_done, term);
}
#if 0
@ -1305,8 +1309,8 @@ selection(void *data, struct wl_data_device *wl_data_device,
{
/* Selection offer from other client */
struct wayland *wayl = data;
struct wl_clipboard *clipboard = &wayl->clipboard;
struct seat *seat = data;
struct wl_clipboard *clipboard = &seat->clipboard;
if (clipboard->data_offer != NULL)
wl_data_offer_destroy(clipboard->data_offer);
@ -1354,8 +1358,8 @@ primary_selection(void *data,
{
/* Selection offer from other client, for primary */
struct wayland *wayl = data;
struct wl_primary *primary = &wayl->primary;
struct seat *seat = data;
struct wl_primary *primary = &seat->primary;
if (primary->data_offer != NULL)
zwp_primary_selection_offer_v1_destroy(primary->data_offer);

View file

@ -8,32 +8,41 @@
extern const struct wl_data_device_listener data_device_listener;
extern const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener;
bool selection_enabled(const struct terminal *term);
bool selection_enabled(const struct terminal *term, struct seat *seat);
void selection_start(
struct terminal *term, int col, int row, enum selection_kind kind);
void selection_update(struct terminal *term, int col, int row);
void selection_finalize(struct terminal *term, uint32_t serial);
void selection_finalize(
struct seat *seat, struct terminal *term, uint32_t serial);
void selection_dirty_cells(struct terminal *term);
void selection_cancel(struct terminal *term);
void selection_extend(struct terminal *term, int col, int row, uint32_t serial);
void selection_extend( struct seat *seat, struct terminal *term,
int col, int row, uint32_t serial);
bool selection_on_rows(const struct terminal *term, int start, int end);
void selection_view_up(struct terminal *term, int new_view);
void selection_view_down(struct terminal *term, int new_view);
void selection_mark_word(struct terminal *term, int col, int row,
bool spaces_only, uint32_t serial);
void selection_mark_row(struct terminal *term, int row, uint32_t serial);
void selection_mark_word(
struct seat *seat, struct terminal *term, int col, int row,
bool spaces_only, uint32_t serial);
void selection_mark_row(
struct seat *seat, struct terminal *term, int row, uint32_t serial);
void selection_to_clipboard(struct terminal *term, uint32_t serial);
void selection_from_clipboard(struct terminal *term, uint32_t serial);
void selection_to_primary(struct terminal *term, uint32_t serial);
void selection_from_primary(struct terminal *term);
void selection_to_clipboard(
struct seat *seat, struct terminal *term, uint32_t serial);
void selection_from_clipboard(
struct seat *seat, struct terminal *term, uint32_t serial);
void selection_to_primary(
struct seat *seat, struct terminal *term, uint32_t serial);
void selection_from_primary(struct seat *seat, struct terminal *term);
/* Copy text *to* primary/clipboard */
bool text_to_clipboard(struct terminal *term, char *text, uint32_t serial);
bool text_to_primary(struct terminal *term, char *text, uint32_t serial);
bool text_to_clipboard(
struct seat *seat, struct terminal *term, char *text, uint32_t serial);
bool text_to_primary(
struct seat *seat, struct terminal *term, char *text, uint32_t serial);
/*
* Copy text *from* primary/clipboard
@ -50,11 +59,11 @@ bool text_to_primary(struct terminal *term, char *text, uint32_t serial);
* point).
*/
void text_from_clipboard(
struct terminal *term, uint32_t serial,
struct seat *seat, struct terminal *term,
void (*cb)(const char *data, size_t size, void *user),
void (*done)(void *user), void *user);
void text_from_primary(
struct terminal *term,
struct seat *seat, struct terminal *term,
void (*cb)(const char *data, size_t size, void *user),
void (*dont)(void *user), void *user);

View file

@ -34,9 +34,17 @@
#define PTMX_TIMING 0
static const char *const XCURSOR_LEFT_PTR = "left_ptr";
static const char *const XCURSOR_TEXT = "text";
//static const char *const XCURSOR_HAND2 = "hand2";
const char *const XCURSOR_LEFT_PTR = "left_ptr";
const char *const XCURSOR_TEXT = "text";
//const char *const XCURSOR_HAND2 = "hand2";
const char *const XCURSOR_TOP_LEFT_CORNER = "top_left_corner";
const char *const XCURSOR_TOP_RIGHT_CORNER = "top_right_corner";
const char *const XCURSOR_BOTTOM_LEFT_CORNER = "bottom_left_corner";
const char *const XCURSOR_BOTTOM_RIGHT_CORNER = "bottom_right_corner";
const char *const XCURSOR_LEFT_SIDE = "left_side";
const char *const XCURSOR_RIGHT_SIDE = "right_side";
const char *const XCURSOR_TOP_SIDE = "top_side";
const char *const XCURSOR_BOTTOM_SIDE = "bottom_side";
bool
term_to_slave(struct terminal *term, const void *_data, size_t len)
@ -889,7 +897,6 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
.text = conf->cursor.color.text,
.cursor = conf->cursor.color.cursor,
},
.xcursor = "text",
.selection = {
.start = {-1, -1},
.end = {-1, -1},
@ -1037,13 +1044,12 @@ fdm_shutdown(struct fdm *fdm, int fd, int events, void *data)
* are deferred (for example, when a screen locker is active), and
* thus we can get here without having been unmapped.
*/
if (wayl->kbd_focus == term)
wayl->kbd_focus = NULL;
if (wayl->mouse_focus == term)
wayl->mouse_focus = NULL;
assert(wayl->kbd_focus != term);
assert(wayl->mouse_focus != term);
tll_foreach(wayl->seats, it) {
if (it->item.kbd_focus == term)
it->item.kbd_focus = NULL;
if (it->item.mouse_focus == term)
it->item.mouse_focus = NULL;
}
void (*cb)(void *, int) = term->shutdown_cb;
void *cb_data = term->shutdown_data;
@ -1711,7 +1717,7 @@ void
term_cursor_blink_enable(struct terminal *term)
{
term->cursor_blink.state = CURSOR_BLINK_ON;
term->cursor_blink.active = term->wl->kbd_focus == term
term->cursor_blink.active = term_has_kbd_focus(term)
? cursor_blink_start_timer(term) : true;
}
@ -1728,7 +1734,7 @@ term_cursor_blink_restart(struct terminal *term)
{
if (term->cursor_blink.active) {
term->cursor_blink.state = CURSOR_BLINK_ON;
term->cursor_blink.active = term->wl->kbd_focus == term
term->cursor_blink.active = term_has_kbd_focus(term)
? cursor_blink_start_timer(term) : true;
}
}
@ -1951,9 +1957,23 @@ term_visual_focus_out(struct terminal *term)
cursor_refresh(term);
}
bool
term_has_kbd_focus(struct terminal *term)
{
tll_foreach(term->wl->seats, it) {
if (it->item.kbd_focus == term)
return true;
}
return false;
}
void
term_kbd_focus_in(struct terminal *term)
{
if (term_has_kbd_focus(term))
return;
if (term->focus_events)
term_to_slave(term, "\033[I", 3);
}
@ -1961,6 +1981,9 @@ term_kbd_focus_in(struct terminal *term)
void
term_kbd_focus_out(struct terminal *term)
{
if (term_has_kbd_focus(term))
return;
if (term->focus_events)
term_to_slave(term, "\033[O", 3);
}
@ -2052,23 +2075,20 @@ report_mouse_motion(struct terminal *term, int encoded_button, int row, int col)
}
bool
term_mouse_grabbed(const struct terminal *term)
term_mouse_grabbed(const struct terminal *term, struct seat *seat)
{
/*
* Mouse is grabbed by us, regardless of whether mouse tracking has been enabled or not.
*/
return
term->wl->kbd_focus == term &&
term->wl->kbd.shift &&
!term->wl->kbd.alt && /*!term->wl->kbd.ctrl &&*/ !term->wl->kbd.meta;
return seat->kbd_focus == term &&
seat->kbd.shift &&
!seat->kbd.alt && /*!seat->kbd.ctrl &&*/ !seat->kbd.meta;
}
void
term_mouse_down(struct terminal *term, int button, int row, int col)
term_mouse_down(struct terminal *term, int button, int row, int col,
bool _shift, bool _alt, bool _ctrl)
{
if (term_mouse_grabbed(term))
return;
/* Map libevent button event code to X button number */
int xbutton = linux_mouse_button_to_x(button);
if (xbutton == -1)
@ -2079,10 +2099,10 @@ term_mouse_down(struct terminal *term, int button, int row, int col)
return;
bool has_focus = term->wl->kbd_focus == term;
bool shift = has_focus ? term->wl->kbd.shift : false;
bool alt = has_focus ? term->wl->kbd.alt : false;
bool ctrl = has_focus ? term->wl->kbd.ctrl : false;
bool has_focus = term_has_kbd_focus(term);
bool shift = has_focus ? _shift : false;
bool alt = has_focus ? _alt : false;
bool ctrl = has_focus ? _ctrl : false;
encoded += (shift ? 4 : 0) + (alt ? 8 : 0) + (ctrl ? 16 : 0);
@ -2104,11 +2124,9 @@ term_mouse_down(struct terminal *term, int button, int row, int col)
}
void
term_mouse_up(struct terminal *term, int button, int row, int col)
term_mouse_up(struct terminal *term, int button, int row, int col,
bool _shift, bool _alt, bool _ctrl)
{
if (term_mouse_grabbed(term))
return;
/* Map libevent button event code to X button number */
int xbutton = linux_mouse_button_to_x(button);
if (xbutton == -1)
@ -2123,10 +2141,10 @@ term_mouse_up(struct terminal *term, int button, int row, int col)
if (encoded == -1)
return;
bool has_focus = term->wl->kbd_focus == term;
bool shift = has_focus ? term->wl->kbd.shift : false;
bool alt = has_focus ? term->wl->kbd.alt : false;
bool ctrl = has_focus ? term->wl->kbd.ctrl : false;
bool has_focus = term_has_kbd_focus(term);
bool shift = has_focus ? _shift : false;
bool alt = has_focus ? _alt : false;
bool ctrl = has_focus ? _ctrl : false;
encoded += (shift ? 4 : 0) + (alt ? 8 : 0) + (ctrl ? 16 : 0);
@ -2148,11 +2166,9 @@ term_mouse_up(struct terminal *term, int button, int row, int col)
}
void
term_mouse_motion(struct terminal *term, int button, int row, int col)
term_mouse_motion(struct terminal *term, int button, int row, int col,
bool _shift, bool _alt, bool _ctrl)
{
if (term_mouse_grabbed(term))
return;
int encoded = 0;
if (button != 0) {
@ -2167,10 +2183,10 @@ term_mouse_motion(struct terminal *term, int button, int row, int col)
} else
encoded = 3; /* "released" */
bool has_focus = term->wl->kbd_focus == term;
bool shift = has_focus ? term->wl->kbd.shift : false;
bool alt = has_focus ? term->wl->kbd.alt : false;
bool ctrl = has_focus ? term->wl->kbd.ctrl : false;
bool has_focus = term_has_kbd_focus(term);
bool shift = has_focus ? _shift : false;
bool alt = has_focus ? _alt : false;
bool ctrl = has_focus ? _ctrl : false;
encoded += 32; /* Motion event */
encoded += (shift ? 4 : 0) + (alt ? 8 : 0) + (ctrl ? 16 : 0);
@ -2199,12 +2215,16 @@ term_mouse_motion(struct terminal *term, int button, int row, int col)
void
term_xcursor_update(struct terminal *term)
{
term->xcursor =
term->is_searching ? XCURSOR_LEFT_PTR : /* TODO: something different? */
selection_enabled(term) ? XCURSOR_TEXT :
XCURSOR_LEFT_PTR;
tll_foreach(term->wl->seats, it) {
struct seat *seat = &it->item;
render_xcursor_set(term);
const char *xcursor
= term->is_searching ? XCURSOR_LEFT_PTR : /* TODO: something different? */
selection_enabled(term, seat) ? XCURSOR_TEXT :
XCURSOR_LEFT_PTR;
render_xcursor_set(seat, term, xcursor);
}
}
void

View file

@ -305,7 +305,6 @@ struct terminal {
uint32_t text;
uint32_t cursor;
} cursor_color;
const char *xcursor;
struct {
enum selection_kind kind;
@ -439,6 +438,18 @@ struct terminal {
char *cwd;
};
extern const char *const XCURSOR_LEFT_PTR;
extern const char *const XCURSOR_TEXT;
//extern const char *const XCURSOR_HAND2;
extern const char *const XCURSOR_TOP_LEFT_CORNER;
extern const char *const XCURSOR_TOP_RIGHT_CORNER;
extern const char *const XCURSOR_BOTTOM_LEFT_CORNER;
extern const char *const XCURSOR_BOTTOM_RIGHT_CORNER;
extern const char *const XCURSOR_LEFT_SIDE;
extern const char *const XCURSOR_RIGHT_SIDE;
extern const char *const XCURSOR_TOP_SIDE;
extern const char *const XCURSOR_BOTTOM_SIDE;
struct config;
struct terminal *term_init(
const struct config *conf, struct fdm *fdm, struct reaper *reaper,
@ -506,12 +517,19 @@ void term_restore_cursor(struct terminal *term, const struct cursor *cursor);
void term_visual_focus_in(struct terminal *term);
void term_visual_focus_out(struct terminal *term);
bool term_has_kbd_focus(struct terminal *term);
void term_kbd_focus_in(struct terminal *term);
void term_kbd_focus_out(struct terminal *term);
void term_mouse_down(struct terminal *term, int button, int row, int col);
void term_mouse_up(struct terminal *term, int button, int row, int col);
void term_mouse_motion(struct terminal *term, int button, int row, int col);
bool term_mouse_grabbed(const struct terminal *term);
void term_mouse_down(
struct terminal *term, int button, int row, int col,
bool shift, bool alt, bool ctrl);
void term_mouse_up(
struct terminal *term, int button, int row, int col,
bool shift, bool alt, bool ctrl);
void term_mouse_motion(
struct terminal *term, int button, int row, int col,
bool shift, bool alt, bool ctrl);
bool term_mouse_grabbed(const struct terminal *term, struct seat *seat);
void term_xcursor_update(struct terminal *term);
void term_set_window_title(struct terminal *term, const char *title);

427
wayland.c
View file

@ -30,9 +30,6 @@
#include "selection.h"
#include "util.h"
static bool wayl_reload_cursor_theme(
struct wayland *wayl, struct terminal *term);
static void
csd_instantiate(struct wl_window *win)
{
@ -71,6 +68,66 @@ csd_destroy(struct wl_window *win)
}
}
static void
seat_destroy(struct seat *seat)
{
if (seat == NULL)
return;
tll_foreach(seat->kbd.bindings.key, it)
tll_free(it->item.bind.key_codes);
tll_free(seat->kbd.bindings.key);
tll_foreach(seat->kbd.bindings.search, it)
tll_free(it->item.bind.key_codes);
tll_free(seat->kbd.bindings.search);
if (seat->kbd.xkb_compose_state != NULL)
xkb_compose_state_unref(seat->kbd.xkb_compose_state);
if (seat->kbd.xkb_compose_table != NULL)
xkb_compose_table_unref(seat->kbd.xkb_compose_table);
if (seat->kbd.xkb_keymap != NULL)
xkb_keymap_unref(seat->kbd.xkb_keymap);
if (seat->kbd.xkb_state != NULL)
xkb_state_unref(seat->kbd.xkb_state);
if (seat->kbd.xkb != NULL)
xkb_context_unref(seat->kbd.xkb);
if (seat->kbd.repeat.fd >= 0)
fdm_del(seat->wayl->fdm, seat->kbd.repeat.fd);
if (seat->pointer.theme != NULL)
wl_cursor_theme_destroy(seat->pointer.theme);
if (seat->pointer.surface != NULL)
wl_surface_destroy(seat->pointer.surface);
if (seat->pointer.xcursor_callback != NULL)
wl_callback_destroy(seat->pointer.xcursor_callback);
if (seat->clipboard.data_source != NULL)
wl_data_source_destroy(seat->clipboard.data_source);
if (seat->clipboard.data_offer != NULL)
wl_data_offer_destroy(seat->clipboard.data_offer);
if (seat->primary.data_source != NULL)
zwp_primary_selection_source_v1_destroy(seat->primary.data_source);
if (seat->primary.data_offer != NULL)
zwp_primary_selection_offer_v1_destroy(seat->primary.data_offer);
if (seat->primary_selection_device != NULL)
zwp_primary_selection_device_v1_destroy(seat->primary_selection_device);
if (seat->data_device != NULL)
wl_data_device_destroy(seat->data_device);
if (seat->wl_keyboard != NULL)
wl_keyboard_destroy(seat->wl_keyboard);
if (seat->wl_pointer != NULL)
wl_pointer_destroy(seat->wl_pointer);
if (seat->wl_seat != NULL)
wl_seat_destroy(seat->wl_seat);
free(seat->clipboard.text);
free(seat->primary.text);
free(seat->name);
}
static void
shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
{
@ -98,29 +155,50 @@ static void
seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
enum wl_seat_capability caps)
{
struct wayland *wayl = data;
struct seat *seat = data;
assert(seat->wl_seat == wl_seat);
LOG_DBG("%s: keyboard=%s, pointer=%s", seat->name,
(caps & WL_SEAT_CAPABILITY_KEYBOARD) ? "yes" : "no",
(caps & WL_SEAT_CAPABILITY_POINTER) ? "yes" : "no");
if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
if (wayl->keyboard == NULL) {
wayl->keyboard = wl_seat_get_keyboard(wl_seat);
wl_keyboard_add_listener(wayl->keyboard, &keyboard_listener, wayl);
if (seat->wl_keyboard == NULL) {
seat->wl_keyboard = wl_seat_get_keyboard(wl_seat);
wl_keyboard_add_listener(seat->wl_keyboard, &keyboard_listener, seat);
}
} else {
if (wayl->keyboard != NULL) {
wl_keyboard_release(wayl->keyboard);
wayl->keyboard = NULL;
if (seat->wl_keyboard != NULL) {
wl_keyboard_release(seat->wl_keyboard);
seat->wl_keyboard = NULL;
}
}
if (caps & WL_SEAT_CAPABILITY_POINTER) {
if (wayl->pointer.pointer == NULL) {
wayl->pointer.pointer = wl_seat_get_pointer(wl_seat);
wl_pointer_add_listener(wayl->pointer.pointer, &pointer_listener, wayl);
if (seat->wl_pointer == NULL) {
assert(seat->pointer.surface == NULL);
seat->pointer.surface = wl_compositor_create_surface(seat->wayl->compositor);
if (seat->pointer.surface == NULL) {
LOG_ERR("%s: failed to create pointer surface", seat->name);
return;
}
seat->wl_pointer = wl_seat_get_pointer(wl_seat);
wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat);
}
} else {
if (wayl->pointer.pointer != NULL) {
wl_pointer_release(wayl->pointer.pointer);
wayl->pointer.pointer = NULL;
if (seat->wl_pointer != NULL) {
wl_pointer_release(seat->wl_pointer);
wl_surface_destroy(seat->pointer.surface);
if (seat->pointer.theme != NULL)
wl_cursor_theme_destroy(seat->pointer.theme);
seat->wl_pointer = NULL;
seat->pointer.surface = NULL;
seat->pointer.theme = NULL;
seat->pointer.cursor = NULL;
}
}
}
@ -128,6 +206,9 @@ seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
static void
seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name)
{
struct seat *seat = data;
free(seat->name);
seat->name = strdup(name);
}
static const struct wl_seat_listener seat_listener = {
@ -144,7 +225,6 @@ update_term_for_output_change(struct terminal *term)
render_resize(term, term->width / term->scale, term->height / term->scale);
term_font_dpi_changed(term);
term_font_subpixel_changed(term);
wayl_reload_cursor_theme(term->wl, term);
}
static void
@ -533,6 +613,32 @@ static const struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration
.configure = &xdg_toplevel_decoration_configure,
};
static bool
fdm_repeat(struct fdm *fdm, int fd, int events, void *data)
{
if (events & EPOLLHUP)
return false;
struct seat *seat = data;
uint64_t expiration_count;
ssize_t ret = read(
seat->kbd.repeat.fd, &expiration_count, sizeof(expiration_count));
if (ret < 0) {
if (errno == EAGAIN)
return true;
LOG_ERRNO("failed to read repeat key from repeat timer fd");
return false;
}
seat->kbd.repeat.dont_re_repeat = true;
for (size_t i = 0; i < expiration_count; i++)
input_repeat(seat, seat->kbd.repeat.key);
seat->kbd.repeat.dont_re_repeat = false;
return true;
}
static void
handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
@ -566,7 +672,6 @@ handle_global(void *data, struct wl_registry *registry,
wayl->shm = wl_registry_bind(
wayl->registry, name, &wl_shm_interface, required);
wl_shm_add_listener(wayl->shm, &shm_listener, wayl);
wl_display_roundtrip(wayl->display);
}
else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
@ -593,10 +698,55 @@ handle_global(void *data, struct wl_registry *registry,
if (!verify_iface_version(interface, version, required))
return;
wayl->seat = wl_registry_bind(
int repeat_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
if (repeat_fd == -1) {
LOG_ERRNO("failed to create keyboard repeat timer FD");
return;
}
struct wl_seat *wl_seat = wl_registry_bind(
wayl->registry, name, &wl_seat_interface, required);
wl_seat_add_listener(wayl->seat, &seat_listener, wayl);
wl_display_roundtrip(wayl->display);
/* Clipboard */
struct wl_data_device *data_device = wl_data_device_manager_get_data_device(
wayl->data_device_manager, wl_seat);
/* Primary selection */
struct zwp_primary_selection_device_v1 *primary_selection_device;
if (wayl->primary_selection_device_manager != NULL) {
primary_selection_device = zwp_primary_selection_device_manager_v1_get_device(
wayl->primary_selection_device_manager, wl_seat);
} else
primary_selection_device = NULL;
tll_push_back(wayl->seats, ((struct seat){
.wayl = wayl,
.wl_seat = wl_seat,
.wl_name = name,
.kbd = {
.repeat = {
.fd = repeat_fd,
},
},
.data_device = data_device,
.primary_selection_device = primary_selection_device,
}));
struct seat *seat = &tll_back(wayl->seats);
if (!fdm_add(wayl->fdm, repeat_fd, EPOLLIN, &fdm_repeat, seat)) {
close(repeat_fd);
seat->kbd.repeat.fd = -1;
seat_destroy(seat);
return;
}
wl_seat_add_listener(wl_seat, &seat_listener, seat);
wl_data_device_add_listener(data_device, &data_device_listener, seat);
if (primary_selection_device != NULL) {
zwp_primary_selection_device_v1_add_listener(
primary_selection_device, &primary_selection_device_listener, seat);
}
}
else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
@ -629,7 +779,6 @@ handle_global(void *data, struct wl_registry *registry,
wayl->xdg_output_manager, mon->output);
zxdg_output_v1_add_listener(mon->xdg, &xdg_output_listener, mon);
}
wl_display_roundtrip(wayl->display);
}
else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) {
@ -685,7 +834,7 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
struct wayland *wayl = data;
/* For now, we only support removal of outputs */
/* Check if this is an output */
tll_foreach(wayl->monitors, it) {
struct monitor *mon = &it->item;
@ -702,11 +851,40 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
tll_foreach(wayl->terms, t)
surface_leave(t->item->window, NULL /* wl_surface - unused */, mon->output);
monitor_destroy(&it->item);
monitor_destroy(mon);
tll_remove(wayl->monitors, it);
return;
}
/* A seat? */
tll_foreach(wayl->seats, it) {
struct seat *seat = &it->item;
if (seat->wl_name != name)
continue;
LOG_INFO("seat destroyed: %s", seat->name);
if (seat->kbd_focus != NULL) {
LOG_WARN("compositor destroyed seat '%s' "
"without sending keyboard/pointer leave events",
seat->name);
struct terminal *term = seat->kbd_focus;
if (seat->wl_keyboard != NULL)
keyboard_listener.leave(
seat, seat->wl_keyboard, -1, term->window->surface);
if (seat->wl_pointer != NULL)
pointer_listener.leave(
seat, seat->wl_pointer, -1, term->window->surface);
}
seat_destroy(seat);
tll_remove(wayl->seats, it);
}
LOG_WARN("unknown global removed: 0x%08x", name);
}
@ -747,32 +925,6 @@ fdm_wayl(struct fdm *fdm, int fd, int events, void *data)
return event_count != -1;
}
static bool
fdm_repeat(struct fdm *fdm, int fd, int events, void *data)
{
if (events & EPOLLHUP)
return false;
struct wayland *wayl = data;
uint64_t expiration_count;
ssize_t ret = read(
wayl->kbd.repeat.fd, &expiration_count, sizeof(expiration_count));
if (ret < 0) {
if (errno == EAGAIN)
return true;
LOG_ERRNO("failed to read repeat key from repeat timer fd");
return false;
}
wayl->kbd.repeat.dont_re_repeat = true;
for (size_t i = 0; i < expiration_count; i++)
input_repeat(wayl, wayl->kbd.repeat.key);
wayl->kbd.repeat.dont_re_repeat = false;
return true;
}
struct wayland *
wayl_init(const struct config *conf, struct fdm *fdm)
{
@ -780,7 +932,6 @@ wayl_init(const struct config *conf, struct fdm *fdm)
wayl->conf = conf;
wayl->fdm = fdm;
wayl->fd = -1;
wayl->kbd.repeat.fd = -1;
if (!fdm_hook_add(fdm, &fdm_hook, wayl, FDM_HOOK_PRIORITY_LOW)) {
LOG_ERR("failed to add FDM hook");
@ -818,20 +969,11 @@ wayl_init(const struct config *conf, struct fdm *fdm)
LOG_ERR("no XDG shell interface");
goto out;
}
if (wayl->seat == NULL) {
LOG_ERR("no seat available");
goto out;
}
if (wayl->data_device_manager == NULL) {
LOG_ERR("no clipboard available "
"(wl_data_device_manager not implemented by server)");
goto out;
}
if (!wayl->have_argb8888) {
LOG_ERR("compositor does not support ARGB surfaces");
goto out;
}
if (wayl->primary_selection_device_manager == NULL)
LOG_WARN("no primary selection available");
@ -840,6 +982,14 @@ wayl_init(const struct config *conf, struct fdm *fdm)
goto out;
}
/* Trigger listeners registered when handling globals */
wl_display_roundtrip(wayl->display);
if (!wayl->have_argb8888) {
LOG_ERR("compositor does not support ARGB surfaces");
goto out;
}
tll_foreach(wayl->monitors, it) {
LOG_INFO(
"%s: %dx%d+%dx%d@%dHz %s %.2f\" scale=%d PPI=%dx%d (physical) PPI=%dx%d (logical)",
@ -851,46 +1001,6 @@ wayl_init(const struct config *conf, struct fdm *fdm)
it->item.ppi.scaled.x, it->item.ppi.scaled.y);
}
/* Clipboard */
wayl->data_device = wl_data_device_manager_get_data_device(
wayl->data_device_manager, wayl->seat);
wl_data_device_add_listener(wayl->data_device, &data_device_listener, wayl);
/* Primary selection */
if (wayl->primary_selection_device_manager != NULL) {
wayl->primary_selection_device = zwp_primary_selection_device_manager_v1_get_device(
wayl->primary_selection_device_manager, wayl->seat);
zwp_primary_selection_device_v1_add_listener(
wayl->primary_selection_device, &primary_selection_device_listener, wayl);
}
/* Cursor */
unsigned cursor_size = 24;
const char *cursor_theme = getenv("XCURSOR_THEME");
{
const char *env_cursor_size = getenv("XCURSOR_SIZE");
if (env_cursor_size != NULL) {
unsigned size;
if (sscanf(env_cursor_size, "%u", &size) == 1)
cursor_size = size;
}
}
/* Note: theme is (re)loaded on scale and output changes */
LOG_INFO("cursor theme: %s, size: %u", cursor_theme, cursor_size);
wayl->pointer.size = cursor_size;
wayl->pointer.theme_name = cursor_theme != NULL ? strdup(cursor_theme) : NULL;
wayl->pointer.surface = wl_compositor_create_surface(wayl->compositor);
if (wayl->pointer.surface == NULL) {
LOG_ERR("failed to create cursor surface");
goto out;
}
/* All wayland initialization done - make it so */
wl_display_roundtrip(wayl->display);
wayl->fd = wl_display_get_fd(wayl->display);
if (fcntl(wayl->fd, F_SETFL, fcntl(wayl->fd, F_GETFL) | O_NONBLOCK) < 0) {
LOG_ERRNO("failed to make Wayland socket non-blocking");
@ -900,15 +1010,6 @@ wayl_init(const struct config *conf, struct fdm *fdm)
if (!fdm_add(fdm, wayl->fd, EPOLLIN, &fdm_wayl, wayl))
goto out;
wayl->kbd.repeat.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
if (wayl->kbd.repeat.fd == -1) {
LOG_ERRNO("failed to create keyboard repeat timer FD");
goto out;
}
if (!fdm_add(fdm, wayl->kbd.repeat.fd, EPOLLIN, &fdm_repeat, wayl))
goto out;
if (wl_display_prepare_read(wayl->display) != 0) {
LOG_ERRNO("failed to prepare for reading wayland events");
goto out;
@ -941,77 +1042,26 @@ wayl_destroy(struct wayland *wayl)
fdm_hook_del(wayl->fdm, &fdm_hook, FDM_HOOK_PRIORITY_LOW);
if (wayl->kbd.repeat.fd != -1)
fdm_del(wayl->fdm, wayl->kbd.repeat.fd);
tll_foreach(wayl->monitors, it) {
tll_foreach(wayl->monitors, it)
monitor_destroy(&it->item);
tll_remove(wayl->monitors, it);
}
tll_free(wayl->monitors);
if (wayl->pointer.xcursor_callback != NULL)
wl_callback_destroy(wayl->pointer.xcursor_callback);
tll_foreach(wayl->seats, it)
seat_destroy(&it->item);
tll_free(wayl->seats);
if (wayl->xdg_output_manager != NULL)
zxdg_output_manager_v1_destroy(wayl->xdg_output_manager);
if (wayl->shell != NULL)
xdg_wm_base_destroy(wayl->shell);
if (wayl->xdg_decoration_manager != NULL)
zxdg_decoration_manager_v1_destroy(wayl->xdg_decoration_manager);
if (wayl->presentation != NULL)
wp_presentation_destroy(wayl->presentation);
tll_foreach(wayl->kbd.bindings.key, it)
tll_free(it->item.bind.key_codes);
tll_free(wayl->kbd.bindings.key);
tll_foreach(wayl->kbd.bindings.search, it)
tll_free(it->item.bind.key_codes);
tll_free(wayl->kbd.bindings.search);
if (wayl->kbd.xkb_compose_state != NULL)
xkb_compose_state_unref(wayl->kbd.xkb_compose_state);
if (wayl->kbd.xkb_compose_table != NULL)
xkb_compose_table_unref(wayl->kbd.xkb_compose_table);
if (wayl->kbd.xkb_keymap != NULL)
xkb_keymap_unref(wayl->kbd.xkb_keymap);
if (wayl->kbd.xkb_state != NULL)
xkb_state_unref(wayl->kbd.xkb_state);
if (wayl->kbd.xkb != NULL)
xkb_context_unref(wayl->kbd.xkb);
if (wayl->clipboard.data_source != NULL)
wl_data_source_destroy(wayl->clipboard.data_source);
if (wayl->clipboard.data_offer != NULL)
wl_data_offer_destroy(wayl->clipboard.data_offer);
free(wayl->clipboard.text);
if (wayl->primary.data_source != NULL)
zwp_primary_selection_source_v1_destroy(wayl->primary.data_source);
if (wayl->primary.data_offer != NULL)
zwp_primary_selection_offer_v1_destroy(wayl->primary.data_offer);
free(wayl->primary.text);
free(wayl->pointer.theme_name);
if (wayl->pointer.theme != NULL)
wl_cursor_theme_destroy(wayl->pointer.theme);
if (wayl->pointer.pointer != NULL)
wl_pointer_destroy(wayl->pointer.pointer);
if (wayl->pointer.surface != NULL)
wl_surface_destroy(wayl->pointer.surface);
if (wayl->keyboard != NULL)
wl_keyboard_destroy(wayl->keyboard);
if (wayl->data_device != NULL)
wl_data_device_destroy(wayl->data_device);
if (wayl->data_device_manager != NULL)
wl_data_device_manager_destroy(wayl->data_device_manager);
if (wayl->primary_selection_device != NULL)
zwp_primary_selection_device_v1_destroy(wayl->primary_selection_device);
if (wayl->primary_selection_device_manager != NULL)
zwp_primary_selection_device_manager_v1_destroy(wayl->primary_selection_device_manager);
if (wayl->seat != NULL)
wl_seat_destroy(wayl->seat);
if (wayl->shm != NULL)
wl_shm_destroy(wayl->shm);
if (wayl->sub_compositor != NULL)
@ -1022,9 +1072,8 @@ wayl_destroy(struct wayland *wayl)
wl_registry_destroy(wayl->registry);
if (wayl->fd != -1)
fdm_del_no_close(wayl->fdm, wayl->fd);
if (wayl->display != NULL) {
if (wayl->display != NULL)
wl_display_disconnect(wayl->display);
}
free(wayl);
}
@ -1160,30 +1209,46 @@ wayl_win_destroy(struct wl_window *win)
free(win);
}
static bool
wayl_reload_cursor_theme(struct wayland *wayl, struct terminal *term)
bool
wayl_reload_xcursor_theme(struct seat *seat, int new_scale)
{
if (wayl->pointer.size == 0)
if (seat->pointer.theme != NULL && seat->pointer.scale == new_scale) {
/* We already have a theme loaded, and the scale hasn't changed */
return true;
if (wayl->pointer.theme != NULL) {
wl_cursor_theme_destroy(wayl->pointer.theme);
wayl->pointer.theme = NULL;
wayl->pointer.cursor = NULL;
}
LOG_DBG("reloading cursor theme: %s@%d",
wayl->pointer.theme_name, wayl->pointer.size);
if (seat->pointer.theme != NULL) {
assert(seat->pointer.scale != new_scale);
wl_cursor_theme_destroy(seat->pointer.theme);
seat->pointer.theme = NULL;
seat->pointer.cursor = NULL;
}
wayl->pointer.theme = wl_cursor_theme_load(
wayl->pointer.theme_name, wayl->pointer.size * term->scale, wayl->shm);
const char *xcursor_theme = getenv("XCURSOR_THEME");
int xcursor_size = 24;
if (wayl->pointer.theme == NULL) {
{
const char *env_cursor_size = getenv("XCURSOR_SIZE");
if (env_cursor_size != NULL) {
unsigned size;
if (sscanf(env_cursor_size, "%u", &size) == 1)
xcursor_size = size;
}
}
LOG_INFO("cursor theme: %s, size: %u, scale: %d",
xcursor_theme, xcursor_size, new_scale);
seat->pointer.theme = wl_cursor_theme_load(
xcursor_theme, xcursor_size * new_scale, seat->wayl->shm);
if (seat->pointer.theme == NULL) {
LOG_ERR("failed to load cursor theme");
return false;
}
return render_xcursor_set(term);
seat->pointer.scale = new_scale;
return true;
}
void

289
wayland.h
View file

@ -15,65 +15,6 @@
#include "fdm.h"
struct monitor {
struct wayland *wayl;
struct wl_output *output;
struct zxdg_output_v1 *xdg;
uint32_t wl_name;
int x;
int y;
struct {
/* Physical size, in mm */
struct {
int width;
int height;
} mm;
/* Physical size, in pixels */
struct {
int width;
int height;
} px_real;
/* Scaled size, in pixels */
struct {
int width;
int height;
} px_scaled;
} dim;
struct {
/* PPI, based on physical size */
struct {
int x;
int y;
} real;
/* PPI, logical, based on scaled size */
struct {
int x;
int y;
} scaled;
} ppi;
int scale;
float refresh;
enum wl_output_subpixel subpixel;
/* From wl_output */
char *make;
char *model;
/* From xdg_output */
char *name;
char *description;
float inch; /* e.g. 24" */
};
typedef tll(xkb_keycode_t) xkb_keycode_list_t;
struct key_binding {
@ -138,38 +79,6 @@ struct key_binding_search {
enum bind_action_search action;
};
struct kbd {
struct xkb_context *xkb;
struct xkb_keymap *xkb_keymap;
struct xkb_state *xkb_state;
struct xkb_compose_table *xkb_compose_table;
struct xkb_compose_state *xkb_compose_state;
struct {
int fd;
bool dont_re_repeat;
int32_t delay;
int32_t rate;
uint32_t key;
} repeat;
xkb_mod_index_t mod_shift;
xkb_mod_index_t mod_alt;
xkb_mod_index_t mod_ctrl;
xkb_mod_index_t mod_meta;
/* Enabled modifiers */
bool shift;
bool alt;
bool ctrl;
bool meta;
struct {
tll(struct key_binding_normal) key;
tll(struct key_binding_search) search;
} bindings;
};
struct wl_clipboard {
struct wl_data_source *data_source;
struct wl_data_offer *data_offer;
@ -184,6 +93,91 @@ struct wl_primary {
uint32_t serial;
};
struct seat {
struct wayland *wayl;
struct wl_seat *wl_seat;
uint32_t wl_name;
char *name;
/* Focused terminals */
struct terminal *kbd_focus;
struct terminal *mouse_focus;
/* Keyboard state */
struct wl_keyboard *wl_keyboard;
struct {
uint32_t serial;
struct xkb_context *xkb;
struct xkb_keymap *xkb_keymap;
struct xkb_state *xkb_state;
struct xkb_compose_table *xkb_compose_table;
struct xkb_compose_state *xkb_compose_state;
struct {
int fd;
bool dont_re_repeat;
int32_t delay;
int32_t rate;
uint32_t key;
} repeat;
xkb_mod_index_t mod_shift;
xkb_mod_index_t mod_alt;
xkb_mod_index_t mod_ctrl;
xkb_mod_index_t mod_meta;
/* Enabled modifiers */
bool shift;
bool alt;
bool ctrl;
bool meta;
struct {
tll(struct key_binding_normal) key;
tll(struct key_binding_search) search;
} bindings;
} kbd;
/* Pointer state */
struct wl_pointer *wl_pointer;
struct {
uint32_t serial;
struct wl_surface *surface;
struct wl_cursor_theme *theme;
struct wl_cursor *cursor;
int scale;
const char *xcursor;
struct wl_callback *xcursor_callback;
bool xcursor_pending;
} pointer;
struct {
int x;
int y;
int col;
int row;
int button;
int count;
int last_button;
struct timeval last_time;
/* We used a discrete axis event in the current pointer frame */
double axis_aggregated;
bool have_discrete;
} mouse;
/* Clipboard */
struct wl_data_device *data_device;
struct zwp_primary_selection_device_v1 *primary_selection_device;
struct wl_clipboard clipboard;
struct wl_primary primary;
};
enum csd_surface {
CSD_SURF_TITLE,
CSD_SURF_LEFT,
@ -196,6 +190,64 @@ enum csd_surface {
CSD_SURF_COUNT,
};
struct monitor {
struct wayland *wayl;
struct wl_output *output;
struct zxdg_output_v1 *xdg;
uint32_t wl_name;
int x;
int y;
struct {
/* Physical size, in mm */
struct {
int width;
int height;
} mm;
/* Physical size, in pixels */
struct {
int width;
int height;
} px_real;
/* Scaled size, in pixels */
struct {
int width;
int height;
} px_scaled;
} dim;
struct {
/* PPI, based on physical size */
struct {
int x;
int y;
} real;
/* PPI, logical, based on scaled size */
struct {
int x;
int y;
} scaled;
} ppi;
int scale;
float refresh;
enum wl_output_subpixel subpixel;
/* From wl_output */
char *make;
char *model;
/* From xdg_output */
char *name;
char *description;
float inch; /* e.g. 24" */
};
struct wayland;
struct wl_window {
struct terminal *term;
@ -248,67 +300,22 @@ struct wayland {
struct wl_subcompositor *sub_compositor;
struct wl_shm *shm;
struct wl_seat *seat;
struct wl_keyboard *keyboard;
struct zxdg_output_manager_v1 *xdg_output_manager;
struct xdg_wm_base *shell;
struct zxdg_decoration_manager_v1 *xdg_decoration_manager;
struct wl_data_device_manager *data_device_manager;
struct zwp_primary_selection_device_manager_v1 *primary_selection_device_manager;
struct wp_presentation *presentation;
uint32_t presentation_clock_id;
/* Keyboard */
struct kbd kbd;
/* Clipboard */
uint32_t input_serial;
struct wl_data_device_manager *data_device_manager;
struct wl_data_device *data_device;
struct zwp_primary_selection_device_manager_v1 *primary_selection_device_manager;
struct zwp_primary_selection_device_v1 *primary_selection_device;
struct wl_clipboard clipboard;
struct wl_primary primary;
/* Cursor */
struct {
struct wl_pointer *pointer;
uint32_t serial;
struct wl_surface *surface;
struct wl_cursor_theme *theme;
struct wl_cursor *cursor;
int size;
char *theme_name;
const char *xcursor;
const struct terminal *pending_terminal;
struct wl_callback *xcursor_callback;
} pointer;
struct {
int x;
int y;
int col;
int row;
int button;
int count;
int last_button;
struct timeval last_time;
/* We used a discrete axis event in the current pointer frame */
double axis_aggregated;
bool have_discrete;
} mouse;
bool have_argb8888;
tll(struct monitor) monitors; /* All available outputs */
tll(struct seat) seats;
tll(struct terminal *) terms;
struct terminal *kbd_focus;
struct terminal *mouse_focus;
};
struct wayland *wayl_init(const struct config *conf, struct fdm *fdm);
@ -319,3 +326,5 @@ void wayl_roundtrip(struct wayland *wayl);
struct wl_window *wayl_win_init(struct terminal *term);
void wayl_win_destroy(struct wl_window *win);
bool wayl_reload_xcursor_theme(struct seat *seat, int new_scale);