13 Commits

Author SHA1 Message Date
Maarten van Gompel
9fb1964f5d version bump 2026-01-22 17:33:05 +01:00
Willow Barraco
5b29d8c1a7 Makefile: do not rebuild on install
Because the directory timestamp depends on the file insise, this rule
cause a second rebuild. Let's just silently create the directory
when we require it.

Signed-off-by: Willow Barraco <contact@willowbarraco.fr>
Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2026-01-22 17:32:10 +01:00
Maarten van Gompel
987ea03f84 Makefile: fix in make clean 2026-01-22 10:31:18 +01:00
Maarten van Gompel
0c743d9518 version bump 2026-01-22 10:27:20 +01:00
Willow Barraco
1963de0165 Improve the makefile to simplify building multiple layouts
At the moment, packaging multiple layout is a bit of a mess, because
there is no easy way to build multiple layouts binary in a row. The
clean task also drop the binary outpus. And the dependency checking is
somehow incorrect. It reuses the same config.h while building the
following layout.

To solve this, we now build config.h and %.o outputs in a builddir,
one per layout.

Signed-off-by: Willow Barraco <contact@willowbarraco.fr>
Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2026-01-22 10:26:42 +01:00
Willow Barraco
b0eff37239 Send modifiers keyboard.key additionaly to keyboard.modifiers
At the moment we just use keyboard.modifiers to maintain our clients
modifiers states. But we should also send the associated key codes.
Clients like wlvncc need them to actually send the keys to the remote
compositor.

We got no clear way to map our modifier enums to key codes. So I added
this zwp_virtual_keyboard_v1_key_mods method.

I think I tried most of the use-cases. The hardest part was arround the
Shift+Space that send Tab. We have to depress the Shift key, reset the
modifiers, send the Tab key, and finally depress back Shift and its
modifier.

I've tested a bit the Code with .code_mod (and .reset_mod), but I'm not
that sure what their behavior should be.

Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2026-01-21 22:00:51 +01:00
Maarten van Gompel
f0c99d276a Cancel pending frame callback before destroying surface and ignore old surfaces
This applies two of the improvements in the pull request
"Fix bug complying with wlr-layer-shell-unstable-v1 which causes crashes" to the overhauled codebase.

Reference: https://github.com/jjsullivan5196/wvkbd/pull/pr114
Co-authored-by: Armando DiCianno <armando@dicianno.org>
2026-01-20 08:24:07 +01:00
Maarten van Gompel
bd4a176eef update touch/pointer event checks in order to sequence drawing to a surface before configured.
This applies one of the improvements in the pull request
"Fix bug complying with wlr-layer-shell-unstable-v1 which causes crashes" to the overhauled codebase.

Reference: https://github.com/jjsullivan5196/wvkbd/pull/114
Co-authored-by: Armando DiCianno <armando@dicianno.org>
2026-01-20 08:19:37 +01:00
Anjandev Momi
a12c42cd18 build: fix clang-format build name 2026-01-18 14:12:08 -08:00
Anjandev Momi
66cd3bf49d build: add clang-format 2026-01-18 14:11:14 -08:00
Anjandev Momi
b215035efc add sourcehut build 2026-01-18 14:10:01 -08:00
Maarten van Gompel
f917d02591 version bump prior to release 2026-01-14 22:10:54 +01:00
Willow Barraco
34a33b41fa Overhaul the output available dimension detection (once again)
Recently I've opened a ticket on the Wayland protocol to discuss
on how to determine the very first dimension a client must use, before
receiving the very first actual wl_surface events:

https://gitlab.freedesktop.org/wayland/wayland/-/issues/576

This is a issue I had on wvkbd, but also on bemenu. Here we need the
dimension to determine which layout and height to use.

This implement another approach, recommended by the Wayland folks:

The wl_output object is currently being slowly deprecated, because it is
mostly unusable for the unprivileged clients. In our context, using this
value to determine the available geometry is actually wrong. Other
layer_shell surfaces might prevent us to use the full width or height.
This explain the most recent addition of the two preferred_buffer_scale
and preferred_scale events to the protocols.

The recommended way is to first ask for a layer_shell surface anchored
to the four anchors (top, right, bottom, left). The received configure
event would then give us the whole available geometry. We now can
prepare our future keyboard, and then we make sure we receive the
expected widht and height with its configure event.

This patch drop all of our wl_output management. To receive the surface
scale value, we upgrade the used Wayland protocol version to 6, to
receive the event wl_surface.preferred_buffer_scale. This drop lot of
code.

This repurpose the function show(), hide(), flip_landscape() (renamed
to redimension_keyboard()), because their behavior was too much
intricated.

Signed-off-by: Willow Barraco <contact@willowbarraco.fr>
Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2026-01-14 22:01:48 +01:00
6 changed files with 254 additions and 239 deletions

22
.build.yml Normal file
View File

@@ -0,0 +1,22 @@
arch: x86_64
image: alpine/edge
packages:
- fontconfig
- wayland-dev
- libxkbcommon-dev
- pango-dev
- scdoc
- clang21-extra-tools # needed for formatting
sources:
- https://git.sr.ht/~proycon/wvkbd
triggers:
- action: email
condition: failure
to: "~mil/sxmo-devel@lists.sr.ht"
tasks:
- format: |
cd wvkbd
make format
- build: |
cd wvkbd
make

6
.gitignore vendored
View File

@@ -5,8 +5,6 @@
include/config.h
.gdb_history
*.log
wvkbd
*.1
config.h
wvkbd-mobintl
wvkbd-deskintl
build-*/*
wvkbd-*

View File

@@ -1,5 +1,7 @@
include config.mk
BUILDDIR=build-${LAYOUT}
NAME=wvkbd
BIN=${NAME}-${LAYOUT}
SRC=.
@@ -9,6 +11,7 @@ PKGS = wayland-client xkbcommon pangocairo
WVKBD_SOURCES += $(wildcard $(SRC)/*.c)
WVKBD_HEADERS += $(wildcard $(SRC)/*.h)
WVKBD_DIR_SOURCES = $(foreach src, $(WVKBD_SOURCES), $(addprefix $(BUILDDIR)/, $(src)))
PKG_CONFIG ?= pkg-config
CFLAGS += -std=gnu99 -Wall -g -DWITH_WAYLAND_SHM -DLAYOUT=\"layout.${LAYOUT}.h\" -DKEYMAP=\"keymap.${LAYOUT}.h\"
@@ -20,16 +23,21 @@ WAYLAND_HEADERS = $(wildcard proto/*.xml)
HDRS = $(WAYLAND_HEADERS:.xml=-client-protocol.h)
WAYLAND_SRC = $(HDRS:.h=.c)
SOURCES = $(WVKBD_SOURCES) $(WAYLAND_SRC)
OBJECTS = $(WVKBD_DIR_SOURCES:.c=.o) $(WAYLAND_SRC:.c=.o)
SCDOC=scdoc
DOCS = wvkbd.1
OBJECTS = $(SOURCES:.c=.o)
all: ${BIN} ${DOCS}
config.h:
cp config.${LAYOUT}.h config.h
$(BUILDDIR)/config.h:
mkdir -p $(BUILDDIR)
cp config.$(LAYOUT).h $@
$(BUILDDIR)/%.o: %.c
mkdir -p $(BUILDDIR)
$(CC) -I $(CURDIR) -I $(CURDIR)/$(BUILDDIR) -c $(CFLAGS) -o $@ $<
proto/%-client-protocol.c: proto/%.xml
wayland-scanner code < $? > $@
@@ -39,11 +47,11 @@ proto/%-client-protocol.h: proto/%.xml
$(OBJECTS): $(HDRS) $(WVKBD_HEADERS)
wvkbd-${LAYOUT}: config.h $(OBJECTS) layout.${LAYOUT}.h
wvkbd-${LAYOUT}: $(BUILDDIR)/config.h $(OBJECTS) layout.${LAYOUT}.h
$(CC) -o wvkbd-${LAYOUT} $(OBJECTS) $(LDFLAGS)
clean:
rm -f $(OBJECTS) config.h $(HDRS) $(WAYLAND_SRC) ${BIN} ${DOCS}
rm -rf "$(BUILDDIR)" wvkbd-$(LAYOUT)
format:
clang-format -i $(WVKBD_SOURCES) $(WVKBD_HEADERS)

View File

@@ -1,4 +1,4 @@
VERSION = 0.18
VERSION = 0.19.2
CFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=700
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man

View File

@@ -274,12 +274,28 @@ kbd_get_layer_index(struct kbd *kb, struct layout *l)
return 0;
}
void
zwp_virtual_keyboard_v1_key_mods(struct zwp_virtual_keyboard_v1 *vkbd, uint32_t time, uint32_t mods, enum wl_keyboard_key_state state)
{
if ((mods & Shift) == Shift)
zwp_virtual_keyboard_v1_key(vkbd, time, KEY_LEFTSHIFT, state);
if ((mods & CapsLock) == CapsLock)
zwp_virtual_keyboard_v1_key(vkbd, time, KEY_CAPSLOCK, state);
if ((mods & Ctrl) == Ctrl)
zwp_virtual_keyboard_v1_key(vkbd, time, KEY_LEFTCTRL, state);
if ((mods & Alt) == Alt)
zwp_virtual_keyboard_v1_key(vkbd, time, KEY_LEFTALT, state);
if ((mods & Super) == Super)
zwp_virtual_keyboard_v1_key(vkbd, time, KEY_LEFTMETA, state);
if ((mods & AltGr) == AltGr)
zwp_virtual_keyboard_v1_key(vkbd, time, KEY_RIGHTALT, state);
}
void
kbd_unpress_key(struct kbd *kb, uint32_t time)
{
bool unlatch_shift, unlatch_ctrl, unlatch_alt, unlatch_super, unlatch_altgr;
unlatch_shift = unlatch_ctrl = unlatch_alt = unlatch_super = unlatch_altgr = false;
bool unlatch_shift, unlatch_ctrl, unlatch_alt, unlatch_super, unlatch_altgr, unlatch_tab;
unlatch_shift = unlatch_ctrl = unlatch_alt = unlatch_super = unlatch_altgr = unlatch_tab = false;
if (kb->last_press) {
unlatch_shift = (kb->mods & Shift) == Shift;
unlatch_ctrl = (kb->mods & Ctrl) == Ctrl;
@@ -287,22 +303,15 @@ kbd_unpress_key(struct kbd *kb, uint32_t time)
unlatch_super = (kb->mods & Super) == Super;
unlatch_altgr = (kb->mods & AltGr) == AltGr;
if (unlatch_shift) kb->mods ^= Shift;
if (unlatch_ctrl) kb->mods ^= Ctrl;
if (unlatch_alt) kb->mods ^= Alt;
if (unlatch_super) kb->mods ^= Super;
if (unlatch_altgr) kb->mods ^= AltGr;
if (unlatch_shift||unlatch_ctrl||unlatch_alt||unlatch_super||unlatch_altgr) {
zwp_virtual_keyboard_v1_modifiers(kb->vkbd, kb->mods, 0, 0, 0);
}
if (kb->last_press->type == Copy) {
zwp_virtual_keyboard_v1_key(kb->vkbd, time, 127, // COMP key
WL_KEYBOARD_KEY_STATE_RELEASED);
} else {
if ((kb->shift_space_is_tab) && (kb->last_press->code == KEY_SPACE) && (unlatch_shift)) {
// shift + space is tab
unlatch_shift = false;
unlatch_tab = true;
kb->mods ^= Shift;
zwp_virtual_keyboard_v1_key(kb->vkbd, time, KEY_TAB,
WL_KEYBOARD_KEY_STATE_RELEASED);
} else {
@@ -312,10 +321,35 @@ kbd_unpress_key(struct kbd *kb, uint32_t time)
}
}
if (unlatch_shift) {
kb->mods ^= Shift;
zwp_virtual_keyboard_v1_key_mods(kb->vkbd, time, Shift, WL_KEYBOARD_KEY_STATE_RELEASED);
}
if (unlatch_ctrl) {
kb->mods ^= Ctrl;
zwp_virtual_keyboard_v1_key_mods(kb->vkbd, time, Ctrl, WL_KEYBOARD_KEY_STATE_RELEASED);
}
if (unlatch_alt) {
kb->mods ^= Alt;
zwp_virtual_keyboard_v1_key_mods(kb->vkbd, time, Alt, WL_KEYBOARD_KEY_STATE_RELEASED);
}
if (unlatch_super) {
kb->mods ^= Super;
zwp_virtual_keyboard_v1_key_mods(kb->vkbd, time, Super, WL_KEYBOARD_KEY_STATE_RELEASED);
}
if (unlatch_altgr) {
kb->mods ^= AltGr;
zwp_virtual_keyboard_v1_key_mods(kb->vkbd, time, AltGr, WL_KEYBOARD_KEY_STATE_RELEASED);
}
if (unlatch_shift||unlatch_ctrl||unlatch_alt||unlatch_super||unlatch_altgr||unlatch_tab) {
zwp_virtual_keyboard_v1_modifiers(kb->vkbd, kb->mods, 0, 0, 0);
}
if (kb->compose >= 2) {
kb->compose = 0;
kbd_switch_layout(kb, kb->last_abc_layout, kb->last_abc_index);
} else if (unlatch_shift||unlatch_ctrl||unlatch_alt||unlatch_super||unlatch_altgr) {
} else if (unlatch_shift||unlatch_ctrl||unlatch_alt||unlatch_super||unlatch_altgr||unlatch_tab) {
kbd_draw_layout(kb);
} else {
kbd_draw_key(kb, kb->last_press, Unpress);
@@ -392,6 +426,7 @@ kbd_press_key(struct kbd *kb, struct key *k, uint32_t time)
switch (k->type) {
case Code:
if (k->code_mod) {
zwp_virtual_keyboard_v1_key_mods(kb->vkbd, time, k->code_mod, WL_KEYBOARD_KEY_STATE_PRESSED);
if (k->reset_mod) {
zwp_virtual_keyboard_v1_modifiers(kb->vkbd, k->code_mod, 0, 0,
0);
@@ -406,7 +441,8 @@ kbd_press_key(struct kbd *kb, struct key *k, uint32_t time)
kbd_draw_key(kb, k, Press);
if ((kb->shift_space_is_tab) && (k->code == KEY_SPACE) && (kb->mods & Shift)) {
// shift space is tab
zwp_virtual_keyboard_v1_modifiers(kb->vkbd, 0, 0, 0, 0);
zwp_virtual_keyboard_v1_key_mods(kb->vkbd, time, Shift, WL_KEYBOARD_KEY_STATE_RELEASED);
zwp_virtual_keyboard_v1_modifiers(kb->vkbd, kb->mods ^ Shift, 0, 0, 0);
zwp_virtual_keyboard_v1_key(kb->vkbd, time, KEY_TAB,
WL_KEYBOARD_KEY_STATE_PRESSED);
} else {
@@ -423,6 +459,11 @@ kbd_press_key(struct kbd *kb, struct key *k, uint32_t time)
break;
case Mod:
kb->mods ^= k->code;
if (kb->mods & k->code) {
zwp_virtual_keyboard_v1_key_mods(kb->vkbd, time, k->code, WL_KEYBOARD_KEY_STATE_PRESSED);
} else {
zwp_virtual_keyboard_v1_key_mods(kb->vkbd, time, k->code, WL_KEYBOARD_KEY_STATE_RELEASED);
}
if ((k->code == Shift) || (k->code == CapsLock)) {
kbd_draw_layout(kb);
} else {

374
main.c
View File

@@ -47,18 +47,10 @@ static struct wp_fractional_scale_manager_v1 *wfs_mgr;
static struct wp_viewport *draw_surf_viewport, *popup_draw_surf_viewport;
static struct wp_viewporter *viewporter;
static bool popup_xdg_surface_configured;
static bool layer_surface_configured;
struct Output {
uint32_t name;
uint32_t w, h;
double scale;
struct wl_output *data;
};
static struct Output *current_output;
#define WL_OUTPUTS_LIMIT 8
static struct Output wl_outputs[WL_OUTPUTS_LIMIT];
static int wl_outputs_size;
static uint32_t available_width, available_height = 0;
static void refresh_available_dimension();
/* drawing */
static struct drw draw_ctx;
@@ -116,11 +108,6 @@ static void 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);
static void wl_surface_enter(void *data, struct wl_surface *wl_surface,
struct wl_output *wl_output);
static void wl_surface_leave(void *data, struct wl_surface *wl_surface,
struct wl_output *wl_output);
static void handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface,
uint32_t version);
@@ -132,8 +119,9 @@ static void layer_surface_configure(void *data,
uint32_t serial, uint32_t w, uint32_t h);
static void layer_surface_closed(void *data,
struct zwlr_layer_surface_v1 *surface);
static void flip_landscape();
static void redimension_keyboard();
static void show();
static void hide();
/* event handlers */
static const struct wl_pointer_listener pointer_listener = {
@@ -159,9 +147,33 @@ static const struct wl_seat_listener seat_listener = {
.name = seat_handle_name,
};
void
wl_surface_enter(void *data, struct wl_surface *wl_surface,
struct wl_output *wl_output)
{
}
void
wl_surface_leave(void *data, struct wl_surface *wl_surface,
struct wl_output *wl_output) {
}
void
wl_preferred_buffer_scale(void *data, struct wl_surface *wl_surface,
int scale) {
keyboard.preferred_scale = scale;
}
void
wl_preferred_buffer_transform(void *data, struct wl_surface *wl_surface,
uint32_t transform) {
}
static const struct wl_surface_listener surface_listener = {
.enter = wl_surface_enter,
.leave = wl_surface_leave,
.preferred_buffer_scale = wl_preferred_buffer_scale,
.preferred_buffer_transform = wl_preferred_buffer_transform,
};
static const struct wl_registry_listener registry_listener = {
@@ -169,6 +181,25 @@ static const struct wl_registry_listener registry_listener = {
.global_remove = handle_global_remove,
};
void
initiate_configure(void *data, struct zwlr_layer_surface_v1 *surface,
uint32_t serial, uint32_t w, uint32_t h)
{
available_width = w;
available_height = h;
zwlr_layer_surface_v1_ack_configure(surface, serial);
}
void
initiate_closed(void *data, struct zwlr_layer_surface_v1 *surface)
{
}
static const struct zwlr_layer_surface_v1_listener initiate_listener = {
.configure = initiate_configure,
.closed = initiate_closed,
};
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
.configure = layer_surface_configure,
.closed = layer_surface_closed,
@@ -194,7 +225,7 @@ wl_touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial,
uint32_t time, struct wl_surface *surface, int32_t id,
wl_fixed_t x, wl_fixed_t y)
{
if(!popup_xdg_surface_configured) {
if(!layer_surface_configured || !popup_xdg_surface_configured) {
return;
}
@@ -220,7 +251,7 @@ void
wl_touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial,
uint32_t time, int32_t id)
{
if(!popup_xdg_surface_configured) {
if(!layer_surface_configured || !popup_xdg_surface_configured) {
return;
}
@@ -231,7 +262,7 @@ void
wl_touch_motion(void *data, struct wl_touch *wl_touch, uint32_t time,
int32_t id, wl_fixed_t x, wl_fixed_t y)
{
if(!popup_xdg_surface_configured) {
if(!layer_surface_configured || !popup_xdg_surface_configured) {
return;
}
@@ -283,7 +314,7 @@ void
wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time,
wl_fixed_t surface_x, wl_fixed_t surface_y)
{
if(!popup_xdg_surface_configured) {
if(!layer_surface_configured || !popup_xdg_surface_configured) {
return;
}
@@ -299,7 +330,7 @@ void
wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
uint32_t time, uint32_t button, uint32_t state)
{
if(!popup_xdg_surface_configured) {
if(!layer_surface_configured || !popup_xdg_surface_configured) {
return;
}
@@ -328,7 +359,7 @@ void
wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time,
uint32_t axis, wl_fixed_t value)
{
if(!popup_xdg_surface_configured) {
if(!layer_surface_configured || !popup_xdg_surface_configured) {
return;
}
@@ -368,82 +399,6 @@ seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name)
{
}
void
wl_surface_enter(void *data, struct wl_surface *wl_surface,
struct wl_output *wl_output)
{
struct Output *old_output = current_output;
for (int i = 0; i < wl_outputs_size; i += 1) {
if (wl_outputs[i].data == wl_output) {
current_output = &wl_outputs[i];
break;
}
}
if (current_output == old_output) {
return;
}
keyboard.preferred_scale = current_output->scale;
flip_landscape();
}
void
wl_surface_leave(void *data, struct wl_surface *wl_surface,
struct wl_output *wl_output) {
}
static void
display_handle_geometry(void *data, struct wl_output *wl_output, int x, int y,
int physical_width, int physical_height, int subpixel,
const char *make, const char *model, int transform)
{
struct Output *output = data;
// Swap width and height on rotated displays
if (transform % 2 != 0) {
int tmp = physical_width;
physical_width = physical_height;
physical_height = tmp;
}
output->w = physical_width;
output->h = physical_height;
if (current_output == output) {
flip_landscape();
};
}
static void
display_handle_done(void *data, struct wl_output *wl_output)
{
}
static void
display_handle_scale(void *data, struct wl_output *wl_output, int32_t scale)
{
struct Output *output = data;
output->scale = scale;
if (current_output == output) {
keyboard.preferred_scale = scale;
flip_landscape();
};
}
static void
display_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags,
int width, int height, int refresh)
{
}
static const struct wl_output_listener output_listener = {
.geometry = display_handle_geometry,
.mode = display_handle_mode,
.done = display_handle_done,
.scale = display_handle_scale};
static void
xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
{
@@ -460,19 +415,9 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name,
{
if (strcmp(interface, wl_compositor_interface.name) == 0) {
compositor =
wl_registry_bind(registry, name, &wl_compositor_interface, 3);
wl_registry_bind(registry, name, &wl_compositor_interface, 6);
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
draw_ctx.shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
} else if (strcmp(interface, wl_output_interface.name) == 0) {
if (wl_outputs_size < WL_OUTPUTS_LIMIT) {
struct Output *output = &wl_outputs[wl_outputs_size];
output->data =
wl_registry_bind(registry, name, &wl_output_interface, 2);
output->name = name;
output->scale = 1;
wl_output_add_listener(output->data, &output_listener, output);
wl_outputs_size += 1;
}
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
seat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
wl_seat_add_listener(seat, &seat_listener, NULL);
@@ -499,16 +444,6 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name,
void
handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
{
for (int i = 0; i < wl_outputs_size; i += 1) {
if (wl_outputs[i].name == name) {
wl_output_destroy(wl_outputs[i].data);
for (; i < wl_outputs_size - 1; i += 1) {
wl_outputs[i] = wl_outputs[i + 1];
}
wl_outputs_size -= 1;
break;
}
}
}
static void
@@ -554,15 +489,9 @@ static const struct wp_fractional_scale_v1_listener
};
void
flip_landscape()
redimension_keyboard()
{
bool previous_landscape = keyboard.landscape;
if (current_output) {
keyboard.landscape = current_output->w > current_output->h;
} else if (wl_outputs_size) {
keyboard.landscape = wl_outputs[0].w > wl_outputs[0].h;
}
keyboard.landscape = available_width > available_height;
enum layout_id layer;
if (keyboard.landscape) {
@@ -573,102 +502,80 @@ flip_landscape()
height = normal_height;
}
keyboard.w = available_width;
keyboard.h = height;
keyboard.layout = &keyboard.layouts[layer];
keyboard.layer_index = 0;
keyboard.prevlayout = keyboard.layout;
keyboard.last_abc_layout = keyboard.layout;
keyboard.last_abc_index = 0;
if (layer_surface && previous_landscape != keyboard.landscape) {
if (popup_xdg_popup) {
xdg_popup_destroy(popup_xdg_popup);
popup_xdg_popup = NULL;
}
if (popup_xdg_surface) {
xdg_surface_destroy(popup_xdg_surface);
popup_xdg_surface = NULL;
}
if (popup_draw_surf.surf) {
wl_surface_destroy(popup_draw_surf.surf);
popup_draw_surf.surf = NULL;
}
zwlr_layer_surface_v1_destroy(layer_surface);
layer_surface = NULL;
wl_surface_destroy(draw_surf.surf);
show();
}
}
void
layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface,
uint32_t serial, uint32_t w, uint32_t h)
{
// Swallow events for old/destroyed surface
if (surface != layer_surface) {
zwlr_layer_surface_v1_ack_configure(surface, serial);
return;
};
// Not what we expected, or redimension, refresh and restart
if (keyboard.w != w || keyboard.h != h) {
zwlr_layer_surface_v1_ack_configure(surface, serial);
hide();
show();
return;
};
// Swallow useless events
if (layer_surface_configured) {
return;
};
layer_surface_configured = true;
double scale = keyboard.preferred_scale;
if (keyboard.preferred_fractional_scale) {
scale = keyboard.preferred_fractional_scale;
}
if (keyboard.w != w || keyboard.h != h || keyboard.scale != scale ||
keyboard.output != current_output || hidden) {
keyboard.scale = scale;
hidden = false;
keyboard.w = w;
keyboard.h = h;
keyboard.scale = scale;
hidden = false;
if (wfs_mgr && viewporter) {
wp_viewport_set_destination(draw_surf_viewport, keyboard.w,
keyboard.h);
} else {
wl_surface_set_buffer_scale(draw_surf.surf, keyboard.scale);
}
if (popup_xdg_popup) {
xdg_popup_destroy(popup_xdg_popup);
}
if (popup_xdg_surface) {
xdg_surface_destroy(popup_xdg_surface);
}
if (popup_draw_surf.surf) {
wl_surface_destroy(popup_draw_surf.surf);
}
popup_draw_surf.surf = wl_compositor_create_surface(compositor);
xdg_positioner_set_size(popup_xdg_positioner, w, h * 2);
xdg_positioner_set_anchor_rect(popup_xdg_positioner, 0, -h, w, h * 2);
wl_surface_set_input_region(popup_draw_surf.surf, empty_region);
popup_xdg_surface =
xdg_wm_base_get_xdg_surface(wm_base, popup_draw_surf.surf);
popup_xdg_surface_configured = false;
xdg_surface_add_listener(popup_xdg_surface, &xdg_popup_surface_listener,
NULL);
popup_xdg_popup = xdg_surface_get_popup(popup_xdg_surface, NULL,
popup_xdg_positioner);
xdg_popup_add_listener(popup_xdg_popup, &xdg_popup_listener, NULL);
zwlr_layer_surface_v1_get_popup(layer_surface, popup_xdg_popup);
if (wfs_mgr && viewporter) {
popup_draw_surf_viewport =
wp_viewporter_get_viewport(viewporter, popup_draw_surf.surf);
wp_viewport_set_destination(popup_draw_surf_viewport, keyboard.w,
keyboard.h * 2);
} else {
wl_surface_set_buffer_scale(popup_draw_surf.surf, keyboard.scale);
}
wl_surface_commit(popup_draw_surf.surf);
zwlr_layer_surface_v1_ack_configure(surface, serial);
kbd_resize(&keyboard, layouts, NumLayouts);
drwsurf_attach(&draw_surf);
keyboard.output = current_output;
if (wfs_mgr && viewporter) {
wp_viewport_set_destination(draw_surf_viewport, keyboard.w,
keyboard.h);
} else {
zwlr_layer_surface_v1_ack_configure(surface, serial);
wl_surface_set_buffer_scale(draw_surf.surf, keyboard.scale);
}
popup_draw_surf.surf = wl_compositor_create_surface(compositor);
xdg_positioner_set_size(popup_xdg_positioner, w, h * 2);
xdg_positioner_set_anchor_rect(popup_xdg_positioner, 0, -h, w, h * 2);
wl_surface_set_input_region(popup_draw_surf.surf, empty_region);
popup_xdg_surface = xdg_wm_base_get_xdg_surface(wm_base, popup_draw_surf.surf);
popup_xdg_surface_configured = false;
xdg_surface_add_listener(popup_xdg_surface, &xdg_popup_surface_listener, NULL);
popup_xdg_popup = xdg_surface_get_popup(popup_xdg_surface, NULL, popup_xdg_positioner);
xdg_popup_add_listener(popup_xdg_popup, &xdg_popup_listener, NULL);
zwlr_layer_surface_v1_get_popup(layer_surface, popup_xdg_popup);
if (wfs_mgr && viewporter) {
popup_draw_surf_viewport = wp_viewporter_get_viewport(viewporter, popup_draw_surf.surf);
wp_viewport_set_destination(popup_draw_surf_viewport, keyboard.w, keyboard.h * 2);
} else {
wl_surface_set_buffer_scale(popup_draw_surf.surf, keyboard.scale);
}
wl_surface_commit(popup_draw_surf.surf);
zwlr_layer_surface_v1_ack_configure(surface, serial);
kbd_resize(&keyboard, layouts, NumLayouts);
drwsurf_attach(&draw_surf);
}
void
@@ -740,18 +647,40 @@ hide()
return;
}
if(wfs_draw_surf) {
if (wfs_draw_surf) {
wp_fractional_scale_v1_destroy(wfs_draw_surf);
wfs_draw_surf = NULL;
}
if(draw_surf_viewport) {
if (draw_surf_viewport) {
wp_viewport_destroy(draw_surf_viewport);
draw_surf_viewport = NULL;
}
if (popup_xdg_popup) {
xdg_popup_destroy(popup_xdg_popup);
popup_xdg_popup = NULL;
}
if (popup_xdg_surface) {
xdg_surface_destroy(popup_xdg_surface);
popup_xdg_surface = NULL;
}
if (popup_draw_surf.surf) {
wl_surface_destroy(popup_draw_surf.surf);
popup_draw_surf.surf = NULL;
}
zwlr_layer_surface_v1_destroy(layer_surface);
wl_surface_destroy(draw_surf.surf);
layer_surface = NULL;
layer_surface_configured = false;
// Cancel pending frame callback before destroying surface
if (draw_surf.frame_cb) {
wl_callback_destroy(draw_surf.frame_cb);
draw_surf.frame_cb = NULL;
}
wl_surface_destroy(draw_surf.surf);
draw_surf.attached = false;
hidden = true;
}
@@ -762,12 +691,12 @@ show()
return;
}
wl_display_sync(display);
flip_landscape();
refresh_available_dimension();
redimension_keyboard();
draw_surf.surf = wl_compositor_create_surface(compositor);
wl_surface_add_listener(draw_surf.surf, &surface_listener, NULL);
wl_surface_add_listener(
draw_surf.surf, &surface_listener, NULL);
if (wfs_mgr && viewporter) {
wfs_draw_surf = wp_fractional_scale_manager_v1_get_fractional_scale(
wfs_mgr, draw_surf.surf);
@@ -778,8 +707,6 @@ show()
}
struct wl_output *current_output_data = NULL;
if (current_output)
current_output_data = current_output->data;
layer_surface = zwlr_layer_shell_v1_get_layer_surface(
layer_shell, draw_surf.surf, current_output_data, layer, namespace);
@@ -830,6 +757,25 @@ set_kbd_colors(uint8_t *bgra, char *hex)
}
}
void
refresh_available_dimension()
{
struct wl_surface *surface = wl_compositor_create_surface(compositor);
struct zwlr_layer_surface_v1 *layer_surface = zwlr_layer_shell_v1_get_layer_surface(
layer_shell, surface, NULL, layer, namespace);
zwlr_layer_surface_v1_set_anchor(layer_surface,
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT);
zwlr_layer_surface_v1_add_listener(layer_surface, &initiate_listener, NULL);
wl_surface_commit(surface);
wl_display_roundtrip(display);
zwlr_layer_surface_v1_destroy(layer_surface);
wl_surface_destroy(surface);
wl_display_roundtrip(display);
}
int
main(int argc, char **argv)
{