diff --git a/CMake/options.cmake b/CMake/options.cmake
index c1aa0dcea..b27f9adf5 100644
--- a/CMake/options.cmake
+++ b/CMake/options.cmake
@@ -297,7 +297,7 @@ if(UNIX)
endif()
unset(FLTK_GRAPHICS_CAIRO CACHE)
set(FLTK_GRAPHICS_CAIRO TRUE CACHE BOOL "all drawing to X11 windows uses Cairo")
- option(FLTK_USE_SYSTEM_LIBDECOR "use libdecor from the system" OFF)
+ option(FLTK_USE_SYSTEM_LIBDECOR "use libdecor from the system" ON)
set(USE_SYSTEM_LIBDECOR 1)
unset(FLTK_USE_XRENDER CACHE)
unset(FLTK_USE_XINERAMA CACHE)
@@ -333,9 +333,9 @@ if(UNIX)
unset(FLTK_USE_PANGO CACHE)
set(FLTK_USE_PANGO TRUE CACHE BOOL "use lib Pango")
if(FLTK_USE_SYSTEM_LIBDECOR)
- pkg_check_modules(SYSTEM_LIBDECOR IMPORTED_TARGET libdecor-0>0.2.2 QUIET)
+ pkg_check_modules(SYSTEM_LIBDECOR libdecor-0>=0.2.0 QUIET)
if(NOT SYSTEM_LIBDECOR_FOUND)
- message(STATUS "Warning: system libdecor doesn't satisfy version > 0.2.2,")
+ message(STATUS "Warning: system libdecor doesn't satisfy version ≥ 0.2.0,")
message(STATUS " using bundled libdecor library instead.")
set(USE_SYSTEM_LIBDECOR 0)
else()
diff --git a/README.CMake.txt b/README.CMake.txt
index a915b3b23..03325a9e4 100644
--- a/README.CMake.txt
+++ b/README.CMake.txt
@@ -282,12 +282,10 @@ FLTK_USE_PTHREADS - default ON except on Windows.
This option is ignored (switched OFF internally) on Windows except
when using Cygwin.
-FLTK_USE_SYSTEM_LIBDECOR - default OFF (Wayland only)
+FLTK_USE_SYSTEM_LIBDECOR - default ON (Wayland only)
This option makes FLTK use package libdecor-0-dev to draw window titlebars
- under Wayland. When OFF or when this package has a version ≤ 0.2.2, FLTK
+ under Wayland. When OFF or when this package has a version < 0.2.0, FLTK
uses its bundled copy of libdecor to draw window titlebars.
- As of early 2024, no version > 0.2.2 of package libdecor-0-dev is available
- yet.
FLTK_USE_SYSTEM_LIBJPEG - default ON (macOS and Windows: OFF)
FLTK_USE_SYSTEM_LIBPNG - default ON (macOS and Windows: OFF)
diff --git a/README.Wayland.txt b/README.Wayland.txt
index dc4c24c36..b88184468 100644
--- a/README.Wayland.txt
+++ b/README.Wayland.txt
@@ -126,8 +126,9 @@ cross-compiling for systems that lack X11 headers and libraries.
The FLTK Wayland platform uses a library called libdecor which handles window decorations
(i.e., titlebars, shade). On very recent Linux distributions (e.g., Debian trixie)
libdecor is available as Linux packages (libdecor-0-dev and libdecor-0-plugin-1-gtk).
-FLTK requires a version > 0.2.2 of these packages that's not yet available.
-Therefore, FLTK uses a copy of libdecor bundled in the FLTK source code.
+FLTK requires version 0.2.0 or more recent of these packages.
+When libdecor is not available or not recent enough, FLTK uses a copy of libdecor
+bundled in the FLTK source code.
FLTK equipped with libdecor supports both the client-side decoration mode (CSD) and the
server-side decoration mode (SSD) as determined by the active Wayland compositor.
Mutter (gnome's Wayland compositor) and Weston use CSD mode, KWin and Sway use SSD mode.
diff --git a/configure.ac b/configure.ac
index 9429b0458..ad2dd5996 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1092,7 +1092,7 @@ AS_CASE([$host_os_gui], [cygwin* | mingw*], [
BUILD="WAYLANDX11"
graphics="Wayland or X11 with cairo"
])
- AS_IF([$PKGCONFIG --exists 'libdecor-0 > 0.2.2'],
+ AS_IF([$PKGCONFIG --exists 'libdecor-0 >= 0.2.0'],
[
plugin_dir="$($PKGCONFIG --variable=libdir libdecor-0)/libdecor/plugins-1"
CFLAGS="$CFLAGS -DUSE_SYSTEM_LIBDECOR"
diff --git a/documentation/src/wayland.dox b/documentation/src/wayland.dox
index 8af4555de..3990556b8 100644
--- a/documentation/src/wayland.dox
+++ b/documentation/src/wayland.dox
@@ -1108,16 +1108,13 @@ Desktop. As of late 2023, libdecor contains two titlebar-drawing plugins:
- \c libdecor-gtk intended for the Gnome desktop;
- \c libdecor-cairo for other situations.
-Because \c libdecor is not yet in major Linux packages, or only at version 0.1.x,
-FLTK bundles the most recent source code of \c libdecor and its plugins. This code
+On recent Linux distributions, FLTK uses the system \c libdecor shared library
+available via packages \c libdecor-0-dev and \c libdecor-0-plugin-1-gtk.
+On earlier Linux versions, or if CMake option \c FLTK_USE_SYSTEM_LIBDECOR is set
+to OFF, FLTK bundles the most recent source code of \c libdecor and its plugins. This code
is included in libfltk. FLTK uses \c libdecor-gtk when software package \c libgtk-3-dev
is present in the build system, and \c libdecor-cairo otherwise.
-As of early 2024, libdecor version 0.2.2 is available in very recent Linux distributions.
-This version is not binary compatible with the libdecor version bundled by FLTK.
-For this reason, CMake option \c FLTK_USE_SYSTEM_LIBDECOR is OFF by default, and
-FLTK uses the bundled \c libdecor copy to draw titlebars.
-
\c Libdecor uses the Wayland protocol
XDG decoration
to request being decorated by a supporting compositor.
diff --git a/libdecor/build/fl_libdecor-plugins.c b/libdecor/build/fl_libdecor-plugins.c
index 1e73d736a..60f6bf56e 100644
--- a/libdecor/build/fl_libdecor-plugins.c
+++ b/libdecor/build/fl_libdecor-plugins.c
@@ -317,13 +317,34 @@ struct libdecor { // copied from libdecor.c, for libdecor versions > 0.2.2
struct wl_list frames;
};
+struct libdecor_022 { // for libdecor versions ≤ 0.2.2
+ int ref_count;
+ const struct libdecor_interface *iface;
+ struct libdecor_plugin *plugin;
+ bool plugin_ready;
+ struct wl_display *wl_display;
+ struct wl_registry *wl_registry;
+ struct xdg_wm_base *xdg_wm_base;
+ struct zxdg_decoration_manager_v1 *decoration_manager;
+ struct wl_callback *init_callback;
+ bool init_done;
+ bool has_error;
+ struct wl_list frames;
+};
+
/* Returns whether surface is a GTK-titlebar created by libdecor-gtk */
-bool fl_is_surface_gtk_titlebar(struct wl_surface *surface, struct libdecor *context) {
+bool fl_is_surface_gtk_titlebar(struct wl_surface *surface, struct libdecor *context,
+ struct wl_display *wl_display) {
if (!context || get_plugin_kind(NULL) != GTK3) return false;
// loop over all decorations created by libdecor-gtk
struct libdecor_frame *frame;
- wl_list_for_each(frame, &context->frames, link) {
+ struct wl_list *frames;
+ if (context->wl_display == wl_display) frames = &context->frames;
+ else if (((struct libdecor_022*)context)->wl_display == wl_display)
+ frames = &(((struct libdecor_022*)context)->frames);
+ else return false;
+ wl_list_for_each(frame, frames, link) {
struct libdecor_frame_gtk *frame_gtk = (struct libdecor_frame_gtk*)frame;
if (frame_gtk->headerbar.wl_surface == surface) return true;
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b01ee09ab..81a7b6605 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -756,7 +756,7 @@ if(UNIX AND FLTK_BACKEND_WAYLAND)
list(APPEND OPTIONAL_LIBS PkgConfig::WLD_EGL PkgConfig::PKG_EGL)
endif(FLTK_USE_GL)
if(USE_SYSTEM_LIBDECOR)
- list(APPEND OPTIONAL_LIBS PkgConfig::SYSTEM_LIBDECOR)
+ list(APPEND OPTIONAL_LIBS ${SYSTEM_LIBDECOR_LDFLAGS})
elseif(GTK_FOUND AND FLTK_USE_LIBDECOR_GTK)
list(APPEND OPTIONAL_LIBS PkgConfig::GTK)
endif(USE_SYSTEM_LIBDECOR)
diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
index efbb176ab..60011393d 100644
--- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
+++ b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
@@ -47,7 +47,7 @@
#include // for strerror()
extern "C" {
bool libdecor_get_cursor_settings(char **theme, int *size);
- bool fl_is_surface_gtk_titlebar(struct wl_surface *, struct libdecor *);
+ bool fl_is_surface_gtk_titlebar(struct wl_surface *, struct libdecor *, struct wl_display *);
}
// set this to 1 for keyboard debug output, 0 for no debug output
@@ -206,7 +206,8 @@ static void pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t se
Fl_Window *win = event_coords_from_surface(surface, surface_x, surface_y);
if (!win && gtk_shell) { // check that surface is the headerbar of a GTK-decorated window
Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- if (fl_is_surface_gtk_titlebar(surface, scr_driver->libdecor_context)) {
+ if (fl_is_surface_gtk_titlebar(surface, scr_driver->libdecor_context,
+ Fl_Wayland_Screen_Driver::wl_display)) {
gtk_shell_surface = surface;
}
}
diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
index e8a0a1af9..ff1682e31 100644
--- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
+++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
@@ -769,6 +769,69 @@ static struct Fl_Wayland_Screen_Driver::output *screen_num_to_output(int num_scr
}
+#define LIBDECOR_MR131 1 // this means libdecor does not include MR!131 yet
+
+#ifdef LIBDECOR_MR131
+/* === Beginning of hack that would become un-needed if libdecor accepted MR!131 === */
+
+// true while the GUI is interactively resizing a decorated window
+static bool in_decorated_window_resizing = false;
+
+
+// libdecor's configure cb function for xdg_toplevel objects
+static void (*decor_xdg_toplevel_configure)(void*, struct xdg_toplevel *, int32_t,
+ int32_t, struct wl_array *);
+
+
+static void fltk_xdg_toplevel_configure(void *user_data, struct xdg_toplevel *xdg_toplevel,
+ int32_t width, int32_t height,
+ struct wl_array *states) {
+ uint32_t *p;
+ in_decorated_window_resizing = false;
+ // Replace wl_array_for_each(p, states) rejected by C++
+ for (p = (uint32_t *)(states)->data;
+ (const char *) p < ((const char *) (states)->data + (states)->size);
+ (p)++) {
+ if (*p == XDG_TOPLEVEL_STATE_RESIZING) {
+ in_decorated_window_resizing = true;
+ break;
+ }
+ }
+ decor_xdg_toplevel_configure(user_data, xdg_toplevel, width, height, states);
+}
+
+
+struct wl_object { // copied from wayland-private.h
+ const struct wl_interface *interface;
+ const void *implementation;
+ uint32_t id;
+};
+
+
+// replace libdecor's toplevel configure cb by FLTK's
+static void use_FLTK_toplevel_configure_cb(struct libdecor_frame *frame) {
+ struct wl_object *object = (struct wl_object *)libdecor_frame_get_xdg_toplevel(frame);
+ static struct xdg_toplevel_listener *fltk_listener = NULL;
+ if (!fltk_listener) {
+ struct xdg_toplevel_listener *decor_listener = (struct xdg_toplevel_listener*)
+ object->implementation;
+ fltk_listener = (struct xdg_toplevel_listener*)
+ malloc(sizeof(struct xdg_toplevel_listener));
+ // initialize FLTK's listener with libdecor's values
+ *fltk_listener = *decor_listener;
+ // memorize libdecor's toplevel configure cb
+ decor_xdg_toplevel_configure = decor_listener->configure;
+ // replace libdecor's toplevel configure cb by FLTK's
+ fltk_listener->configure = fltk_xdg_toplevel_configure;
+ }
+ // replace the toplevel listener by a copy whose configure member is FLTK's
+ object->implementation = fltk_listener;
+}
+
+/* === End of hack that would become un-needed if libdecor accepted MR!131 === */
+#endif // LIBDECOR_MR131
+
+
static void handle_configure(struct libdecor_frame *frame,
struct libdecor_configuration *configuration, void *user_data)
{
@@ -786,6 +849,9 @@ static void handle_configure(struct libdecor_frame *frame,
if (!window->xdg_surface) window->xdg_surface = libdecor_frame_get_xdg_surface(frame);
+#ifdef LIBDECOR_MR131
+ if (is_1st_run) use_FLTK_toplevel_configure_cb(frame);
+#endif
struct wl_output *wl_output = NULL;
if (window->fl_win->fullscreen_active()) {
if (!(window->state & LIBDECOR_WINDOW_STATE_FULLSCREEN)) {
@@ -839,7 +905,10 @@ static void handle_configure(struct libdecor_frame *frame,
//fprintf(stderr,"handle_configure: using floating %dx%d\n",width,height);
}
- bool condition = (window->state & LIBDECOR_WINDOW_STATE_RESIZING);
+#ifndef LIBDECOR_MR131
+ bool in_decorated_window_resizing = (window->state & LIBDECOR_WINDOW_STATE_RESIZING);
+#endif
+ bool condition = in_decorated_window_resizing;
if (condition) { // see issue #878
condition = (window->covered ? (window->buffer && window->buffer->in_use) : (window->frame_cb != NULL));
}