Wayland: call libdecor_dispatch(), libdecor_unref(), libdecor_get_fd() as expected by libdecor.

Corresponds to these commits to master: 8e9e2b7, f121bc1, e8e5e61, d816da5.
This commit is contained in:
ManoloFLTK
2026-04-03 13:17:32 +02:00
parent 54303bc4c2
commit 09aafc7b52
2 changed files with 36 additions and 52 deletions
@@ -1352,30 +1352,30 @@ static const struct wl_registry_listener registry_listener = {
};
extern int fl_send_system_handlers(void *);
static void wayland_socket_callback(int fd, struct wl_display *display) {
if (fl_send_system_handlers(NULL)) return;
struct pollfd fds = (struct pollfd) { fd, POLLIN, 0 };
do {
if (wl_display_dispatch(display) == -1) {
int err = wl_display_get_error(display);
if (err == EPROTO) {
const struct wl_interface *interface;
int code = wl_display_get_protocol_error(display, &interface, NULL);
Fl::fatal("Fatal error no %d in Wayland protocol: %s", code,
(interface ? interface->name : "unknown") );
} else {
Fl::fatal("Fatal error while communicating with the Wayland server: %s",
strerror(errno));
}
}
static void libdecor_fd_callback(int fd, struct libdecor *libdecor_context) {
if (libdecor_dispatch(libdecor_context, 0) >= 0) return;
if (wl_display_get_error(Fl_Wayland_Screen_Driver::wl_display) == EPROTO) {
const struct wl_interface *interface;
int code = wl_display_get_protocol_error(Fl_Wayland_Screen_Driver::wl_display, &interface, NULL);
Fl::fatal("Fatal error no %d in Wayland protocol: %s", code,
(interface ? interface->name : "unknown") );
} else {
Fl::fatal("Fatal error while communicating with the Wayland server: %s",
strerror(errno));
}
while (poll(&fds, 1, 0) > 0);
}
static void handle_error(struct libdecor *libdecor_context, enum libdecor_error error, const char *message)
{
Fl::fatal("Caught error (%d): %s\n", error, message);
}
static struct libdecor_interface libdecor_iface = {
.error = handle_error,
};
Fl_Wayland_Screen_Driver::Fl_Wayland_Screen_Driver() : Fl_Unix_Screen_Driver() {
libdecor_context = NULL;
seat = NULL;
@@ -1404,8 +1404,11 @@ static const struct wl_callback_listener sync_listener = {
static void do_atexit() {
if (Fl_Wayland_Screen_Driver::wl_display) {
wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display);
// Issue #821 no longer seems to require extra operations under gnome version < 44.
Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
if (scr_driver->libdecor_context) { // libdecor recommends a call to libdecor_unref()
libdecor_unref(scr_driver->libdecor_context);
scr_driver->libdecor_context = NULL;
}
}
@@ -1431,15 +1434,10 @@ void Fl_Wayland_Screen_Driver::open_display_platform() {
struct wl_callback *registry_cb = wl_display_sync(wl_display);
wl_callback_add_listener(registry_cb, &sync_listener, &registry_cb);
while (registry_cb) wl_display_dispatch(wl_display);
Fl::add_fd(wl_display_get_fd(wl_display), FL_READ, (Fl_FD_Handler)wayland_socket_callback,
wl_display);
libdecor_context = libdecor_new(wl_display, &libdecor_iface);
Fl::add_fd(libdecor_get_fd(libdecor_context), FL_READ, (Fl_FD_Handler)libdecor_fd_callback,
libdecor_context);
fl_create_print_window();
/* This is useful to avoid crash of the Wayland compositor after
FLTK apps terminate in certain situations:
- gnome-shell version < 44 (e.g. version 42.9)
- focus set to "follow-mouse"
See issue #821 for details.
*/
atexit(do_atexit);
}
@@ -1519,21 +1517,20 @@ void Fl_Wayland_Screen_Driver::close_display() {
wl_seat_destroy(seat->wl_seat); seat->wl_seat = NULL;
if (seat->name) free(seat->name);
free(seat); seat = NULL;
if (libdecor_context) {
libdecor_unref(libdecor_context);
libdecor_context = NULL;
}
xdg_wm_base_destroy(xdg_wm_base); xdg_wm_base = NULL;
Fl_Wayland_Plugin *plugin = Fl_Wayland_Window_Driver::gl_plugin();
if (plugin) plugin->terminate();
Fl::remove_fd(wl_display_get_fd(Fl_Wayland_Screen_Driver::wl_display));
if (libdecor_context) {
Fl::remove_fd(libdecor_get_fd(libdecor_context));
libdecor_unref(libdecor_context);
libdecor_context = NULL;
}
wl_registry_destroy(wl_registry); wl_registry = NULL;
wl_display_disconnect(Fl_Wayland_Screen_Driver::wl_display);
Fl_Wayland_Screen_Driver::wl_display = NULL;
delete Fl_Display_Device::display_device()->driver();
delete Fl_Display_Device::display_device();
delete Fl::system_driver();
delete this;
}
@@ -648,17 +648,6 @@ int Fl_Wayland_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h,
}
static void handle_error(struct libdecor *libdecor_context, enum libdecor_error error, const char *message)
{
Fl::fatal("Caught error (%d): %s\n", error, message);
}
static struct libdecor_interface libdecor_iface = {
.error = handle_error,
};
void change_scale(Fl_Wayland_Screen_Driver::output *output, struct wld_window *window,
float pre_scale) {
Fl_Wayland_Window_Driver *win_driver = Fl_Wayland_Window_Driver::driver(window->fl_win);
@@ -1007,11 +996,12 @@ void Fl_Wayland_Window_Driver::wait_for_expose()
Fl_Window_Driver::wait_for_expose();
struct wld_window * xid = fl_wl_xid(pWindow);
if (!xid) return;
Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
if (pWindow->fullscreen_active()) {
if (xid->kind == DECORATED) {
while (!(xid->state & LIBDECOR_WINDOW_STATE_FULLSCREEN) ||
!(xid->state & LIBDECOR_WINDOW_STATE_ACTIVE)) {
wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display);
libdecor_dispatch(scr_driver->libdecor_context, 0);
}
} else if (xid->kind == UNFRAMED) {
wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display);
@@ -1019,7 +1009,7 @@ void Fl_Wayland_Window_Driver::wait_for_expose()
} else if (xid->kind == DECORATED) {
// necessary for the windowfocus demo program with recent Wayland versions
if (!(xid->state & LIBDECOR_WINDOW_STATE_ACTIVE)) {
wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display);
libdecor_dispatch(scr_driver->libdecor_context, 0);
}
}
}
@@ -1465,9 +1455,6 @@ void Fl_Wayland_Window_Driver::makeWindow()
} else if (pWindow->border() && !pWindow->parent() ) { // a decorated window
new_window->kind = DECORATED;
if (!scr_driver->libdecor_context)
scr_driver->libdecor_context = libdecor_new(Fl_Wayland_Screen_Driver::wl_display,
&libdecor_iface);
new_window->frame = libdecor_decorate(scr_driver->libdecor_context, new_window->wl_surface,
&libdecor_frame_iface, new_window);
// appears in the Gnome desktop menu bar