Skip to content

Commit

Permalink
[wayland] Improved scaling handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
Apprentice-Alchemist committed Jun 25, 2024
1 parent 1cd06ab commit dd18990
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 56 deletions.
8 changes: 6 additions & 2 deletions Backends/System/Linux/Sources/kinc/backend/wayland/system.c.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include "kinc/math/core.h"
#include "wayland-generated/wayland-fractional-scale.h"
#include "wayland.h"

#include <kinc/input/pen.h>
Expand Down Expand Up @@ -280,7 +282,7 @@ void wl_pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, uint32_
case KINC_WL_DECORATION_FOCUS_BOTTOM:
if (x < 10)
cursor_name = "sw-resize";
else if (x > window->width + 10)
else if (x > window->surface_width + 10)
cursor_name = "se-resize";
else
cursor_name = "s-resize";
Expand Down Expand Up @@ -942,7 +944,7 @@ static const struct zwp_tablet_seat_v2_listener zwp_tablet_seat_v2_listener = {

static void wl_registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) {
if (strcmp(interface, wl_compositor_interface.name) == 0) {
wl_ctx.compositor = wl_registry_bind(wl_ctx.registry, name, &wl_compositor_interface, 4);
wl_ctx.compositor = wl_registry_bind(wl_ctx.registry, name, &wl_compositor_interface, kinc_mini(version, 6));
}
else if (strcmp(interface, wl_shm_interface.name) == 0) {
wl_ctx.shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
Expand Down Expand Up @@ -1012,6 +1014,8 @@ static void wl_registry_handle_global(void *data, struct wl_registry *registry,
}
else if (strcmp(interface, zwp_relative_pointer_manager_v1_interface.name) == 0) {
wl_ctx.relative_pointer_manager = wl_registry_bind(registry, name, &zwp_relative_pointer_manager_v1_interface, 1);
} else if(strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == 0) {
wl_ctx.fractional_scale_manager = wl_registry_bind(registry, name, &wp_fractional_scale_manager_v1_interface, 1);
}
}

Expand Down
28 changes: 19 additions & 9 deletions Backends/System/Linux/Sources/kinc/backend/wayland/wayland.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ struct kinc_wl_procs {
extern struct kinc_wl_procs wl;

#include <wayland-client-protocol.h>
#include <wayland-generated/wayland-fractional-scale.h>
#include <wayland-generated/wayland-pointer-constraint.h>
#include <wayland-generated/wayland-relative-pointer.h>
#include <wayland-generated/wayland-tablet.h>
Expand Down Expand Up @@ -150,39 +151,47 @@ enum kinc_wl_decoration_focus {

#define KINC_WL_DECORATION_TOP_X 0
#define KINC_WL_DECORATION_TOP_Y -(KINC_WL_DECORATION_TOP_HEIGHT)
#define KINC_WL_DECORATION_TOP_WIDTH window->width
#define KINC_WL_DECORATION_TOP_WIDTH window->surface_width
#define KINC_WL_DECORATION_TOP_HEIGHT KINC_WL_DECORATION_WIDTH * 3

#define KINC_WL_DECORATION_LEFT_X -10
#define KINC_WL_DECORATION_LEFT_Y -(KINC_WL_DECORATION_TOP_HEIGHT)
#define KINC_WL_DECORATION_LEFT_WIDTH KINC_WL_DECORATION_WIDTH
#define KINC_WL_DECORATION_LEFT_HEIGHT window->height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT
#define KINC_WL_DECORATION_LEFT_HEIGHT window->surface_height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT

#define KINC_WL_DECORATION_RIGHT_X window->width
#define KINC_WL_DECORATION_RIGHT_X window->surface_width
#define KINC_WL_DECORATION_RIGHT_Y -(KINC_WL_DECORATION_TOP_HEIGHT)
#define KINC_WL_DECORATION_RIGHT_WIDTH 10
#define KINC_WL_DECORATION_RIGHT_HEIGHT window->height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT
#define KINC_WL_DECORATION_RIGHT_HEIGHT window->surface_height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT

#define KINC_WL_DECORATION_BOTTOM_X 0
#define KINC_WL_DECORATION_BOTTOM_Y window->height
#define KINC_WL_DECORATION_BOTTOM_WIDTH window->width
#define KINC_WL_DECORATION_BOTTOM_Y window->surface_height
#define KINC_WL_DECORATION_BOTTOM_WIDTH window->surface_width
#define KINC_WL_DECORATION_BOTTOM_HEIGHT KINC_WL_DECORATION_WIDTH

#define KINC_WL_DECORATION_CLOSE_X window->width - 10
#define KINC_WL_DECORATION_CLOSE_X window->surface_width - 10
#define KINC_WL_DECORATION_CLOSE_Y -20
#define KINC_WL_DECORATION_CLOSE_WIDTH 9
#define KINC_WL_DECORATION_CLOSE_HEIGHT 9

struct kinc_wl_window {
int display_index;
int window_id;
int width;
int height;
int surface_width;
int surface_height;

int buffer_width;
int buffer_height;

kinc_window_mode_t mode;
struct wl_surface *surface;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *toplevel;
struct zxdg_toplevel_decoration_v1 *xdg_decoration;
struct wp_fractional_scale_v1 *fractional_scale;
struct wp_viewport *viewport;

uint32_t preferred_scale;

bool configured;

Expand Down Expand Up @@ -347,6 +356,7 @@ struct wayland_context {
struct zwp_tablet_manager_v2 *tablet_manager;
struct zwp_pointer_constraints_v1 *pointer_constraints;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
struct wp_fractional_scale_manager_v1 *fractional_scale_manager;
struct wl_cursor_theme *cursor_theme;
int cursor_size;
int num_windows;
Expand Down
151 changes: 106 additions & 45 deletions Backends/System/Linux/Sources/kinc/backend/wayland/window.c.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <kinc/image.h>
#include <kinc/window.h>
#include <kinc/log.h>

// for all that shared memory stuff later on
#include <errno.h>
Expand All @@ -27,17 +28,17 @@ void kinc_wayland_destroy_decoration(struct kinc_wl_decoration *);
void kinc_wayland_resize_decoration(struct kinc_wl_decoration *, int x, int y, int width, int height);
static void xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *toplevel, int32_t width, int32_t height, struct wl_array *states) {
struct kinc_wl_window *window = data;
if ((width <= 0 || height <= 0) || (width == window->width + (KINC_WL_DECORATION_WIDTH * 2) &&
height == window->height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT)) {
return;
}
if (window->decorations.server_side) {
window->width = width;
window->height = height;
}
else {
window->width = width - (KINC_WL_DECORATION_WIDTH * 2);
window->height = height - KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT;
if(width > 0 && height > 0) {
if (window->decorations.server_side) {
window->surface_width = width;
window->surface_height = height;
}
else {
window->surface_width = width - (KINC_WL_DECORATION_WIDTH * 2);
window->surface_height = height - KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT;
}
window->buffer_width = window->surface_width * window->preferred_scale / 120;
window->buffer_height = window->surface_height * window->preferred_scale / 120;
}

enum xdg_toplevel_state *state;
Expand All @@ -54,30 +55,41 @@ static void xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *tople
break;
}
}
kinc_internal_resize(window->window_id, window->width, window->height);
kinc_internal_call_resize_callback(window->window_id, window->width, window->height);
if (window->decorations.server_side) {
xdg_surface_set_window_geometry(window->xdg_surface, 0, 0, window->width, window->height);
}
else {
xdg_surface_set_window_geometry(window->xdg_surface, KINC_WL_DECORATION_LEFT_X, KINC_WL_DECORATION_TOP_Y,
window->width + (KINC_WL_DECORATION_WIDTH * 2),
window->height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT);
}

if (window->surface_width > 0 && window->surface_height > 0) {
if (window->decorations.server_side) {
xdg_surface_set_window_geometry(window->xdg_surface, 0, 0, window->surface_width, window->surface_height);
}
else {
xdg_surface_set_window_geometry(window->xdg_surface, KINC_WL_DECORATION_LEFT_X, KINC_WL_DECORATION_TOP_Y,
window->surface_width + (KINC_WL_DECORATION_WIDTH * 2),
window->surface_height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT);
}
if (window->viewport) {
wp_viewport_set_source(window->viewport, 0, 0, wl_fixed_from_int(window->buffer_width), wl_fixed_from_int(window->buffer_height));
wp_viewport_set_destination(window->viewport, window->surface_width, window->surface_height);
}
else {
wl_surface_set_buffer_scale(window->surface, window->preferred_scale / 120);
}

kinc_internal_resize(window->window_id, window->buffer_width, window->buffer_height);
kinc_internal_call_resize_callback(window->window_id, window->buffer_width, window->buffer_height);
#ifdef KINC_EGL
wl_egl_window_resize(window->egl_window, window->width, window->height, 0, 0);
wl_egl_window_resize(window->egl_window, window->buffer_width, window->buffer_height, 0, 0);
#endif

kinc_wayland_resize_decoration(&window->decorations.top, KINC_WL_DECORATION_TOP_X, KINC_WL_DECORATION_TOP_Y, KINC_WL_DECORATION_TOP_WIDTH,
KINC_WL_DECORATION_TOP_HEIGHT);
kinc_wayland_resize_decoration(&window->decorations.left, KINC_WL_DECORATION_LEFT_X, KINC_WL_DECORATION_LEFT_Y, KINC_WL_DECORATION_LEFT_WIDTH,
KINC_WL_DECORATION_LEFT_HEIGHT);
kinc_wayland_resize_decoration(&window->decorations.right, KINC_WL_DECORATION_RIGHT_X, KINC_WL_DECORATION_RIGHT_Y, KINC_WL_DECORATION_RIGHT_WIDTH,
KINC_WL_DECORATION_RIGHT_HEIGHT);
kinc_wayland_resize_decoration(&window->decorations.bottom, KINC_WL_DECORATION_BOTTOM_X, KINC_WL_DECORATION_BOTTOM_Y, KINC_WL_DECORATION_BOTTOM_WIDTH,
KINC_WL_DECORATION_BOTTOM_HEIGHT);
kinc_wayland_resize_decoration(&window->decorations.close, KINC_WL_DECORATION_CLOSE_X, KINC_WL_DECORATION_CLOSE_Y, KINC_WL_DECORATION_CLOSE_WIDTH,
KINC_WL_DECORATION_CLOSE_HEIGHT);
kinc_wayland_resize_decoration(&window->decorations.top, KINC_WL_DECORATION_TOP_X, KINC_WL_DECORATION_TOP_Y, KINC_WL_DECORATION_TOP_WIDTH,
KINC_WL_DECORATION_TOP_HEIGHT);
kinc_wayland_resize_decoration(&window->decorations.left, KINC_WL_DECORATION_LEFT_X, KINC_WL_DECORATION_LEFT_Y, KINC_WL_DECORATION_LEFT_WIDTH,
KINC_WL_DECORATION_LEFT_HEIGHT);
kinc_wayland_resize_decoration(&window->decorations.right, KINC_WL_DECORATION_RIGHT_X, KINC_WL_DECORATION_RIGHT_Y, KINC_WL_DECORATION_RIGHT_WIDTH,
KINC_WL_DECORATION_RIGHT_HEIGHT);
kinc_wayland_resize_decoration(&window->decorations.bottom, KINC_WL_DECORATION_BOTTOM_X, KINC_WL_DECORATION_BOTTOM_Y, KINC_WL_DECORATION_BOTTOM_WIDTH,
KINC_WL_DECORATION_BOTTOM_HEIGHT);
kinc_wayland_resize_decoration(&window->decorations.close, KINC_WL_DECORATION_CLOSE_X, KINC_WL_DECORATION_CLOSE_Y, KINC_WL_DECORATION_CLOSE_WIDTH,
KINC_WL_DECORATION_CLOSE_HEIGHT);
}
}

void kinc_wayland_window_destroy(int window_index);
Expand Down Expand Up @@ -301,9 +313,23 @@ void wl_surface_handle_enter(void *data, struct wl_surface *wl_surface, struct w

void wl_surface_handle_leave(void *data, struct wl_surface *wl_surface, struct wl_output *output) {}

static void wl_surface_handle_preferred_buffer_scale(void *data, struct wl_surface *wl_surface, int32_t scale) {
struct kinc_wl_window *window = wl_surface_get_user_data(wl_surface);
if (!wl_ctx.fractional_scale_manager) {
window->preferred_scale = scale * 120;
}
}
static void wl_surface_handle_preferred_buffer_transform(void *data, struct wl_surface *wl_surface, uint32_t transform) {}

static const struct wl_surface_listener wl_surface_listener = {
wl_surface_handle_enter,
wl_surface_handle_leave,
#ifdef WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION
wl_surface_handle_preferred_buffer_scale,
#endif
#ifdef WL_SURFACE_PREFERRED_BUFFER_TRANSFORM_SINCE_VERSION
wl_surface_handle_preferred_buffer_transform,
#endif
};

static const struct xdg_surface_listener xdg_surface_listener = {
Expand All @@ -319,6 +345,15 @@ static const struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration
xdg_toplevel_decoration_configure,
};

static void wp_fractional_scale_v1_handle_preferred_scale(void *data, struct wp_fractional_scale_v1 *fractional_scale, uint32_t scale) {
struct kinc_wl_window *window = data;
window->preferred_scale = scale;
}

static const struct wp_fractional_scale_v1_listener wp_fractional_scale_v1_listener = {
wp_fractional_scale_v1_handle_preferred_scale,
};

void kinc_wayland_window_set_title(int window_index, const char *title);
void kinc_wayland_window_change_mode(int window_index, kinc_window_mode_t mode);

Expand All @@ -331,26 +366,36 @@ int kinc_wayland_window_create(kinc_window_options_t *win, kinc_framebuffer_opti
}
}
if (window_index == -1) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Too much windows (maximum is %i)", MAXIMUM_WINDOWS);
kinc_log(KINC_LOG_LEVEL_ERROR, "Too many windows (maximum is %i)", MAXIMUM_WINDOWS);
exit(1);
}
struct kinc_wl_window *window = &wl_ctx.windows[window_index];
window->window_id = window_index;
window->width = win->width;
window->height = win->height;
window->mode = KINC_WINDOW_MODE_WINDOW;
window->mode = -1;
window->preferred_scale = 120;
window->surface = wl_compositor_create_surface(wl_ctx.compositor);
wl_surface_set_user_data(window->surface, window);
wl_surface_add_listener(window->surface, &wl_surface_listener, NULL);

if (wl_ctx.viewporter) {
window->viewport = wp_viewporter_get_viewport(wl_ctx.viewporter, window->surface);
}

if (wl_ctx.fractional_scale_manager) {
if (!window->viewport) {
kinc_log(KINC_LOG_LEVEL_ERROR, "missing wp_viewport wayland extension");
exit(1);
}
window->fractional_scale = wp_fractional_scale_manager_v1_get_fractional_scale(wl_ctx.fractional_scale_manager, window->surface);
wp_fractional_scale_v1_add_listener(window->fractional_scale, &wp_fractional_scale_v1_listener, window);
}

window->xdg_surface = xdg_wm_base_get_xdg_surface(wl_ctx.xdg_wm_base, window->surface);
xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window);

window->toplevel = xdg_surface_get_toplevel(window->xdg_surface);
xdg_toplevel_add_listener(window->toplevel, &xdg_toplevel_listener, window);

kinc_wayland_window_set_title(window_index, win->title);

if (wl_ctx.decoration_manager) {
window->xdg_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(wl_ctx.decoration_manager, window->toplevel);
#ifdef KINC_WAYLAND_FORCE_CSD
Expand All @@ -360,20 +405,36 @@ int kinc_wayland_window_create(kinc_window_options_t *win, kinc_framebuffer_opti
}
else {
window->decorations.server_side = false;
kinc_wayland_create_decorations(window);
}

#ifdef KINC_EGL
window->egl_window = wl_egl_window_create(window->surface, window->width, window->height);
#endif
wl_surface_commit(window->surface);
kinc_wayland_window_change_mode(window_index, win->mode);
wl_ctx.num_windows++;

while (!window->configured) {
wl_display_roundtrip(wl_ctx.display);
}

kinc_wayland_window_set_title(window_index, win->title);
kinc_wayland_window_change_mode(window_index, win->mode);
window->surface_width = (win->width * 120) / window->preferred_scale;
window->surface_height = (win->height * 120) / window->preferred_scale;
window->buffer_width = win->width;
window->buffer_height = win->height;
if (window->viewport) {
wp_viewport_set_source(window->viewport, 0, 0, wl_fixed_from_int(window->buffer_width), wl_fixed_from_int(window->buffer_height));
wp_viewport_set_destination(window->viewport, window->surface_width, window->surface_height);
} else {
wl_surface_set_buffer_scale(window->surface, window->preferred_scale / 120);
}
xdg_surface_set_window_geometry(window->xdg_surface, 0, 0, window->surface_width, window->surface_height);
if(!window->decorations.server_side) {
kinc_wayland_create_decorations(window);
}

#ifdef KINC_EGL
window->egl_window = wl_egl_window_create(window->surface, window->buffer_width, window->buffer_height);
#endif
wl_surface_commit(window->surface);
return window_index;
}

Expand Down Expand Up @@ -413,11 +474,11 @@ void kinc_wayland_window_move(int window_index, int x, int y) {
}

int kinc_wayland_window_width(int window_index) {
return wl_ctx.windows[window_index].width;
return wl_ctx.windows[window_index].buffer_width;
}

int kinc_wayland_window_height(int window_index) {
return wl_ctx.windows[window_index].height;
return wl_ctx.windows[window_index].buffer_height;
}

void kinc_wayland_window_resize(int window_index, int width, int height) {
Expand Down
1 change: 1 addition & 0 deletions kfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ else if (platform === Platform.Linux || platform === Platform.FreeBSD) {
wl_protocol('unstable/tablet/tablet-unstable-v2.xml', 'wayland-tablet');
wl_protocol('unstable/pointer-constraints/pointer-constraints-unstable-v1.xml', 'wayland-pointer-constraint');
wl_protocol('unstable/relative-pointer/relative-pointer-unstable-v1.xml', 'wayland-relative-pointer');
wl_protocol('staging/fractional-scale/fractional-scale-v1.xml', 'wayland-fractional-scale');

if (good_wayland) {
let cfile = '#include "wayland-protocol.c.h"\n';
Expand Down

0 comments on commit dd18990

Please sign in to comment.