From 182617513ef1985f696bedb9c86cf8d6436b6cdf Mon Sep 17 00:00:00 2001 From: Window Maker Date: Sun, 24 May 2026 10:20:01 +0200 Subject: [PATCH] wings(wayland-client): build system + connection skeleton MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- +cmd | 8 ++ WINGs/Makefile.am | 28 +++- WINGs/WINGs/WINGsP.h.in | 19 +++ WINGs/wclient_wl.c | 263 +++++++++++++++++++++++++++++++++++++ WINGs/xdg-shell-protocol.c | 184 ++++++++++++++++++++++++++ configure.ac | 43 ++++++ 6 files changed, 543 insertions(+), 2 deletions(-) create mode 100644 WINGs/wclient_wl.c create mode 100644 WINGs/xdg-shell-protocol.c diff --git a/+cmd b/+cmd index fb4a9ad..aa17bd0 100644 --- a/+cmd +++ b/+cmd @@ -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 diff --git a/WINGs/Makefile.am b/WINGs/Makefile.am index a4592b4..e5488e0 100644 --- a/WINGs/Makefile.am +++ b/WINGs/Makefile.am @@ -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 diff --git a/WINGs/WINGs/WINGsP.h.in b/WINGs/WINGs/WINGsP.h.in index 361851b..8ce9f8c 100644 --- a/WINGs/WINGs/WINGsP.h.in +++ b/WINGs/WINGs/WINGsP.h.in @@ -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 ]--------------------------------------------------------- */ diff --git a/WINGs/wclient_wl.c b/WINGs/wclient_wl.c new file mode 100644 index 0000000..8f8749a --- /dev/null +++ b/WINGs/wclient_wl.c @@ -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 +#include "xdg-shell-client-protocol.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* ------------------------------------------------------------------ */ +/* 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, ®istry_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 */ diff --git a/WINGs/xdg-shell-protocol.c b/WINGs/xdg-shell-protocol.c new file mode 100644 index 0000000..5a50433 --- /dev/null +++ b/WINGs/xdg-shell-protocol.c @@ -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 +#include +#include +#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, +}; + diff --git a/configure.ac b/configure.ac index 90257ea..142ff4f 100644 --- a/configure.ac +++ b/configure.ac @@ -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