libdecor
Some checks failed
pyrite-dev/milsko/pipeline/head There was a failure building this commit

This commit is contained in:
IoI_xD 2026-04-28 20:17:30 -07:00
commit 8d22109bd1
2 changed files with 228 additions and 240 deletions

View file

@ -15,6 +15,13 @@
#include <cairo/cairo.h> #include <cairo/cairo.h>
#include <pthread.h> #include <pthread.h>
#include <dbus/dbus.h> #include <dbus/dbus.h>
/* libdecor is included later on so that it's covered by the wayland dynloading. */
struct libdecor_frame;
struct libdecor_interface;
struct libdecor_configuration;
struct libdecor_frame_interface;
enum libdecor_window_state;
struct wl_surface;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -44,11 +51,14 @@ typedef struct wayland_call_table {
void* lib; void* lib;
void* xkb_lib; void* xkb_lib;
void* cairo_lib; void* cairo_lib;
void* libdecor_lib;
#ifdef USE_DBUS #ifdef USE_DBUS
MwLLDBusFuncTable dbus; MwLLDBusFuncTable dbus;
MwBool has_dbus; MwBool has_dbus;
#endif #endif
MwBool has_libdecor;
int (*wl_display_dispatch)(struct wl_display* display); int (*wl_display_dispatch)(struct wl_display* display);
int (*wl_display_dispatch_pending)(struct wl_display* display); int (*wl_display_dispatch_pending)(struct wl_display* display);
void (*wl_display_disconnect)(struct wl_display* display); void (*wl_display_disconnect)(struct wl_display* display);
@ -141,6 +151,18 @@ typedef struct wayland_call_table {
void (*cairo_set_antialias)(cairo_t*, cairo_antialias_t); void (*cairo_set_antialias)(cairo_t*, cairo_antialias_t);
void (*cairo_set_operator)(cairo_t* cr, cairo_operator_t op); void (*cairo_set_operator)(cairo_t* cr, cairo_operator_t op);
struct libdecor* (*libdecor_new)(struct wl_display* display, struct libdecor_interface* iface);
struct libdecor_state* (*libdecor_state_new)(int width, int height);
void (*libdecor_frame_commit)(struct libdecor_frame* frame, struct libdecor_state* state, struct libdecor_configuration* configuration);
void (*libdecor_state_free)(struct libdecor_state* state);
struct libdecor_frame* (*libdecor_decorate)(struct libdecor* context, struct wl_surface* surface, struct libdecor_frame_interface* iface, void* user_data);
void (*libdecor_frame_set_app_id)(struct libdecor_frame* frame, const char* app_id);
void (*libdecor_frame_set_title)(struct libdecor_frame* frame, const char* title);
void (*libdecor_frame_map)(struct libdecor_frame* frame);
MwBool (*libdecor_configuration_get_content_size)(struct libdecor_configuration* configuration, struct libdecor_frame* frame, int* width, int* height);
MwBool (*libdecor_configuration_get_window_state)(struct libdecor_configuration* configuration, enum libdecor_window_state* window_state);
struct xdg_surface* (*libdecor_frame_get_xdg_surface)(struct libdecor_frame* frame);
int (*libdecor_dispatch)(struct libdecor* context, int timeout);
} wayland_call_table_t; } wayland_call_table_t;
extern wayland_call_table_t wl_call_tbl; extern wayland_call_table_t wl_call_tbl;
@ -174,6 +196,17 @@ MwInline int wayland_load_funcs() {
printf("(libcairo not found, cannot use Wayland backend.)\n"); printf("(libcairo not found, cannot use Wayland backend.)\n");
return 1; return 1;
} }
/* i mean i pray if somebody is using thr wayland backend over apple/ios that actual decorations are supported. */
#ifdef __APPLE__
wl_call_tbl.libdecor_lib = MwDynamicOpen("libdecor-0.dylib");
#else
wl_call_tbl.libdecor_lib = MwDynamicOpen("libdecor-0.so");
#endif
wl_call_tbl.has_libdecor = (wl_call_tbl.libdecor_lib != NULL);
if(!wl_call_tbl.libdecor_lib) {
printf("(libdecor not found, window will not have any decorations.)\n");
}
#define WAYLAND_FUNC(x) \ #define WAYLAND_FUNC(x) \
wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.lib, #x); \ wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.lib, #x); \
if(!wl_call_tbl.x) { \ if(!wl_call_tbl.x) { \
@ -262,6 +295,27 @@ MwInline int wayland_load_funcs() {
wl_call_tbl.has_dbus = MwLLDBusFuncSetup(&wl_call_tbl.dbus); wl_call_tbl.has_dbus = MwLLDBusFuncSetup(&wl_call_tbl.dbus);
#endif #endif
if(wl_call_tbl.has_libdecor) {
#define LIBDECOR_FUNC(x) \
wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.libdecor_lib, #x); \
if(!wl_call_tbl.x) { \
printf("WARNING: Can't use libdecor because libdecor-1 doesn't export " #x ".\n"); \
wl_call_tbl.has_libdecor = MwFALSE; \
};
}
LIBDECOR_FUNC(libdecor_new);
LIBDECOR_FUNC(libdecor_state_new);
LIBDECOR_FUNC(libdecor_frame_commit);
LIBDECOR_FUNC(libdecor_state_free);
LIBDECOR_FUNC(libdecor_decorate);
LIBDECOR_FUNC(libdecor_frame_set_app_id);
LIBDECOR_FUNC(libdecor_frame_set_title);
LIBDECOR_FUNC(libdecor_frame_map);
LIBDECOR_FUNC(libdecor_configuration_get_content_size);
LIBDECOR_FUNC(libdecor_configuration_get_window_state);
LIBDECOR_FUNC(libdecor_frame_get_xdg_surface);
return 0; return 0;
} }
@ -337,6 +391,8 @@ MwInline int wayland_load_funcs() {
#include "Wayland/xdg-toplevel-icon-client-protocol.h" #include "Wayland/xdg-toplevel-icon-client-protocol.h"
#endif #endif
#include <libdecor-0/libdecor.h>
typedef struct wayland_protocol { typedef struct wayland_protocol {
void* listener; void* listener;
void* context; void* context;
@ -352,6 +408,7 @@ typedef struct wayland_protocol_callback_table {
struct _MwLLWaylandTopLevel { struct _MwLLWaylandTopLevel {
struct xdg_surface* xdg_surface; struct xdg_surface* xdg_surface;
struct xdg_surface* xdg_surface_parent;
struct xdg_toplevel* xdg_top_level; struct xdg_toplevel* xdg_top_level;
struct xdg_toplevel_listener xdg_toplevel_listener; struct xdg_toplevel_listener xdg_toplevel_listener;
struct xdg_surface_listener xdg_surface_listener; struct xdg_surface_listener xdg_surface_listener;
@ -360,7 +417,7 @@ struct _MwLLWaylandTopLevel {
MwBool xdg_wm_base_created; MwBool xdg_wm_base_created;
MwBool xdg_surface_created; MwBool xdg_surface_created;
struct wl_subsurface* ssurface; // struct wl_subsurface* ssurface;
struct wl_subcompositor* scompositor; struct wl_subcompositor* scompositor;
}; };
@ -486,6 +543,11 @@ struct _MwLLWayland {
MwLLDBusContext dbus; MwLLDBusContext dbus;
#endif #endif
struct libdecor* decor;
struct libdecor_frame* decor_frame;
struct libdecor_interface* decor_interface;
enum libdecor_window_state decor_state;
MwBool dark_theme_detection; MwBool dark_theme_detection;
MwU32 dark_theme; MwU32 dark_theme;
@ -540,8 +602,8 @@ struct _MwLLWayland {
MwBool dispatching_resize; MwBool dispatching_resize;
struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer framebuffer;
struct _MwLLWaylandShmBuffer backbuffer; // struct _MwLLWaylandShmBuffer backbuffer;
struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer cursor;
struct _MwLLWaylandShmBuffer* icon; struct _MwLLWaylandShmBuffer* icon;

View file

@ -18,9 +18,13 @@ wayland_call_table_t wl_call_tbl;
MwBool MwWaylandAlwaysRender = MwFALSE; MwBool MwWaylandAlwaysRender = MwFALSE;
static pthread_mutex_t destroyedWidgetsTableMutex; static pthread_mutex_t destroyedWidgetsTableMutex;
/* So Wayland, bless its soul; it keeps using callbacks LONG after they should not only be destroyed but the widget doesn't even exist anymore. Naturally, this causes use after free. so we fight fire with fire in the worst code i've ever written: by storing the freed pointers here, we disallow wayland from ever using them again. if something else is created that takes this slot, we remove it from the table. */ /* So Wayland, bless its soul; it keeps using callbacks LONG after they should not only be destroyed but the widget doesn't even exist anymore. Naturally, this causes use after free. so we fight fire with fire in the worst code i've ever written: by storing the freed pointers here, we disallow wayland from ever using them again. if something else is created that takes this slot, we remove it from the table. */
static MwLL* destroyedWidgetsTable; static MwLL* destroyedWidgetsTable;
/* Currently held down widget. Protected by eventsMutex. */
static MwLL currentlyHeldWidget = NULL;
static MwBool is_destroyed(MwLL self) { static MwBool is_destroyed(MwLL self) {
int i; int i;
pthread_mutex_lock(&destroyedWidgetsTableMutex); pthread_mutex_lock(&destroyedWidgetsTableMutex);
@ -67,11 +71,6 @@ static void framebuffer_setup(struct _MwLLWayland* wayland);
/* Destroy the framebuffer */ /* Destroy the framebuffer */
static void framebuffer_destroy(struct _MwLLWayland* handle); static void framebuffer_destroy(struct _MwLLWayland* handle);
/* Setup the framebuffer with the saved width/height */
static void backbuffer_setup(struct _MwLLWayland* wayland);
/* Destroy the backbuffer */
static void backbuffer_destroy(struct _MwLLWayland* handle);
static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer); static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer);
static void region_setup(MwLL handle); static void region_setup(MwLL handle);
@ -532,32 +531,6 @@ static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 seria
WAYLAND_EVENT_OP_END(self); WAYLAND_EVENT_OP_END(self);
}; };
static void xdg_borderless_step(MwLL self, MwMouse p, MwU32 serial) {
if(self->wayland.type == MwLL_WAYLAND_TOPLEVEL && self->wayland.backbuffer.surface == curSurface) {
if(p.point.y >= (self->wayland.wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM) - 5) {
if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) {
xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT);
} else {
xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM);
}
} else if(p.point.y <= 5) {
if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) {
xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT);
} else {
xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_TOP);
}
} else if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) {
xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_RIGHT);
} else if(p.point.x <= 5) {
xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_LEFT);
} else if(p.point.y <= CSD_BORDER_FRAME_TOP) {
xdg_toplevel_move(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial);
}
};
}
static MwLL currentlyHeldWidget = NULL;
static void relative_pointer_motion(void* data, static void relative_pointer_motion(void* data,
struct zwp_relative_pointer_v1* pointer, struct zwp_relative_pointer_v1* pointer,
uint32_t timeHi, uint32_t timeHi,
@ -628,9 +601,6 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time
inArea |= self->wayland.framebuffer.surface == curSurface; inArea |= self->wayland.framebuffer.surface == curSurface;
} }
if(self->wayland.backbuffer.surface) {
inArea |= self->wayland.backbuffer.surface == curSurface;
}
if(inArea) { if(inArea) {
wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, self->wayland.cursor.surface, 0, 0); wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, self->wayland.cursor.surface, 0, 0);
} }
@ -654,9 +624,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri
if(self->wayland.framebuffer.surface) { if(self->wayland.framebuffer.surface) {
inArea |= self->wayland.framebuffer.surface == curSurface; inArea |= self->wayland.framebuffer.surface == curSurface;
} }
if(self->wayland.backbuffer.surface) {
inArea |= self->wayland.backbuffer.surface == curSurface;
}
if(inArea) { if(inArea) {
switch(button) { switch(button) {
case BTN_LEFT: case BTN_LEFT:
@ -688,10 +656,6 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri
} }
} }
if(!self->wayland.has_decorations) {
xdg_borderless_step(self, p, serial);
}
WAYLAND_EVENT_OP_END(self); WAYLAND_EVENT_OP_END(self);
}; };
@ -801,9 +765,6 @@ static void keyboard_key(void* data,
inArea |= self->wayland.framebuffer.surface == curSurface; inArea |= self->wayland.framebuffer.surface == curSurface;
} }
if(self->wayland.backbuffer.surface) {
inArea |= self->wayland.backbuffer.surface == curSurface;
}
if(inArea) { if(inArea) {
xkb_layout_index_t layout; xkb_layout_index_t layout;
MwU32 levels; MwU32 levels;
@ -1186,8 +1147,6 @@ static int event_loop(MwLL handle) {
wl_display_cancel_read(wayland->display); wl_display_cancel_read(wayland->display);
update_buffer(handle, &wayland->framebuffer); update_buffer(handle, &wayland->framebuffer);
if(wayland->type == MwLL_WAYLAND_TOPLEVEL)
update_buffer(handle, &wayland->backbuffer);
return 0; return 0;
} }
wl_display_read_events(wayland->display); wl_display_read_events(wayland->display);
@ -1239,11 +1198,8 @@ static void xdg_toplevel_configure(void* data,
if(self->wayland.resizing == 0) { if(self->wayland.resizing == 0) {
xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh); xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh);
backbuffer_destroy(&self->wayland);
backbuffer_setup(&self->wayland);
framebuffer_destroy(&self->wayland); framebuffer_destroy(&self->wayland);
framebuffer_setup(&self->wayland); framebuffer_setup(&self->wayland);
region_setup(self); region_setup(self);
MwLLDispatch(self, resize, NULL); MwLLDispatch(self, resize, NULL);
@ -1253,6 +1209,7 @@ static void xdg_toplevel_configure(void* data,
zwp_locked_pointer_v1_set_cursor_position_hint(self->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP); zwp_locked_pointer_v1_set_cursor_position_hint(self->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP);
wl_surface_commit(self->wayland.framebuffer.surface); wl_surface_commit(self->wayland.framebuffer.surface);
} }
self->wayland.resizing = 1; self->wayland.resizing = 1;
} }
}; };
@ -1278,7 +1235,6 @@ static void xdg_surface_configure(
if(self->wayland.configured) { if(self->wayland.configured) {
update_buffer(self, &self->wayland.framebuffer); update_buffer(self, &self->wayland.framebuffer);
update_buffer(self, &self->wayland.backbuffer);
} }
self->wayland.configured = MwTRUE; self->wayland.configured = MwTRUE;
@ -1287,7 +1243,6 @@ static void xdg_surface_configure(
/* wl_shm setup function */ /* wl_shm setup function */
static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland) { static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland) {
wayland->framebuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); wayland->framebuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1);
wayland->backbuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1);
wayland->cursor.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); wayland->cursor.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1);
return NULL; return NULL;
@ -1383,7 +1338,6 @@ static void framebuffer_setup(struct _MwLLWayland* wayland) {
wl_surface_attach(wayland->framebuffer.surface, wayland->framebuffer.shm_buffer, 0, 0); wl_surface_attach(wayland->framebuffer.surface, wayland->framebuffer.shm_buffer, 0, 0);
wl_surface_commit(wayland->framebuffer.surface); wl_surface_commit(wayland->framebuffer.surface);
hang_until_configured((MwLL)wayland);
update_buffer((MwLL)wayland, &wayland->framebuffer); update_buffer((MwLL)wayland, &wayland->framebuffer);
}; };
static void framebuffer_destroy(struct _MwLLWayland* wayland) { static void framebuffer_destroy(struct _MwLLWayland* wayland) {
@ -1392,34 +1346,6 @@ static void framebuffer_destroy(struct _MwLLWayland* wayland) {
cairo_surface_destroy(wayland->front_cs); cairo_surface_destroy(wayland->front_cs);
}; };
static void backbuffer_setup(struct _MwLLWayland* wayland) {
if(wayland->type != MwLL_WAYLAND_TOPLEVEL) {
return;
}
MwU32 w = wayland->ww;
MwU32 h = wayland->wh;
if(!wayland->has_decorations) {
w += (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT);
h += (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM);
}
buffer_setup(&wayland->backbuffer, w, h);
wayland->back_cs = cairo_image_surface_create_for_data(wayland->backbuffer.buf_back, CAIRO_FORMAT_ARGB32, w, h, 4 * w);
wayland->back_cairo = cairo_create(wayland->back_cs);
memset(wayland->backbuffer.buf_back, 255, wayland->backbuffer.buf_size);
if(wayland->configured)
wl_surface_attach(wayland->backbuffer.surface, wayland->backbuffer.shm_buffer, 0, 0);
wl_surface_commit(wayland->backbuffer.surface);
hang_until_configured((MwLL)wayland);
update_buffer((MwLL)wayland, &wayland->backbuffer);
};
static void backbuffer_destroy(struct _MwLLWayland* wayland) {
buffer_destroy(&wayland->backbuffer);
cairo_destroy(wayland->back_cairo);
cairo_surface_destroy(wayland->back_cs);
};
static void region_invalidate(MwLL handle) { static void region_invalidate(MwLL handle) {
if(!handle->wayland.configured) { if(!handle->wayland.configured) {
return; return;
@ -1445,10 +1371,6 @@ static void region_setup(MwLL handle) {
// wl_region_add(handle->wayland.region, 0, 0, width, height); // wl_region_add(handle->wayland.region, 0, 0, width, height);
} }
if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) {
wl_surface_set_opaque_region(handle->wayland.backbuffer.surface, handle->wayland.o_region);
wl_surface_set_input_region(handle->wayland.backbuffer.surface, handle->wayland.region);
}
wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.o_region); wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.o_region);
wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region); wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region);
} }
@ -1507,6 +1429,96 @@ static void setup_callbacks(struct _MwLLWayland* wayland) {
#undef WL_INTERFACE #undef WL_INTERFACE
} }
/* shitdecor */
static void libdecor_error(struct libdecor* context,
enum libdecor_error error,
const char* message) {
printf("libdecor error (%d): %s\n", error, message);
}
static void
handle_configure(struct libdecor_frame* frame,
struct libdecor_configuration* configuration,
void* user_data) {
MwLL self = user_data;
int width, height;
enum libdecor_window_state window_state;
struct libdecor_state* state;
if(!wl_call_tbl.libdecor_configuration_get_content_size(configuration, frame,
&width, &height)) {
width = self->wayland.ww;
height = self->wayland.wh;
}
width = (width == 0) ? 1 : width;
height = (height == 0) ? 1 : height;
// region_invalidate(self);
self->wayland.ww = width;
self->wayland.wh = height;
if(self->wayland.resizing == 0) {
framebuffer_destroy(&self->wayland);
framebuffer_setup(&self->wayland);
region_setup(self);
MwLLDispatch(self, resize, NULL);
recursive_dispatch_resize(self);
if(self->wayland.pointer_constrained) {
zwp_locked_pointer_v1_set_cursor_position_hint(self->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP);
wl_surface_commit(self->wayland.framebuffer.surface);
}
self->wayland.resizing = 1;
}
MwLLDispatch(self, draw, NULL);
if(!wl_call_tbl.libdecor_configuration_get_window_state(configuration,
&window_state))
window_state = LIBDECOR_WINDOW_STATE_NONE;
self->wayland.decor_state = window_state;
state = wl_call_tbl.libdecor_state_new(width, height);
wl_call_tbl.libdecor_frame_commit(frame, state, configuration);
wl_call_tbl.libdecor_state_free(state);
self->wayland.configured = MwTRUE;
}
static void
handle_close(struct libdecor_frame* frame,
void* user_data) {
MwLL self = user_data;
MwLLDispatch(self, close, NULL);
}
static void
handle_commit(struct libdecor_frame* frame,
void* user_data) {
MwLL self = user_data;
wl_surface_commit(self->wayland.framebuffer.surface);
}
static void
handle_dismiss_popup(struct libdecor_frame* frame,
const char* seat_name,
void* user_data) {
}
static struct libdecor_frame_interface libdecor_frame_iface = {
handle_configure,
handle_close,
handle_commit,
handle_dismiss_popup,
};
static struct libdecor_interface libdecor_interface = {
libdecor_error};
/* Toplevel setup function */ /* Toplevel setup function */
static void setup_toplevel(MwLL r, int x, int y) { static void setup_toplevel(MwLL r, int x, int y) {
r->wayland.type = MwLL_WAYLAND_TOPLEVEL; r->wayland.type = MwLL_WAYLAND_TOPLEVEL;
@ -1535,20 +1547,18 @@ static void setup_toplevel(MwLL r, int x, int y) {
/* check now if we have decorations so that everything else can act accordingly */ /* check now if we have decorations so that everything else can act accordingly */
if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) {
r->wayland.has_decorations = MwTRUE; // r->wayland.has_decorations = MwTRUE;
} }
r->wayland.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); r->wayland.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
/* Create a wl_surface, a xdg_surface and a xdg_toplevel */
r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor);
r->wayland.backbuffer.surface = wl_compositor_create_surface(r->wayland.compositor);
r->wayland.toplevel->ssurface = wl_subcompositor_get_subsurface(r->wayland.toplevel->scompositor, r->wayland.framebuffer.surface, r->wayland.backbuffer.surface);
wl_subsurface_set_desync(r->wayland.toplevel->ssurface);
r->wayland.toplevel->xdg_surface = if(r->wayland.has_decorations) {
xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.backbuffer.surface); r->wayland.toplevel->xdg_surface =
r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface); xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface);
r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface);
}
/* setup mandatory listeners */ /* setup mandatory listeners */
r->wayland.toplevel->xdg_surface_listener.configure = xdg_surface_configure; r->wayland.toplevel->xdg_surface_listener.configure = xdg_surface_configure;
@ -1556,16 +1566,25 @@ static void setup_toplevel(MwLL r, int x, int y) {
r->wayland.toplevel->xdg_toplevel_listener.configure = xdg_toplevel_configure; r->wayland.toplevel->xdg_toplevel_listener.configure = xdg_toplevel_configure;
r->wayland.toplevel->xdg_toplevel_listener.close = xdg_toplevel_close; r->wayland.toplevel->xdg_toplevel_listener.close = xdg_toplevel_close;
xdg_surface_add_listener(r->wayland.toplevel->xdg_surface, &r->wayland.toplevel->xdg_surface_listener, r); if(r->wayland.has_decorations) {
xdg_toplevel_add_listener(r->wayland.toplevel->xdg_top_level, &r->wayland.toplevel->xdg_toplevel_listener, xdg_surface_add_listener(r->wayland.toplevel->xdg_surface, &r->wayland.toplevel->xdg_surface_listener, r);
r); xdg_toplevel_add_listener(r->wayland.toplevel->xdg_top_level, &r->wayland.toplevel->xdg_toplevel_listener,
r);
xdg_toplevel_set_title(r->wayland.toplevel->xdg_top_level, "Milsko App"); xdg_toplevel_set_title(r->wayland.toplevel->xdg_top_level, "Milsko App");
xdg_toplevel_set_app_id(r->wayland.toplevel->xdg_top_level, "MilskoWaylandApp"); xdg_toplevel_set_app_id(r->wayland.toplevel->xdg_top_level, "MilskoWaylandApp");
} else {
r->wayland.decor = wl_call_tbl.libdecor_new(r->wayland.display, &libdecor_interface);
r->wayland.decor_frame = wl_call_tbl.libdecor_decorate(r->wayland.decor, r->wayland.framebuffer.surface,
&libdecor_frame_iface, r);
wl_call_tbl.libdecor_frame_set_app_id(r->wayland.decor_frame, "milsko-app");
wl_call_tbl.libdecor_frame_set_title(r->wayland.decor_frame, "Milsko App");
wl_call_tbl.libdecor_frame_map(r->wayland.decor_frame);
}
/* Perform the initial commit and wait for the first configure event */ /* Perform the initial commit and wait for the first configure event */
wl_surface_commit(r->wayland.backbuffer.surface);
wl_surface_commit(r->wayland.framebuffer.surface); wl_surface_commit(r->wayland.framebuffer.surface);
while(!r->wayland.configured) { while(!r->wayland.configured) {
event_loop(r); event_loop(r);
} }
@ -1579,8 +1598,6 @@ static void setup_toplevel(MwLL r, int x, int y) {
zxdg_toplevel_decoration_v1_set_mode( zxdg_toplevel_decoration_v1_set_mode(
dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
} else {
wl_subsurface_set_position(r->wayland.toplevel->ssurface, CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_TOP);
} }
} }
@ -1597,7 +1614,9 @@ static void destroy_toplevel(MwLL r) {
xdg_surface_destroy(r->wayland.toplevel->xdg_surface); xdg_surface_destroy(r->wayland.toplevel->xdg_surface);
xdg_toplevel_destroy(r->wayland.toplevel->xdg_top_level); if(r->wayland.has_decorations) {
xdg_toplevel_destroy(r->wayland.toplevel->xdg_top_level);
}
xkb_keymap_unref(r->wayland.xkb_keymap); xkb_keymap_unref(r->wayland.xkb_keymap);
@ -1663,7 +1682,6 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) {
/* Sublevel setup function */ /* Sublevel setup function */
static void destroy_sublevel(MwLL r) { static void destroy_sublevel(MwLL r) {
backbuffer_destroy(&r->wayland);
framebuffer_destroy(&r->wayland); framebuffer_destroy(&r->wayland);
wl_subsurface_destroy(r->wayland.sublevel->subsurface); wl_subsurface_destroy(r->wayland.sublevel->subsurface);
@ -1712,10 +1730,6 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) {
while(topmost_parent->wayland.type != MwLL_WAYLAND_TOPLEVEL) { while(topmost_parent->wayland.type != MwLL_WAYLAND_TOPLEVEL) {
topmost_parent = topmost_parent->wayland.parent; topmost_parent = topmost_parent->wayland.parent;
} }
if(!topmost_parent->wayland.has_decorations) {
r->wayland.x += ceil((float)CSD_BORDER_FRAME_LEFT / 2.);
r->wayland.y += ceil((float)CSD_BORDER_FRAME_TOP / 2.);
}
setup_callbacks(&r->wayland); setup_callbacks(&r->wayland);
@ -1733,7 +1747,7 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) {
/* check now if we have decorations so that everything else can act accordingly */ /* check now if we have decorations so that everything else can act accordingly */
if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) {
r->wayland.has_decorations = MwTRUE; // r->wayland.has_decorations = MwTRUE;
} }
r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context; r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context;
@ -1751,8 +1765,12 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) {
r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor);
r->wayland.popup->xdg_surface = if(r->wayland.has_decorations) {
xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); r->wayland.popup->xdg_surface =
xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface);
r->wayland.popup->xdg_surface_listener.configure = xdg_surface_configure;
xdg_surface_add_listener(r->wayland.popup->xdg_surface, &r->wayland.popup->xdg_surface_listener, r);
}
r->wayland.popup->xdg_popup = xdg_surface_get_popup( r->wayland.popup->xdg_popup = xdg_surface_get_popup(
r->wayland.popup->xdg_surface, r->wayland.popup->xdg_surface,
@ -1761,9 +1779,6 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) {
xdg_popup_add_listener(r->wayland.popup->xdg_popup, &popup_listener, r); xdg_popup_add_listener(r->wayland.popup->xdg_popup, &popup_listener, r);
r->wayland.popup->xdg_surface_listener.configure = xdg_surface_configure;
xdg_surface_add_listener(r->wayland.popup->xdg_surface, &r->wayland.popup->xdg_surface_listener, r);
/* Perform the initial commit and wait for the first configure event */ /* Perform the initial commit and wait for the first configure event */
wl_surface_commit(r->wayland.framebuffer.surface); wl_surface_commit(r->wayland.framebuffer.surface);
while(!r->wayland.configured) { while(!r->wayland.configured) {
@ -1915,7 +1930,6 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh
WIDGET_CHECK(r); WIDGET_CHECK(r);
framebuffer_setup(&r->wayland); framebuffer_setup(&r->wayland);
backbuffer_setup(&r->wayland);
r->wayland.region = wl_compositor_create_region(r->wayland.compositor); r->wayland.region = wl_compositor_create_region(r->wayland.compositor);
r->wayland.o_region = wl_compositor_create_region(r->wayland.compositor); r->wayland.o_region = wl_compositor_create_region(r->wayland.compositor);
@ -1925,11 +1939,6 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh
if(parent != NULL) { if(parent != NULL) {
MwLLForceRender(parent); MwLLForceRender(parent);
} }
if(!r->wayland.has_decorations) {
MwLLBeginDraw(r);
MwLLEndDraw(r);
}
} }
#ifdef USE_DBUS #ifdef USE_DBUS
@ -2084,7 +2093,11 @@ static void actually_set_wh(MwLL handle) {
region_invalidate(handle); region_invalidate(handle);
if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL && handle->wayland.configured) { if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL && handle->wayland.configured) {
xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh); if(handle->wayland.has_decorations) {
xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh);
} else {
xdg_surface_set_window_geometry(wl_call_tbl.libdecor_frame_get_xdg_surface(handle->wayland.decor_frame), 0, 0, handle->wayland.ww, handle->wayland.wh);
}
} }
if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL && handle->wayland.configured && !handle->wayland.dispatching_resize) { if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL && handle->wayland.configured && !handle->wayland.dispatching_resize) {
@ -2104,8 +2117,6 @@ static void actually_set_wh(MwLL handle) {
framebuffer_destroy(&handle->wayland); framebuffer_destroy(&handle->wayland);
framebuffer_setup(&handle->wayland); framebuffer_setup(&handle->wayland);
backbuffer_destroy(&handle->wayland);
backbuffer_setup(&handle->wayland);
MwLLDispatch(handle, draw, NULL); MwLLDispatch(handle, draw, NULL);
} }
@ -2133,110 +2144,25 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) {
} }
static void MwLLBeginDrawImpl(MwLL handle) { static void MwLLBeginDrawImpl(MwLL handle) {
WIDGET_CHECK(handle); // WIDGET_CHECK(handle);
cairo_save(handle->wayland.front_cairo); // cairo_save(handle->wayland.front_cairo);
cairo_set_source_rgba(handle->wayland.front_cairo, 0, 0, 0, 0); // cairo_set_source_rgba(handle->wayland.front_cairo, 0, 0, 0, 0);
cairo_set_operator(handle->wayland.front_cairo, CAIRO_OPERATOR_SOURCE); // cairo_set_operator(handle->wayland.front_cairo, CAIRO_OPERATOR_SOURCE);
cairo_rectangle(handle->wayland.front_cairo, 0, 0, handle->wayland.ww, handle->wayland.wh); // cairo_rectangle(handle->wayland.front_cairo, 0, 0, handle->wayland.ww, handle->wayland.wh);
cairo_fill(handle->wayland.front_cairo); // cairo_fill(handle->wayland.front_cairo);
cairo_restore(handle->wayland.front_cairo); // cairo_restore(handle->wayland.front_cairo);
if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) { // if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) {
handle->wayland.selected_cairo = handle->wayland.front_cairo; // handle->wayland.selected_cairo = handle->wayland.front_cairo;
return; // return;
} // }
if(!handle->wayland.has_decorations) { // handle->wayland.selected_cairo = handle->wayland.front_cairo;
int x;
MwU32 w = handle->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT;
MwU32 h = handle->wayland.wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM;
cairo_set_line_width(handle->wayland.back_cairo, 4.0);
for(x = 0; x < w; x++) {
float placeholder = (float)x / (float)w;
cairo_set_source_rgb(handle->wayland.back_cairo, placeholder, 0.25, 0.25);
cairo_move_to(handle->wayland.back_cairo, w - x, 0);
cairo_line_to(handle->wayland.back_cairo, w - x, CSD_BORDER_FRAME_TOP);
cairo_stroke(handle->wayland.back_cairo);
cairo_move_to(handle->wayland.back_cairo, x, CSD_BORDER_FRAME_TOP);
cairo_line_to(handle->wayland.back_cairo, x, h);
cairo_stroke(handle->wayland.back_cairo);
}
cairo_set_source_rgba(handle->wayland.back_cairo, 1, 1, 1, 0.5);
cairo_move_to(handle->wayland.back_cairo, 0, 0);
cairo_line_to(handle->wayland.back_cairo, 0, h);
cairo_stroke(handle->wayland.back_cairo);
cairo_move_to(handle->wayland.back_cairo, 0, 0);
cairo_line_to(handle->wayland.back_cairo, w, 0);
cairo_stroke(handle->wayland.back_cairo);
cairo_set_source_rgba(handle->wayland.back_cairo, 0, 0, 0, 0.5);
cairo_move_to(handle->wayland.back_cairo, 0, h);
cairo_line_to(handle->wayland.back_cairo, w, h);
cairo_stroke(handle->wayland.back_cairo);
cairo_move_to(handle->wayland.back_cairo, w, 0);
cairo_line_to(handle->wayland.back_cairo, w, h);
cairo_stroke(handle->wayland.back_cairo);
if(strlen(handle->wayland.title) != 0) {
int y, x;
int i = 0, sx = 0, sy = 0;
int tw, th;
unsigned char* px;
MwRect r;
MwLLPixmap p;
tw = strlen(handle->wayland.title) * 7;
th = 14;
px = malloc(tw * th * 4);
assert(px);
memset(px, 0, tw * th * 4);
handle->wayland.selected_cairo = handle->wayland.back_cairo;
while(handle->wayland.title[i]) {
int out;
i += MwUTF8ToUTF32(handle->wayland.title + i, &out);
if(out > 0xff) {
out = 0;
}
for(y = 0; y < 14; y++) {
for(x = 0; x < 7; x++) {
unsigned char* ppx = &px[((sy + y) * tw + sx + x) * 4];
int col = MwFontData[out].data[y] & (1 << ((7 - 1) - x)) ? 255 : 0;
ppx[0] = col;
ppx[1] = col;
ppx[2] = col;
ppx[3] = col;
}
}
sx += 7;
}
p = MwLLCreatePixmap(handle, px, tw, th);
r.x = 5;
r.y = 5;
r.width = tw;
r.height = th;
MwLLDrawPixmap(handle, &r, p);
MwLLDestroyPixmap(p);
free(px);
}
update_buffer(handle, &handle->wayland.backbuffer);
}
handle->wayland.selected_cairo = handle->wayland.front_cairo;
} }
static void MwLLEndDrawImpl(MwLL handle) { static void MwLLEndDrawImpl(MwLL handle) {
if(handle->wayland.configured) { if(handle->wayland.configured) {
if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { // update_buffer(handle, &handle->wayland.framebuffer);
update_buffer(handle, &handle->wayland.backbuffer);
}
update_buffer(handle, &handle->wayland.framebuffer);
} }
} }
@ -2372,15 +2298,13 @@ static int MwLLPendingImpl(MwLL handle) {
} }
update_buffer(handle, &handle->wayland.framebuffer); update_buffer(handle, &handle->wayland.framebuffer);
if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) {
update_buffer(handle, &handle->wayland.backbuffer);
}
return handle->wayland.force_render || handle->wayland.events_pending || pending; return handle->wayland.force_render || handle->wayland.events_pending || pending;
} }
static void MwLLNextEventImpl(MwLL handle) { static void MwLLNextEventImpl(MwLL handle) {
WIDGET_CHECK(handle); WIDGET_CHECK(handle);
if(!MwWaylandAlwaysRender) { if(!MwWaylandAlwaysRender) {
if(handle->wayland.did_event_loop_early) { if(handle->wayland.did_event_loop_early) {
handle->wayland.did_event_loop_early = MwFALSE; handle->wayland.did_event_loop_early = MwFALSE;
@ -2389,6 +2313,8 @@ static void MwLLNextEventImpl(MwLL handle) {
} }
} }
// wl_call_tbl.libdecor_dispatch(handle->wayland.decor, 0);
if(handle->wayland.force_render) { if(handle->wayland.force_render) {
MwLLDispatch(handle, draw, NULL); MwLLDispatch(handle, draw, NULL);
if(handle->wayland.configured) update_buffer(handle, &handle->wayland.framebuffer); if(handle->wayland.configured) update_buffer(handle, &handle->wayland.framebuffer);
@ -2402,13 +2328,15 @@ static void MwLLNextEventImpl(MwLL handle) {
static void MwLLSetTitleImpl(MwLL handle, const char* title) { static void MwLLSetTitleImpl(MwLL handle, const char* title) {
WIDGET_CHECK(handle); WIDGET_CHECK(handle);
if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) {
xdg_toplevel_set_title(handle->wayland.toplevel->xdg_top_level, title); if(handle->wayland.has_decorations) {
} xdg_toplevel_set_title(handle->wayland.toplevel->xdg_top_level, title);
if(!handle->wayland.has_decorations) { }
strncpy(handle->wayland.title, title, 255);
MwLLBeginDraw(handle);
MwLLEndDraw(handle);
} }
// if(!handle->wayland.has_decorations) {
// strncpy(handle->wayland.title, title, 255);
// MwLLBeginDraw(handle);
// MwLLEndDraw(handle);
// }
} }
static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) {
@ -2621,10 +2549,6 @@ static void MwLLShowImpl(MwLL handle, int show) {
wl_surface_attach(handle->wayland.framebuffer.surface, show ? handle->wayland.framebuffer.shm_buffer : NULL, 0, 0); wl_surface_attach(handle->wayland.framebuffer.surface, show ? handle->wayland.framebuffer.shm_buffer : NULL, 0, 0);
wl_surface_commit(handle->wayland.framebuffer.surface); wl_surface_commit(handle->wayland.framebuffer.surface);
} }
if(handle->wayland.backbuffer.surface) {
wl_surface_attach(handle->wayland.backbuffer.surface, show ? handle->wayland.backbuffer.shm_buffer : NULL, 0, 0);
wl_surface_commit(handle->wayland.backbuffer.surface);
}
} }
static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { static void MwLLMakePopupImpl(MwLL handle, MwLL parent) {
@ -2636,8 +2560,10 @@ static void MwLLMakePopupImpl(MwLL handle, MwLL parent) {
static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) {
WIDGET_CHECK(handle); WIDGET_CHECK(handle);
if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) {
xdg_toplevel_set_min_size(handle->wayland.toplevel->xdg_top_level, minx, miny); if(handle->wayland.has_decorations) {
xdg_toplevel_set_max_size(handle->wayland.toplevel->xdg_top_level, maxx, maxy); xdg_toplevel_set_min_size(handle->wayland.toplevel->xdg_top_level, minx, miny);
xdg_toplevel_set_max_size(handle->wayland.toplevel->xdg_top_level, maxx, maxy);
}
} }
} }
@ -2645,7 +2571,7 @@ static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) {
(void)toggle; (void)toggle;
WIDGET_CHECK(handle); WIDGET_CHECK(handle);
if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) {
if(WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1) != NULL) { if(handle->wayland.has_decorations) {
zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1)->context; zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1)->context;
dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
@ -2668,8 +2594,8 @@ static void MwLLGrabPointerImpl(MwLL handle, int toggle) {
while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent;
if(handle->wayland.pointer_constraints && handle->wayland.relative_pointer_manager) { if(handle->wayland.pointer_constraints && handle->wayland.relative_pointer_manager) {
if(toggle) { if(toggle) {
topmost_parent->wayland.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(topmost_parent->wayland.pointer_constraints, topmost_parent->wayland.backbuffer.surface, topmost_parent->wayland.pointer, topmost_parent->wayland.region, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); topmost_parent->wayland.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(topmost_parent->wayland.pointer_constraints, topmost_parent->wayland.framebuffer.surface, topmost_parent->wayland.pointer, topmost_parent->wayland.region, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
wl_surface_commit(topmost_parent->wayland.backbuffer.surface); wl_surface_commit(topmost_parent->wayland.framebuffer.surface);
zwp_locked_pointer_v1_set_cursor_position_hint(topmost_parent->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP); zwp_locked_pointer_v1_set_cursor_position_hint(topmost_parent->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP);
handle->wayland.relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(handle->wayland.relative_pointer_manager, handle->wayland.pointer); handle->wayland.relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(handle->wayland.relative_pointer_manager, handle->wayland.pointer);
zwp_relative_pointer_v1_add_listener(handle->wayland.relative_pointer, &relative_pointer_listener, topmost_parent); zwp_relative_pointer_v1_add_listener(handle->wayland.relative_pointer, &relative_pointer_listener, topmost_parent);