mirror of
https://github.com/jjsullivan5196/wvkbd.git
synced 2026-04-09 14:42:30 +02:00
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>
This commit is contained in:
committed by
Maarten van Gompel
parent
ed702f9562
commit
34a33b41fa
348
main.c
348
main.c
@@ -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,
|
||||
@@ -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,74 @@ 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)
|
||||
{
|
||||
// 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 +641,32 @@ 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;
|
||||
wl_surface_destroy(draw_surf.surf);
|
||||
|
||||
hidden = true;
|
||||
}
|
||||
|
||||
@@ -762,12 +677,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 +693,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 +743,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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user