Allow libdecor package version ≥ 0.2.0 with FLTK_USE_SYSTEM_LIBDECOR

This commit is contained in:
ManoloFLTK 2024-04-18 19:32:47 +02:00
parent 3fc8875756
commit e6957fc2f5
9 changed files with 110 additions and 23 deletions

View File

@ -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()

View File

@ -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)

View File

@ -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.

View File

@ -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"

View File

@ -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
<a href=https://wayland.app/protocols/xdg-decoration-unstable-v1>XDG decoration</a>
to request being decorated by a supporting compositor.

View File

@ -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;
}

View File

@ -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)

View File

@ -47,7 +47,7 @@
#include <string.h> // 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;
}
}

View File

@ -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));
}