mirror of
https://github.com/swaywm/sway.git
synced 2026-04-27 06:46:25 -04:00
store layout per keyboard for every window
Fixes: https://github.com/swaywm/sway/issues/2361 Signed-off-by: Konstantin Kharlamov <Hi-Angel@yandex.ru>
This commit is contained in:
parent
481accca2a
commit
3a5544f56c
9 changed files with 143 additions and 5 deletions
|
|
@ -63,10 +63,16 @@ struct sway_keyboard {
|
|||
|
||||
struct wl_event_source *key_repeat_source;
|
||||
struct sway_binding *repeat_binding;
|
||||
xkb_layout_index_t default_kbd_layout;
|
||||
};
|
||||
|
||||
struct xkb_keymap *sway_keyboard_compile_keymap(struct input_config *ic);
|
||||
|
||||
struct sway_layout_per_kbd {
|
||||
struct wlr_keyboard *kbd;
|
||||
xkb_layout_index_t layout;
|
||||
};
|
||||
|
||||
struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
|
||||
struct sway_seat_device *device);
|
||||
|
||||
|
|
@ -74,5 +80,9 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard);
|
|||
|
||||
void sway_keyboard_destroy(struct sway_keyboard *keyboard);
|
||||
|
||||
void sway_keyboard_set_layout(struct wlr_keyboard *kbd, xkb_layout_index_t layout);
|
||||
|
||||
xkb_layout_index_t sway_keyboard_get_layout(struct xkb_state *kbd_state);
|
||||
|
||||
void sway_keyboard_disarm_key_repeat(struct sway_keyboard *keyboard);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ struct sway_view {
|
|||
} events;
|
||||
|
||||
struct wl_listener surface_new_subsurface;
|
||||
|
||||
list_t *kbd_layouts; // struct sway_layout_per_kbd *
|
||||
};
|
||||
|
||||
struct sway_xdg_shell_v6_view {
|
||||
|
|
@ -309,7 +311,7 @@ void view_for_each_popup(struct sway_view *view,
|
|||
|
||||
// view implementation
|
||||
|
||||
void view_init(struct sway_view *view, enum sway_view_type type,
|
||||
bool view_init(struct sway_view *view, enum sway_view_type type,
|
||||
const struct sway_view_impl *impl);
|
||||
|
||||
void view_destroy(struct sway_view *view);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ struct seat_config *new_seat_config(const char* name) {
|
|||
}
|
||||
seat->hide_cursor_timeout = -1;
|
||||
seat->allow_constrain = CONSTRAIN_DEFAULT;
|
||||
seat->keep_keyboard_layout = KEYBOARD_LAYOUT_UNDEFINED;
|
||||
|
||||
return seat;
|
||||
}
|
||||
|
|
@ -116,6 +117,10 @@ void merge_seat_config(struct seat_config *dest, struct seat_config *source) {
|
|||
dest->fallback = source->fallback;
|
||||
}
|
||||
|
||||
if (source->keep_keyboard_layout != KEYBOARD_LAYOUT_UNDEFINED) {
|
||||
dest->keep_keyboard_layout = source->keep_keyboard_layout;
|
||||
}
|
||||
|
||||
for (int i = 0; i < source->attachments->length; ++i) {
|
||||
struct seat_attachment_config *source_attachment =
|
||||
source->attachments->items[i];
|
||||
|
|
|
|||
|
|
@ -504,7 +504,11 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl);
|
||||
if (!view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl)) {
|
||||
sway_assert(false, "Failed to init view");
|
||||
return;
|
||||
}
|
||||
|
||||
xdg_shell_view->view.wlr_xdg_surface = xdg_surface;
|
||||
|
||||
xdg_shell_view->map.notify = handle_map;
|
||||
|
|
|
|||
|
|
@ -492,7 +492,11 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
view_init(&xdg_shell_v6_view->view, SWAY_VIEW_XDG_SHELL_V6, &view_impl);
|
||||
if (!view_init(&xdg_shell_v6_view->view, SWAY_VIEW_XDG_SHELL_V6, &view_impl)) {
|
||||
sway_assert(false, "Failed to init view");
|
||||
return;
|
||||
}
|
||||
|
||||
xdg_shell_v6_view->view.wlr_xdg_surface_v6 = xdg_surface;
|
||||
|
||||
xdg_shell_v6_view->map.notify = handle_map;
|
||||
|
|
|
|||
|
|
@ -595,7 +595,11 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl);
|
||||
if (!view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl)) {
|
||||
sway_assert(false, "Failed to init view");
|
||||
return;
|
||||
}
|
||||
|
||||
xwayland_view->view.wlr_xwayland_surface = xsurface;
|
||||
|
||||
wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "sway/input/keyboard.h"
|
||||
#include "sway/input/seat.h"
|
||||
#include "sway/ipc-server.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "log.h"
|
||||
|
||||
static struct modifier_key {
|
||||
|
|
@ -475,6 +476,20 @@ static void handle_keyboard_modifiers(struct wl_listener *listener,
|
|||
determine_bar_visibility(modifiers);
|
||||
}
|
||||
|
||||
static void add_kbd_to_view(struct sway_container *con, void *data) {
|
||||
if (!con->view) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct sway_layout_per_kbd *lpk = calloc(1, sizeof(struct sway_layout_per_kbd));
|
||||
if (!sway_assert(lpk, "Failed to allocate sway_layout_per_kbd")) {
|
||||
return;
|
||||
}
|
||||
|
||||
*lpk = *(struct sway_layout_per_kbd *)data;
|
||||
list_add(con->view->kbd_layouts, lpk);
|
||||
}
|
||||
|
||||
struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
|
||||
struct sway_seat_device *device) {
|
||||
struct sway_keyboard *keyboard =
|
||||
|
|
@ -580,6 +595,32 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
|
|||
wl_signal_add(&wlr_device->keyboard->events.modifiers,
|
||||
&keyboard->keyboard_modifiers);
|
||||
keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers;
|
||||
|
||||
keyboard->default_kbd_layout =
|
||||
sway_keyboard_get_layout(wlr_device->keyboard->xkb_state);
|
||||
struct sway_layout_per_kbd lpk = {
|
||||
.kbd = wlr_device->keyboard,
|
||||
.layout = keyboard->default_kbd_layout
|
||||
};
|
||||
root_for_each_container(add_kbd_to_view, &lpk);
|
||||
}
|
||||
|
||||
static void rm_kbd_from_view(struct sway_container *con, void *data) {
|
||||
if (!con->view) {
|
||||
return;
|
||||
}
|
||||
|
||||
list_t *kbd_layouts = con->view->kbd_layouts;
|
||||
for (int i = 0; i < kbd_layouts->length; ++i) {
|
||||
struct sway_layout_per_kbd *lpk = kbd_layouts->items[i];
|
||||
if (lpk->kbd == (struct wlr_keyboard *)data) {
|
||||
free(lpk);
|
||||
list_del(kbd_layouts, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
sway_assert(false,
|
||||
"sway_layout_per_kbd not found in sway_view for removal");
|
||||
}
|
||||
|
||||
void sway_keyboard_destroy(struct sway_keyboard *keyboard) {
|
||||
|
|
@ -593,5 +634,19 @@ void sway_keyboard_destroy(struct sway_keyboard *keyboard) {
|
|||
wl_list_remove(&keyboard->keyboard_modifiers.link);
|
||||
sway_keyboard_disarm_key_repeat(keyboard);
|
||||
wl_event_source_remove(keyboard->key_repeat_source);
|
||||
root_for_each_container(rm_kbd_from_view,
|
||||
keyboard->seat_device->input_device->wlr_device->keyboard);
|
||||
free(keyboard);
|
||||
}
|
||||
|
||||
void sway_keyboard_set_layout(struct wlr_keyboard *kbd, xkb_layout_index_t layout) {
|
||||
wlr_keyboard_notify_modifiers(kbd,
|
||||
kbd->modifiers.depressed,
|
||||
kbd->modifiers.latched,
|
||||
kbd->modifiers.locked,
|
||||
layout);
|
||||
}
|
||||
|
||||
xkb_layout_index_t sway_keyboard_get_layout(struct xkb_state *kbd_state) {
|
||||
return xkb_state_serialize_layout(kbd_state, XKB_STATE_LAYOUT_EFFECTIVE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,13 @@ static void seat_send_activate(struct sway_node *node, struct sway_seat *seat) {
|
|||
}
|
||||
}
|
||||
|
||||
static void set_kbd_layouts(const struct sway_view *view) {
|
||||
for (int i = 0; i < view->kbd_layouts->length; ++i) {
|
||||
struct sway_layout_per_kbd *lpk = view->kbd_layouts->items[i];
|
||||
sway_keyboard_set_layout(lpk->kbd, lpk->layout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If con is a view, set it as active and enable keyboard input.
|
||||
* If con is a container, set all child views as active and don't enable
|
||||
|
|
@ -99,6 +106,12 @@ static void seat_send_focus(struct sway_node *node, struct sway_seat *seat) {
|
|||
#endif
|
||||
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
|
||||
if (keyboard) {
|
||||
const struct seat_config *seat_config = seat_get_config(seat);
|
||||
if (seat_config) {
|
||||
if (seat_config->keep_keyboard_layout == KEYBOARD_LAYOUT_PER_WINDOW) {
|
||||
set_kbd_layouts(view);
|
||||
}
|
||||
}
|
||||
wlr_seat_keyboard_notify_enter(seat->wlr_seat,
|
||||
view->surface, keyboard->keycodes,
|
||||
keyboard->num_keycodes, &keyboard->modifiers);
|
||||
|
|
@ -765,6 +778,13 @@ static void send_unfocus(struct sway_container *con, void *data) {
|
|||
}
|
||||
}
|
||||
|
||||
static void save_kbd_layouts(struct sway_view *view) {
|
||||
for (int i = 0; i < view->kbd_layouts->length; ++i) {
|
||||
struct sway_layout_per_kbd *lpk = view->kbd_layouts->items[i];
|
||||
lpk->layout = sway_keyboard_get_layout(lpk->kbd->xkb_state);
|
||||
}
|
||||
}
|
||||
|
||||
// Unfocus the container and any children (eg. when leaving `focus parent`)
|
||||
static void seat_send_unfocus(struct sway_node *node, struct sway_seat *seat) {
|
||||
sway_cursor_constrain(seat->cursor, NULL);
|
||||
|
|
@ -772,6 +792,15 @@ static void seat_send_unfocus(struct sway_node *node, struct sway_seat *seat) {
|
|||
if (node->type == N_WORKSPACE) {
|
||||
workspace_for_each_container(node->sway_workspace, send_unfocus, seat);
|
||||
} else {
|
||||
struct sway_view *view = node->type == N_CONTAINER ?
|
||||
node->sway_container->view : NULL;
|
||||
const struct seat_config *seat_config = seat_get_config(seat);
|
||||
|
||||
if (seat_config && view && seat_is_input_allowed(seat, view->surface) &&
|
||||
seat_config->keep_keyboard_layout == KEYBOARD_LAYOUT_PER_WINDOW) {
|
||||
save_kbd_layouts(view);
|
||||
}
|
||||
|
||||
send_unfocus(node->sway_container, seat);
|
||||
container_for_each_child(node->sway_container, send_unfocus, seat);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "sway/desktop.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/input/keyboard.h"
|
||||
#include "sway/ipc-server.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/input/seat.h"
|
||||
|
|
@ -30,13 +31,36 @@
|
|||
#include "pango.h"
|
||||
#include "stringop.h"
|
||||
|
||||
void view_init(struct sway_view *view, enum sway_view_type type,
|
||||
static bool view_setup_kbd_layouts(struct sway_view *view) {
|
||||
struct sway_seat *seat = NULL;
|
||||
wl_list_for_each(seat, &server.input->seats, link) {
|
||||
struct sway_seat_device *device = NULL;
|
||||
wl_list_for_each(device, &seat->devices, link) {
|
||||
struct wlr_input_device *wlr_input_device = device->input_device->wlr_device;
|
||||
if (wlr_input_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
|
||||
continue;
|
||||
}
|
||||
struct sway_layout_per_kbd *lpk = calloc(1, sizeof(struct sway_layout_per_kbd));
|
||||
if (!sway_assert(lpk, "Failed to allocate sway_layout_per_kbd")) {
|
||||
return false;
|
||||
}
|
||||
lpk->kbd = wlr_input_device->keyboard;
|
||||
lpk->layout = device->keyboard->default_kbd_layout;
|
||||
list_add(view->kbd_layouts, lpk);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool view_init(struct sway_view *view, enum sway_view_type type,
|
||||
const struct sway_view_impl *impl) {
|
||||
view->type = type;
|
||||
view->impl = impl;
|
||||
view->executed_criteria = create_list();
|
||||
view->kbd_layouts = create_list();
|
||||
view->allow_request_urgent = true;
|
||||
wl_signal_init(&view->events.unmap);
|
||||
return view_setup_kbd_layouts(view);
|
||||
}
|
||||
|
||||
void view_destroy(struct sway_view *view) {
|
||||
|
|
@ -55,6 +79,7 @@ void view_destroy(struct sway_view *view) {
|
|||
list_free(view->executed_criteria);
|
||||
|
||||
free(view->title_format);
|
||||
list_free_items_and_destroy(view->kbd_layouts);
|
||||
|
||||
if (view->impl->destroy) {
|
||||
view->impl->destroy(view);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue