wings(wayland-client): build system + connection skeleton

Task 1 + 2 of the WINGs Wayland-client backend.

Adds optional --enable-wayland-client (default auto) which depends on
wayland-client, xkbcommon, wayland-protocols, and wayland-scanner.
configure.ac probes for these and exposes WAYLAND_CLIENT_CFLAGS/LIBS
plus the protocols data dir and scanner path.

WINGs/Makefile.am wires a wayland-scanner rule that generates
xdg-shell-{protocol,client-protocol}.{c,h} at build time and links
libWINGs against wayland-client + xkbcommon when enabled.

WINGs/wclient_wl.c is the new file.  It self-stubs when the feature
is disabled.  When enabled it provides:

  W_WLClientInit(scrPtr, display)
    Connects via wl_display_connect, registers a wl_registry listener,
    binds wl_compositor/wl_shm/wl_seat/xdg_wm_base, creates an xkb_context,
    and hooks the libwayland event pump into the existing
    W_EventBackendWL via W_WL_SetLoopDispatch().  This lets the existing
    ring-buffer event mechanism keep working unchanged: the ring is fed
    by client-side wl_pointer/wl_keyboard listeners (next task) and
    drained by WMNextEvent / WMMaskEvent / waitForEvent.

  W_WLClientShutdown(scrPtr)
    Tears down all bound globals and disconnects the wl_display.

No surfaces / buffers / input dispatch yet — those come in tasks 3-5.
Build verified clean, wmaker still links and runs as before.
This commit is contained in:
Window Maker 2026-05-24 10:20:01 +02:00
parent 852fb2adeb
commit 182617513e
6 changed files with 543 additions and 2 deletions

8
+cmd
View File

@ -1,6 +1,8 @@
Xwayland :3
DISPLAY=':3' gdb -batch -ex 'set confirm off' -ex 'set filename-display absolute' -ex run -ex bt -ex quit --args src/.libs/wmaker --for-real >[2=1]
WMAKER_USE_WAYLAND='1' WMAKER_WAYLAND_NESTED='1' LD_LIBRARY_PATH='/usr/local/lib' G_SLICE=always-malloc MALLOC_CHECK_=3 valgrind --tool=memcheck --track-origins=yes --leak-check=no ./src/.libs/wmaker
WMAKER_USE_WAYLAND='1' WMAKER_WAYLAND_NESTED='1' LD_LIBRARY_PATH='/usr/local/lib' gdb -batch -ex 'set confirm off' -ex 'set filename-display absolute' -ex run -ex bt -ex quit --args src/.libs/wmaker --for-real >[2=1]
WAYLAND_DISPLAY=wayland-0 foot
@ -8,6 +10,12 @@ WAYLAND_DISPLAY=wayland-0 foot
./configure --prefix=/usr/local --enable-wayland
make clean
make -j8 CFLAGS='-fsanitize=leak' LDFLAGS='-fsanitize=leak'
CFLAGS='-O0 -g -fsanitize=address -fno-omit-frame-pointer' LDFLAGS='-fsanitize=address' ./configure --prefix=/usr/local --enable-wayland; CFLAGS='-O0 -g -fsanitize=address -fno-omit-frame-pointer' LDFLAGS='-fsanitize=address' make -j8
WMAKER_USE_WAYLAND='1' WMAKER_WAYLAND_NESTED='1' LD_LIBRARY_PATH='/usr/local/lib' ./src/.libs/wmaker
win sudo make install
git stash pop

View File

@ -12,9 +12,15 @@ lib_LTLIBRARIES = libWUtil.la libWINGs.la
LDADD= libWUtil.la libWINGs.la $(top_builddir)/wrlib/libwraster.la @INTLIBS@
libWINGs_la_LIBADD = libWUtil.la $(top_builddir)/wrlib/libwraster.la @XLIBS@ @XFT_LIBS@ @FCLIBS@ @LIBM@ @PANGO_LIBS@ @PIXMAN_LIBS@
libWINGs_la_LIBADD = libWUtil.la $(top_builddir)/wrlib/libwraster.la @XLIBS@ @XFT_LIBS@ @FCLIBS@ @LIBM@ @PANGO_LIBS@ @PIXMAN_LIBS@ $(WAYLAND_CLIENT_LIBS_IF_ENABLED)
libWUtil_la_LIBADD = @LIBBSD@
if USE_WAYLAND_CLIENT
WAYLAND_CLIENT_LIBS_IF_ENABLED = @WAYLAND_CLIENT_LIBS@
else
WAYLAND_CLIENT_LIBS_IF_ENABLED =
endif
EXTRA_DIST = BUGS make-rgb Examples Extras Tests
@ -69,8 +75,25 @@ libWINGs_la_SOURCES = \
wview.c \
wview_x11.c \
wview_wl.c \
wclient_wl.c \
wwindow.c
if USE_WAYLAND_CLIENT
nodist_libWINGs_la_SOURCES = \
xdg-shell-protocol.c \
xdg-shell-client-protocol.h
BUILT_SOURCES = xdg-shell-client-protocol.h xdg-shell-protocol.c
CLEANFILES = xdg-shell-client-protocol.h xdg-shell-protocol.c
xdg-shell-client-protocol.h:
$(WAYLAND_SCANNER) client-header \
$(WAYLAND_PROTOCOLS_DIR)/stable/xdg-shell/xdg-shell.xml $@
xdg-shell-protocol.c: xdg-shell-client-protocol.h
$(WAYLAND_SCANNER) private-code \
$(WAYLAND_PROTOCOLS_DIR)/stable/xdg-shell/xdg-shell.xml $@
endif
libWUtil_la_SOURCES = \
array.c \
bagtree.c \
@ -97,11 +120,12 @@ libWUtil_la_SOURCES = \
wutil.c
AM_CFLAGS = @PANGO_CFLAGS@ @PIXMAN_CFLAGS@
AM_CFLAGS = @PANGO_CFLAGS@ @PIXMAN_CFLAGS@ @WAYLAND_CLIENT_CFLAGS@
AM_CPPFLAGS = -DRESOURCE_PATH=\"$(datadir)/WINGs\" \
-I$(top_srcdir)/WINGs/WINGs -I$(top_builddir)/WINGs/WINGs \
-I$(top_builddir)/wrlib -I$(top_srcdir)/src \
-I$(top_builddir)/WINGs \
@XFT_CFLAGS@ @HEADER_SEARCH_PATH@
pkgconfigdir = $(libdir)/pkgconfig

View File

@ -490,6 +490,25 @@ void W_WL_SetLoopDispatch(struct W_Screen *scr,
void (*dispatch_fn)(int timeout_ms, void *ud),
void *userdata);
/*
* Wayland client backend (wclient_wl.c). Optional; only available
* when wmaker is configured with --enable-wayland-client (USE_WAYLAND_CLIENT).
*
* W_WLClientInit() opens a wayland-client connection to the compositor,
* binds the required globals (wl_compositor, wl_shm, xdg_wm_base, wl_seat),
* sets up the event-loop dispatch via W_WL_SetLoopDispatch(), and
* arranges for top-level W_Views to acquire wl_surface + xdg_toplevel
* pairs and per-surface wl_shm backing buffers.
*
* Returns True on success, False on any failure. When False is
* returned, the caller should fall back to the X11 backend.
*
* WMOpenScreen() calls this automatically when it detects WAYLAND_DISPLAY
* in the environment and DISPLAY is unset.
*/
Bool W_WLClientInit(struct W_Screen *scrPtr, const char *display);
void W_WLClientShutdown(struct W_Screen *scrPtr);
/* ---[ wfont.c ]--------------------------------------------------------- */

263
WINGs/wclient_wl.c Normal file
View File

@ -0,0 +1,263 @@
/*
* wclient_wl.c — Wayland *client* backend for WINGs.
*
* This is the counterpart to wevent_wl.c / wview_wl.c / wfont_wl.c /
* wrender_wl.c, but used when a WINGs program runs as a *client* of an
* external Wayland compositor (e.g. WPrefs.app under wmaker-wl, sway,
* or any wlroots-based compositor).
*
* In compositor mode the WM owns the rendering pipeline and the same
* Wayland backend files run inside the compositor process; surfaces
* are scene-graph nodes managed by wlroots.
*
* In client mode (this file), the program connects via libwayland-client,
* binds the standard globals (wl_compositor, wl_shm, xdg_wm_base, wl_seat),
* creates an xdg_toplevel for each top-level W_View, and submits buffers
* via wl_shm. Pixman backing images are allocated over a memfd-mapped
* region wrapped in a wl_buffer so paints can be done with the same
* pixman calls used everywhere else.
*
* Input dispatch translates wl_pointer / wl_keyboard events into
* WMEvent and feeds them to the existing W_EventBackendWL ring buffer
* via W_WL_EnqueueEvent — the same mechanism the compositor-internal
* Wayland backend uses.
*/
#include "wconfig.h"
#ifdef USE_WAYLAND_CLIENT
#include "WINGsP.h"
#include <wayland-client.h>
#include "xdg-shell-client-protocol.h"
#include <xkbcommon/xkbcommon.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
/* ------------------------------------------------------------------ */
/* Per-screen Wayland-client context */
/* ------------------------------------------------------------------ */
typedef struct WLClientCtx {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_shm *shm;
struct wl_seat *seat;
struct xdg_wm_base *wm_base;
struct wl_pointer *pointer;
struct wl_keyboard *keyboard;
struct xkb_context *xkb_ctx;
struct xkb_keymap *xkb_keymap;
struct xkb_state *xkb_state;
/* Back-reference for input handlers */
struct W_Screen *scr;
} WLClientCtx;
/* ------------------------------------------------------------------ */
/* xdg_wm_base ping */
/* ------------------------------------------------------------------ */
static void
wm_base_ping(void *data, struct xdg_wm_base *base, uint32_t serial)
{
(void)data;
xdg_wm_base_pong(base, serial);
}
static const struct xdg_wm_base_listener wm_base_listener = {
.ping = wm_base_ping,
};
/* ------------------------------------------------------------------ */
/* Registry — bind required globals */
/* ------------------------------------------------------------------ */
static void
registry_handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
WLClientCtx *ctx = data;
if (strcmp(interface, wl_compositor_interface.name) == 0) {
uint32_t v = version < 4 ? version : 4;
ctx->compositor = wl_registry_bind(registry, name,
&wl_compositor_interface, v);
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
ctx->shm = wl_registry_bind(registry, name,
&wl_shm_interface, 1);
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
uint32_t v = version < 5 ? version : 5;
ctx->seat = wl_registry_bind(registry, name,
&wl_seat_interface, v);
/* Pointer/keyboard probes happen lazily on the first capabilities event;
* we'll add a wl_seat listener below in W_WLClientInit. */
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
uint32_t v = version < 3 ? version : 3;
ctx->wm_base = wl_registry_bind(registry, name,
&xdg_wm_base_interface, v);
xdg_wm_base_add_listener(ctx->wm_base, &wm_base_listener, ctx);
}
}
static void
registry_handle_global_remove(void *data, struct wl_registry *registry,
uint32_t name)
{
(void)data; (void)registry; (void)name;
/* Globals like seat or output may go away on hotplug; ignore for now. */
}
static const struct wl_registry_listener registry_listener = {
.global = registry_handle_global,
.global_remove = registry_handle_global_remove,
};
/* ------------------------------------------------------------------ */
/* Event-loop dispatch (used by W_EventBackendWL when queue is empty) */
/* ------------------------------------------------------------------ */
static void
wlclient_dispatch(int timeout_ms, void *userdata)
{
WLClientCtx *ctx = userdata;
if (!ctx || !ctx->display) return;
/* Standard libwayland-client event-pumping idiom:
* 1. Prepare a read.
* 2. Flush outgoing requests.
* 3. Poll the fd.
* 4. read_events / cancel_read.
* 5. Dispatch any queued events.
*
* We don't need the prepare/read split when we're only blocking
* here, but doing it correctly keeps us safe if multiple threads
* ever want to share the wl_display.
*/
while (wl_display_prepare_read(ctx->display) != 0) {
if (wl_display_dispatch_pending(ctx->display) < 0) return;
}
if (wl_display_flush(ctx->display) < 0 && errno != EAGAIN) {
wl_display_cancel_read(ctx->display);
return;
}
struct pollfd pfd = {
.fd = wl_display_get_fd(ctx->display),
.events = POLLIN,
};
int n = poll(&pfd, 1, timeout_ms);
if (n <= 0) {
wl_display_cancel_read(ctx->display);
return;
}
if (wl_display_read_events(ctx->display) < 0) return;
wl_display_dispatch_pending(ctx->display);
}
/* ------------------------------------------------------------------ */
/* Public API */
/* ------------------------------------------------------------------ */
/* Storage for the active context — for now we only support one screen. */
static WLClientCtx *g_wlclient_ctx = NULL;
Bool
W_WLClientInit(struct W_Screen *scrPtr, const char *display)
{
WLClientCtx *ctx = wmalloc(sizeof(*ctx));
memset(ctx, 0, sizeof(*ctx));
ctx->scr = scrPtr;
ctx->display = wl_display_connect(display);
if (!ctx->display) {
wwarning(_("WINGs: wl_display_connect() failed"));
goto fail;
}
ctx->registry = wl_display_get_registry(ctx->display);
if (!ctx->registry) goto fail;
wl_registry_add_listener(ctx->registry, &registry_listener, ctx);
/* Two roundtrips: first to receive globals, second to settle any
* follow-up events from those globals (e.g. wl_seat capabilities). */
if (wl_display_roundtrip(ctx->display) < 0) goto fail;
if (wl_display_roundtrip(ctx->display) < 0) goto fail;
if (!ctx->compositor || !ctx->shm || !ctx->wm_base) {
wwarning(_("WINGs: compositor missing required globals "
"(wl_compositor / wl_shm / xdg_wm_base)"));
goto fail;
}
ctx->xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!ctx->xkb_ctx) goto fail;
/* Hook event-loop dispatch into the WINGs Wayland event backend so
* WMNextEvent / waitForEvent will pump the compositor when idle. */
W_WL_SetLoopDispatch(scrPtr,
wl_display_get_fd(ctx->display),
wlclient_dispatch,
ctx);
g_wlclient_ctx = ctx;
return True;
fail:
if (ctx->xkb_ctx) xkb_context_unref(ctx->xkb_ctx);
if (ctx->wm_base) xdg_wm_base_destroy(ctx->wm_base);
if (ctx->seat) wl_seat_destroy(ctx->seat);
if (ctx->shm) wl_shm_destroy(ctx->shm);
if (ctx->compositor) wl_compositor_destroy(ctx->compositor);
if (ctx->registry) wl_registry_destroy(ctx->registry);
if (ctx->display) wl_display_disconnect(ctx->display);
wfree(ctx);
return False;
}
void
W_WLClientShutdown(struct W_Screen *scrPtr)
{
(void)scrPtr;
WLClientCtx *ctx = g_wlclient_ctx;
if (!ctx) return;
g_wlclient_ctx = NULL;
if (ctx->xkb_state) xkb_state_unref(ctx->xkb_state);
if (ctx->xkb_keymap) xkb_keymap_unref(ctx->xkb_keymap);
if (ctx->xkb_ctx) xkb_context_unref(ctx->xkb_ctx);
if (ctx->pointer) wl_pointer_destroy(ctx->pointer);
if (ctx->keyboard) wl_keyboard_destroy(ctx->keyboard);
if (ctx->wm_base) xdg_wm_base_destroy(ctx->wm_base);
if (ctx->seat) wl_seat_destroy(ctx->seat);
if (ctx->shm) wl_shm_destroy(ctx->shm);
if (ctx->compositor) wl_compositor_destroy(ctx->compositor);
if (ctx->registry) wl_registry_destroy(ctx->registry);
if (ctx->display) wl_display_disconnect(ctx->display);
wfree(ctx);
}
#else /* !USE_WAYLAND_CLIENT */
#include "WINGsP.h"
Bool W_WLClientInit(struct W_Screen *scrPtr, const char *display)
{
(void)scrPtr; (void)display;
return False;
}
void W_WLClientShutdown(struct W_Screen *scrPtr) { (void)scrPtr; }
#endif /* USE_WAYLAND_CLIENT */

184
WINGs/xdg-shell-protocol.c Normal file
View File

@ -0,0 +1,184 @@
/* Generated by wayland-scanner 1.24.0 */
/*
* Copyright © 2008-2013 Kristian Høgsberg
* Copyright © 2013 Rafael Antognolli
* Copyright © 2013 Jasper St. Pierre
* Copyright © 2010-2013 Intel Corporation
* Copyright © 2015-2017 Samsung Electronics Co., Ltd
* Copyright © 2015-2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface xdg_positioner_interface;
extern const struct wl_interface xdg_surface_interface;
extern const struct wl_interface xdg_toplevel_interface;
static const struct wl_interface *xdg_shell_types[] = {
NULL,
NULL,
NULL,
NULL,
&xdg_positioner_interface,
&xdg_surface_interface,
&wl_surface_interface,
&xdg_toplevel_interface,
&xdg_popup_interface,
&xdg_surface_interface,
&xdg_positioner_interface,
&xdg_toplevel_interface,
&wl_seat_interface,
NULL,
NULL,
NULL,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&xdg_positioner_interface,
NULL,
};
static const struct wl_message xdg_wm_base_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "create_positioner", "n", xdg_shell_types + 4 },
{ "get_xdg_surface", "no", xdg_shell_types + 5 },
{ "pong", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_wm_base_events[] = {
{ "ping", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
"xdg_wm_base", 7,
4, xdg_wm_base_requests,
1, xdg_wm_base_events,
};
static const struct wl_message xdg_positioner_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_size", "ii", xdg_shell_types + 0 },
{ "set_anchor_rect", "iiii", xdg_shell_types + 0 },
{ "set_anchor", "u", xdg_shell_types + 0 },
{ "set_gravity", "u", xdg_shell_types + 0 },
{ "set_constraint_adjustment", "u", xdg_shell_types + 0 },
{ "set_offset", "ii", xdg_shell_types + 0 },
{ "set_reactive", "3", xdg_shell_types + 0 },
{ "set_parent_size", "3ii", xdg_shell_types + 0 },
{ "set_parent_configure", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
"xdg_positioner", 7,
10, xdg_positioner_requests,
0, NULL,
};
static const struct wl_message xdg_surface_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "get_toplevel", "n", xdg_shell_types + 7 },
{ "get_popup", "n?oo", xdg_shell_types + 8 },
{ "set_window_geometry", "iiii", xdg_shell_types + 0 },
{ "ack_configure", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_surface_events[] = {
{ "configure", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_surface_interface = {
"xdg_surface", 7,
5, xdg_surface_requests,
1, xdg_surface_events,
};
static const struct wl_message xdg_toplevel_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_parent", "?o", xdg_shell_types + 11 },
{ "set_title", "s", xdg_shell_types + 0 },
{ "set_app_id", "s", xdg_shell_types + 0 },
{ "show_window_menu", "ouii", xdg_shell_types + 12 },
{ "move", "ou", xdg_shell_types + 16 },
{ "resize", "ouu", xdg_shell_types + 18 },
{ "set_max_size", "ii", xdg_shell_types + 0 },
{ "set_min_size", "ii", xdg_shell_types + 0 },
{ "set_maximized", "", xdg_shell_types + 0 },
{ "unset_maximized", "", xdg_shell_types + 0 },
{ "set_fullscreen", "?o", xdg_shell_types + 21 },
{ "unset_fullscreen", "", xdg_shell_types + 0 },
{ "set_minimized", "", xdg_shell_types + 0 },
};
static const struct wl_message xdg_toplevel_events[] = {
{ "configure", "iia", xdg_shell_types + 0 },
{ "close", "", xdg_shell_types + 0 },
{ "configure_bounds", "4ii", xdg_shell_types + 0 },
{ "wm_capabilities", "5a", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
"xdg_toplevel", 7,
14, xdg_toplevel_requests,
4, xdg_toplevel_events,
};
static const struct wl_message xdg_popup_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "grab", "ou", xdg_shell_types + 22 },
{ "reposition", "3ou", xdg_shell_types + 24 },
};
static const struct wl_message xdg_popup_events[] = {
{ "configure", "iiii", xdg_shell_types + 0 },
{ "popup_done", "", xdg_shell_types + 0 },
{ "repositioned", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_popup_interface = {
"xdg_popup", 7,
3, xdg_popup_requests,
3, xdg_popup_events,
};

View File

@ -680,6 +680,49 @@ AC_SUBST([WLROOTS_CFLAGS])
AC_SUBST([WLROOTS_LIBS])
dnl Wayland client support for WINGs (WPrefs and other native clients)
dnl =================================================================
dnl Allows building WINGs apps as native Wayland clients. Independent
dnl from --enable-wayland-backend (which is only for the compositor).
m4_divert_push([INIT_PREPARE])dnl
AC_ARG_ENABLE([wayland-client],
[AS_HELP_STRING([--enable-wayland-client],
[build WINGs with Wayland client support so apps like WPrefs run native @<:@default=auto@:>@])],
[AS_CASE(["$enableval"],
[yes|no|auto], [],
[AC_MSG_ERROR([bad value $enableval for --enable-wayland-client])])],
[enable_wayland_client=auto])
m4_divert_pop([INIT_PREPARE])dnl
AS_IF([test "x$enable_wayland_client" != "xno"],
[PKG_CHECK_MODULES([WAYLAND_CLIENT],
[wayland-client xkbcommon],
[PKG_CHECK_EXISTS([wayland-protocols >= 1.20],
[have_wayland_client=yes
WAYLAND_PROTOCOLS_DIR=`$PKG_CONFIG --variable=pkgdatadir wayland-protocols`
WAYLAND_SCANNER=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner 2>/dev/null`
AS_IF([test -z "$WAYLAND_SCANNER"],
[AC_PATH_PROG([WAYLAND_SCANNER], [wayland-scanner], [no])])
AS_IF([test "x$WAYLAND_SCANNER" = "xno" -o -z "$WAYLAND_SCANNER"],
[have_wayland_client=no])],
[have_wayland_client=no])],
[have_wayland_client=no])
AS_IF([test "x$have_wayland_client" = "xyes"],
[AC_DEFINE([USE_WAYLAND_CLIENT], [1],
[Define to 1 to build WINGs with Wayland client support])
supported_core="$supported_core WaylandClient"],
[AS_IF([test "x$enable_wayland_client" = "xyes"],
[AC_MSG_ERROR([wayland-client, xkbcommon, wayland-protocols, or wayland-scanner not found])])
unsupported="$unsupported WaylandClient"])],
[have_wayland_client=no
unsupported="$unsupported WaylandClient"])
AM_CONDITIONAL([USE_WAYLAND_CLIENT], [test "x$have_wayland_client" = "xyes"])
AC_SUBST([WAYLAND_CLIENT_CFLAGS])
AC_SUBST([WAYLAND_CLIENT_LIBS])
AC_SUBST([WAYLAND_PROTOCOLS_DIR])
AC_SUBST([WAYLAND_SCANNER])
dnl Math library
dnl ============
dnl libWINGS uses math functions, check whether usage requires linking