From 2d9b9b76c5c69b0b6f72f789bd669b52cfbc6f0b Mon Sep 17 00:00:00 2001 From: Levi Neely <141506390+lneely@users.noreply.github.com> Date: Sun, 10 May 2026 18:51:05 +0200 Subject: [PATCH] wayland: migrate wlroots 0.16 API to 0.19 + animation overlay system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port from wlroots ~0.16 to 0.19 (Gentoo slotted packages) and add the Phase 81 XOR animation overlay. Fixes Gentoo build from scratch. configure.ac: detect wlroots-0.19 versioned slot before falling back to unversioned; fixes "Package wlroots was not found" on Gentoo. startup.c: add missing for XrmUniqueQuark on Gentoo's stricter X11 headers. wl_backend.c — wlroots 0.16→0.19 API migration: - Backend creation: display* → wl_event_loop* (get_event_loop) - wlr_output_layout_create gains display* arg - Output configuration: wlr_output_enable/commit/set_mode → wlr_output_state API - wlr_output_layout_get_box: returns void, writes to caller-supplied box - Scene graph: scene root is scene->tree (wlr_scene_tree*); create functions return/accept wlr_scene_tree*; scene_node.state.x/y → .x/.y - wlr_scene_output_commit gains options arg (NULL) - Protocol globals gain version args: compositor(6), xdg_shell(3), layer_shell(4), linux_dmabuf_with_renderer(4), presentation(1) - Input: dev->keyboard/pointer embedded fields removed; use wlr_keyboard/pointer_from_input_device(); headless backend no longer has input devices; XKB keymap created independently at startup - Keyboard: wlr_event_keyboard_key → wlr_keyboard_key_event; wlr_seat_set_keyboard takes wlr_keyboard* directly - Pointer: all wlr_event_pointer_* → wlr_pointer_*_event; wlr_seat_pointer_notify_axis gains relative_direction arg; wlr_cursor_warp_absolute uses &ev->pointer->base - Cursor: wlr_xcursor_manager_set_cursor_image → wlr_cursor_set_xcursor - XDG shell: xdg_surface->events.map/unmap → surface->events.map/unmap; xdg_surface->mapped → surface->mapped; toplevel_set_size/send_close/ parent take wlr_xdg_toplevel* - XWayland: events.map/unmap → events.associate/dissociate; xw->mapped → xw->surface->mapped; size_hints is xcb_size_hints_t* - Layer shell: ls->events.map/unmap → ls->surface->events.map/unmap - wlr_buffer: include wlr/interfaces/wlr_buffer.h for wlr_buffer_init - Remove wlr_input_inhibitor and wlr_idle (dropped in wlroots 0.18) wl_backend.c — Phase 81 XOR animation overlay: - Full-screen pixman SHM overlay surface for move/resize rubber-band guides and miniaturize animations - Embedded 5×9 bitmap font (96 printable ASCII glyphs) - Bresenham line drawing; hline/vline fast paths - overlay_ensure: lazy alloc/resize tied to WScreen dimensions - server_ungrab flushes overlay to scene graph Co-Authored-By: Claude Sonnet 4.6 --- aclocal.m4 | 567 ++++++++++++++++------- configure.ac | 7 +- m4/ltoptions.m4 | 108 +++-- m4/ltsugar.m4 | 2 +- m4/ltversion.m4 | 13 +- m4/lt~obsolete.m4 | 4 +- src/backend/wayland/wl_backend.c | 768 ++++++++++++++++++++----------- src/startup.c | 1 + 8 files changed, 994 insertions(+), 476 deletions(-) diff --git a/aclocal.m4 b/aclocal.m4 index 92963c5..4b514dc 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.16.2 -*- Autoconf -*- +# generated automatically by aclocal 1.18.1 -*- Autoconf -*- -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2025 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -14,14 +14,14 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, -[m4_warning([this file was generated for autoconf 2.69. +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.72],, +[m4_warning([this file was generated for autoconf 2.72. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) -# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- -# serial 12 (pkg-config-0.29.2) +# pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- +# serial 13 (pkgconf) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson @@ -37,9 +37,7 @@ dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License -dnl along with this program; if not, write to the Free Software -dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -dnl 02111-1307, USA. +dnl along with this program; if not, see . dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a @@ -68,8 +66,8 @@ m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ -dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) -dnl ---------------------------------- +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION], [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to @@ -77,6 +75,12 @@ dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. +dnl +dnl If pkg-config is not found or older than specified, it will result +dnl in an empty PKG_CONFIG variable. To avoid widespread issues with +dnl scripts not checking it, ACTION-IF-NOT-FOUND defaults to aborting. +dnl You can specify [PKG_CONFIG=false] as an action instead, which would +dnl result in pkg-config tests failing, but no bogus error messages. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) @@ -97,6 +101,9 @@ if test -n "$PKG_CONFIG"; then AC_MSG_RESULT([no]) PKG_CONFIG="" fi +fi +if test -z "$PKG_CONFIG"; then + m4_default([$2], [AC_MSG_ERROR([pkg-config not found])]) fi[]dnl ])dnl PKG_PROG_PKG_CONFIG @@ -108,7 +115,7 @@ dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -dnl only at the first occurence in configure.ac, so if the first place +dnl only at the first occurrence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], @@ -177,14 +184,14 @@ if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then - $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else - $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi - # Put the nasty error message in config.log where it belongs - echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD - m4_default([$4], [AC_MSG_ERROR( + m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS @@ -196,7 +203,7 @@ _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) - m4_default([$4], [AC_MSG_FAILURE( + m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. @@ -206,10 +213,10 @@ _PKG_TEXT To get pkg-config, see .])[]dnl ]) else - $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS - $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) - $3 + $3 fi[]dnl ])dnl PKG_CHECK_MODULES @@ -296,7 +303,75 @@ AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR -# Copyright (C) 2002-2020 Free Software Foundation, Inc. +dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], +dnl [DESCRIPTION], [DEFAULT]) +dnl ------------------------------------------ +dnl +dnl Prepare a "--with-" configure option using the lowercase +dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and +dnl PKG_CHECK_MODULES in a single macro. +AC_DEFUN([PKG_WITH_MODULES], +[ +m4_pushdef([with_arg], m4_tolower([$1])) + +m4_pushdef([description], + [m4_default([$5], [build with ]with_arg[ support])]) + +m4_pushdef([def_arg], [m4_default([$6], [auto])]) +m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) +m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) + +m4_case(def_arg, + [yes],[m4_pushdef([with_without], [--without-]with_arg)], + [m4_pushdef([with_without],[--with-]with_arg)]) + +AC_ARG_WITH(with_arg, + AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, + [AS_TR_SH([with_]with_arg)=def_arg]) + +AS_CASE([$AS_TR_SH([with_]with_arg)], + [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], + [auto],[PKG_CHECK_MODULES([$1],[$2], + [m4_n([def_action_if_found]) $3], + [m4_n([def_action_if_not_found]) $4])]) + +m4_popdef([with_arg]) +m4_popdef([description]) +m4_popdef([def_arg]) + +])dnl PKG_WITH_MODULES + +dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [DESCRIPTION], [DEFAULT]) +dnl ----------------------------------------------- +dnl +dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES +dnl check._[VARIABLE-PREFIX] is exported as make variable. +AC_DEFUN([PKG_HAVE_WITH_MODULES], +[ +PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) + +AM_CONDITIONAL([HAVE_][$1], + [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) +])dnl PKG_HAVE_WITH_MODULES + +dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [DESCRIPTION], [DEFAULT]) +dnl ------------------------------------------------------ +dnl +dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after +dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make +dnl and preprocessor variable. +AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], +[ +PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) + +AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], + [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) +])dnl PKG_HAVE_DEFINE_WITH_MODULES + +# Copyright (C) 2002-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -308,10 +383,10 @@ AS_VAR_IF([$1], [""], [$5], [$4])dnl # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.16' +[am__api_version='1.18' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.16.2], [], +m4_if([$1], [1.18.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -327,14 +402,14 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.16.2])dnl +[AM_AUTOMAKE_VERSION([1.18.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -386,7 +461,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd` # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2020 Free Software Foundation, Inc. +# Copyright (C) 1997-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -417,7 +492,7 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999-2020 Free Software Foundation, Inc. +# Copyright (C) 1999-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -549,7 +624,7 @@ AC_CACHE_CHECK([dependency style of $depcc], # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: + # When given -MP, icc 7.0 and 7.1 complain thus: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported @@ -608,7 +683,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999-2020 Free Software Foundation, Inc. +# Copyright (C) 1999-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -676,7 +751,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], # Do all the work for Automake. -*- Autoconf -*- -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -704,6 +779,10 @@ m4_defn([AC_PROG_CC]) # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl +m4_ifdef([_$0_ALREADY_INIT], + [m4_fatal([$0 expanded multiple times +]m4_defn([_$0_ALREADY_INIT]))], + [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl @@ -740,7 +819,7 @@ m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( - m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl @@ -772,8 +851,9 @@ AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], - [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_PROG_TAR([v7])])]) + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_IF_OPTION([tar-v7], [_AM_PROG_TAR([v7])], + [_AM_PROG_TAR([ustar])])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], @@ -792,7 +872,21 @@ AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) -AC_REQUIRE([AM_SILENT_RULES])dnl +# Variables for tags utilities; see am/tags.am +if test -z "$CTAGS"; then + CTAGS=ctags +fi +AC_SUBST([CTAGS]) +if test -z "$ETAGS"; then + ETAGS=etags +fi +AC_SUBST([ETAGS]) +if test -z "$CSCOPE"; then + CSCOPE=cscope +fi +AC_SUBST([CSCOPE]) + +AC_REQUIRE([_AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. @@ -800,47 +894,9 @@ AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl -# POSIX will say in a future version that running "rm -f" with no argument -# is OK; and we want to be able to make that assumption in our Makefile -# recipes. So use an aggressive probe to check that the usage we want is -# actually supported "in the wild" to an acceptable degree. -# See automake bug#10828. -# To make any issue more visible, cause the running configure to be aborted -# by default if the 'rm' program in use doesn't match our expectations; the -# user can still override this though. -if rm -f && rm -fr && rm -rf; then : OK; else - cat >&2 <<'END' -Oops! +AC_REQUIRE([_AM_PROG_RM_F]) +AC_REQUIRE([_AM_PROG_XARGS_N]) -Your 'rm' program seems unable to run without file operands specified -on the command line, even when the '-f' option is present. This is contrary -to the behaviour of most rm programs out there, and not conforming with -the upcoming POSIX standard: - -Please tell bug-automake@gnu.org about your system, including the value -of your $PATH and any error possibly output before this message. This -can help us improve future automake versions. - -END - if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then - echo 'Configuration will proceed anyway, since you have set the' >&2 - echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 - echo >&2 - else - cat >&2 <<'END' -Aborting the configuration process, to ensure you take notice of the issue. - -You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . - -If you want to complete the configuration process using your problematic -'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM -to "yes", and re-run configure. - -END - AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) - fi -fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. @@ -873,7 +929,7 @@ for _am_header in $config_headers :; do done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -894,7 +950,7 @@ if test x"${install_sh+set}" != xset; then fi AC_SUBST([install_sh])]) -# Copyright (C) 2003-2020 Free Software Foundation, Inc. +# Copyright (C) 2003-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -915,7 +971,7 @@ AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -958,7 +1014,7 @@ AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997-2020 Free Software Foundation, Inc. +# Copyright (C) 1997-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -979,12 +1035,7 @@ AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac + MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then @@ -997,7 +1048,7 @@ fi # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1026,7 +1077,7 @@ AC_DEFUN([_AM_SET_OPTIONS], AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -# Copyright (C) 1999-2020 Free Software Foundation, Inc. +# Copyright (C) 1999-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1058,7 +1109,10 @@ AC_CACHE_CHECK( break fi done - rm -f core conftest* + # aligned with autoconf, so not including core; see bug#72225. + rm -f -r a.out a.exe b.out conftest.$ac_ext conftest.$ac_objext \ + conftest.dSYM conftest1.$ac_ext conftest1.$ac_objext conftest1.dSYM \ + conftest2.$ac_ext conftest2.$ac_objext conftest2.dSYM unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. @@ -1073,7 +1127,23 @@ AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2022-2025 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_RM_F +# --------------- +# Check whether 'rm -f' without any arguments works. +# https://bugs.gnu.org/10828 +AC_DEFUN([_AM_PROG_RM_F], +[am__rm_f_notfound= +AS_IF([(rm -f && rm -fr && rm -rf) 2>/dev/null], [], [am__rm_f_notfound='""']) +AC_SUBST(am__rm_f_notfound) +]) + +# Copyright (C) 2001-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1092,26 +1162,181 @@ AC_DEFUN([AM_RUN_LOG], # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. +# _AM_SLEEP_FRACTIONAL_SECONDS +# ---------------------------- +AC_DEFUN([_AM_SLEEP_FRACTIONAL_SECONDS], [dnl +AC_CACHE_CHECK([whether sleep supports fractional seconds], + am_cv_sleep_fractional_seconds, [dnl +AS_IF([sleep 0.001 2>/dev/null], [am_cv_sleep_fractional_seconds=yes], + [am_cv_sleep_fractional_seconds=no]) +])]) + +# _AM_FILESYSTEM_TIMESTAMP_RESOLUTION +# ----------------------------------- +# Determine the filesystem's resolution for file modification +# timestamps. The coarsest we know of is FAT, with a resolution +# of only two seconds, even with the most recent "exFAT" extensions. +# The finest (e.g. ext4 with large inodes, XFS, ZFS) is one +# nanosecond, matching clock_gettime. However, it is probably not +# possible to delay execution of a shell script for less than one +# millisecond, due to process creation overhead and scheduling +# granularity, so we don't check for anything finer than that. (See below.) +AC_DEFUN([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION], [dnl +AC_REQUIRE([_AM_SLEEP_FRACTIONAL_SECONDS]) +AC_CACHE_CHECK([filesystem timestamp resolution], + am_cv_filesystem_timestamp_resolution, [dnl +# Default to the worst case. +am_cv_filesystem_timestamp_resolution=2 + +# Only try to go finer than 1 sec if sleep can do it. +# Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, +# - 1 sec is not much of a win compared to 2 sec, and +# - it takes 2 seconds to perform the test whether 1 sec works. +# +# Instead, just use the default 2s on platforms that have 1s resolution, +# accept the extra 1s delay when using $sleep in the Automake tests, in +# exchange for not incurring the 2s delay for running the test for all +# packages. +# +am_try_resolutions= +if test "$am_cv_sleep_fractional_seconds" = yes; then + # Even a millisecond often causes a bunch of false positives, + # so just try a hundredth of a second. The time saved between .001 and + # .01 is not terribly consequential. + am_try_resolutions="0.01 0.1 $am_try_resolutions" +fi + +# In order to catch current-generation FAT out, we must *modify* files +# that already exist; the *creation* timestamp is finer. Use names +# that make ls -t sort them differently when they have equal +# timestamps than when they have distinct timestamps, keeping +# in mind that ls -t prints the *newest* file first. +rm -f conftest.ts? +: > conftest.ts1 +: > conftest.ts2 +: > conftest.ts3 + +# Make sure ls -t actually works. Do 'set' in a subshell so we don't +# clobber the current shell's arguments. (Outer-level square brackets +# are removed by m4; they're present so that m4 does not expand +# ; be careful, easy to get confused.) +if ( + set X `[ls -t conftest.ts[12]]` && + { + test "$[]*" != "X conftest.ts1 conftest.ts2" || + test "$[]*" != "X conftest.ts2 conftest.ts1"; + } +); then :; else + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + _AS_ECHO_UNQUOTED( + ["Bad output from ls -t: \"`[ls -t conftest.ts[12]]`\""], + [AS_MESSAGE_LOG_FD]) + AC_MSG_FAILURE([ls -t produces unexpected output. +Make sure there is not a broken ls alias in your environment.]) +fi + +for am_try_res in $am_try_resolutions; do + # Any one fine-grained sleep might happen to cross the boundary + # between two values of a coarser actual resolution, but if we do + # two fine-grained sleeps in a row, at least one of them will fall + # entirely within a coarse interval. + echo alpha > conftest.ts1 + sleep $am_try_res + echo beta > conftest.ts2 + sleep $am_try_res + echo gamma > conftest.ts3 + + # We assume that 'ls -t' will make use of high-resolution + # timestamps if the operating system supports them at all. + if (set X `ls -t conftest.ts?` && + test "$[]2" = conftest.ts3 && + test "$[]3" = conftest.ts2 && + test "$[]4" = conftest.ts1); then + # + # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, + # because we don't need to test make. + make_ok=true + if test $am_try_res != 1; then + # But if we've succeeded so far with a subsecond resolution, we + # have one more thing to check: make. It can happen that + # everything else supports the subsecond mtimes, but make doesn't; + # notably on macOS, which ships make 3.81 from 2006 (the last one + # released under GPLv2). https://bugs.gnu.org/68808 + # + # We test $MAKE if it is defined in the environment, else "make". + # It might get overridden later, but our hope is that in practice + # it does not matter: it is the system "make" which is (by far) + # the most likely to be broken, whereas if the user overrides it, + # probably they did so with a better, or at least not worse, make. + # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html + # + # Create a Makefile (real tab character here): + rm -f conftest.mk + echo 'conftest.ts1: conftest.ts2' >conftest.mk + echo ' touch conftest.ts2' >>conftest.mk + # + # Now, running + # touch conftest.ts1; touch conftest.ts2; make + # should touch ts1 because ts2 is newer. This could happen by luck, + # but most often, it will fail if make's support is insufficient. So + # test for several consecutive successes. + # + # (We reuse conftest.ts[12] because we still want to modify existing + # files, not create new ones, per above.) + n=0 + make=${MAKE-make} + until test $n -eq 3; do + echo one > conftest.ts1 + sleep $am_try_res + echo two > conftest.ts2 # ts2 should now be newer than ts1 + if $make -f conftest.mk | grep 'up to date' >/dev/null; then + make_ok=false + break # out of $n loop + fi + n=`expr $n + 1` + done + fi + # + if $make_ok; then + # Everything we know to check worked out, so call this resolution good. + am_cv_filesystem_timestamp_resolution=$am_try_res + break # out of $am_try_res loop + fi + # Otherwise, we'll go on to check the next resolution. + fi +done +rm -f conftest.ts? +# (end _am_filesystem_timestamp_resolution) +])]) + # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], -[AC_MSG_CHECKING([whether build environment is sane]) +[AC_REQUIRE([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION]) +# This check should not be cached, as it may vary across builds of +# different projects. +AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_RESULT([no]) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_RESULT([no]) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac @@ -1120,49 +1345,40 @@ esac # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). -if ( - am_has_slept=no - for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$[*]" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - if test "$[*]" != "X $srcdir/configure conftest.file" \ - && test "$[*]" != "X conftest.file $srcdir/configure"; then +am_build_env_is_sane=no +am_has_slept=no +rm -f conftest.file +for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[]*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + test "$[]2" = conftest.file + ); then + am_build_env_is_sane=yes + break + fi + # Just in case. + sleep "$am_cv_filesystem_timestamp_resolution" + am_has_slept=yes +done - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken - alias in your environment]) - fi - if test "$[2]" = conftest.file || test $am_try -eq 2; then - break - fi - # Just in case. - sleep 1 - am_has_slept=yes - done - test "$[2]" = conftest.file - ) -then - # Ok. - : -else - AC_MSG_ERROR([newly created file is older than distributed files! +AC_MSG_RESULT([$am_build_env_is_sane]) +if test "$am_build_env_is_sane" = no; then + AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi -AC_MSG_RESULT([yes]) + # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= -if grep 'slept: no' conftest.file >/dev/null 2>&1; then - ( sleep 1 ) & +AS_IF([test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1],, [dnl + ( sleep "$am_cv_filesystem_timestamp_resolution" ) & am_sleep_pid=$! -fi +]) AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then @@ -1173,18 +1389,18 @@ AC_CONFIG_COMMANDS_PRE( rm -f conftest.file ]) -# Copyright (C) 2009-2020 Free Software Foundation, Inc. +# Copyright (C) 2009-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. -# AM_SILENT_RULES([DEFAULT]) -# -------------------------- -# Enable less verbose build rules; with the default set to DEFAULT -# ("yes" being less verbose, "no" or empty being verbose). -AC_DEFUN([AM_SILENT_RULES], -[AC_ARG_ENABLE([silent-rules], [dnl +# _AM_SILENT_RULES +# ---------------- +# Enable less verbose build rules support. +AC_DEFUN([_AM_SILENT_RULES], +[AM_DEFAULT_VERBOSITY=1 +AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) @@ -1192,11 +1408,6 @@ AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) -case $enable_silent_rules in @%:@ ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; - *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; -esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. @@ -1215,14 +1426,6 @@ am__doit: else am_cv_make_support_nested_variables=no fi]) -if test $am_cv_make_support_nested_variables = yes; then - dnl Using '$V' instead of '$(V)' breaks IRIX make. - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl @@ -1231,9 +1434,37 @@ AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +dnl Delay evaluation of AM_DEFAULT_VERBOSITY to the end to allow multiple calls +dnl to AM_SILENT_RULES to change the default value. +AC_CONFIG_COMMANDS_PRE([dnl +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; +esac +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +])dnl ]) -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Set the default verbosity level to DEFAULT ("yes" being less verbose, "no" or +# empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_REQUIRE([_AM_SILENT_RULES]) +AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1])m4_newline +dnl We intentionally force a newline after the assignment, since a) nothing +dnl good can come of more text following, and b) that was the behavior +dnl before 1.17. See https://bugs.gnu.org/72267. +]) + +# Copyright (C) 2001-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1261,7 +1492,7 @@ fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006-2020 Free Software Foundation, Inc. +# Copyright (C) 2006-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1280,7 +1511,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004-2020 Free Software Foundation, Inc. +# Copyright (C) 2004-2025 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1326,15 +1557,19 @@ m4_if([$1], [v7], am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) - if test $am_uid -le $am_max_uid; then - AC_MSG_RESULT([yes]) + if test x$am_uid = xunknown; then + AC_MSG_WARN([ancient id detected; assuming current UID is ok, but dist-ustar might not work]) + elif test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) else - AC_MSG_RESULT([no]) - _am_tools=none + AC_MSG_RESULT([no]) + _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) - if test $am_gid -le $am_max_gid; then - AC_MSG_RESULT([yes]) + if test x$gm_gid = xunknown; then + AC_MSG_WARN([ancient id detected; assuming current GID is ok, but dist-ustar might not work]) + elif test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none @@ -1411,6 +1646,26 @@ AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR +# Copyright (C) 2022-2025 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_XARGS_N +# ---------------- +# Check whether 'xargs -n' works. It should work everywhere, so the fallback +# is not optimized at all as we never expect to use it. +AC_DEFUN([_AM_PROG_XARGS_N], +[AC_CACHE_CHECK([xargs -n works], am_cv_xargs_n_works, [dnl +AS_IF([test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 +3"], [am_cv_xargs_n_works=yes], [am_cv_xargs_n_works=no])]) +AS_IF([test "$am_cv_xargs_n_works" = yes], [am__xargs_n='xargs -n'], [dnl + am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "$@" "$am__xargs_n_arg"; done; }' +])dnl +AC_SUBST(am__xargs_n) +]) + m4_include([m4/ax_cflags_gcc_option.m4]) m4_include([m4/ax_pthread.m4]) m4_include([m4/ld-version-script.m4]) diff --git a/configure.ac b/configure.ac index fd253c3..4996469 100644 --- a/configure.ac +++ b/configure.ac @@ -665,9 +665,12 @@ m4_divert_pop([INIT_PREPARE])dnl AS_IF([test "x$enable_wayland_backend" != "xno"], [PKG_CHECK_MODULES([WLROOTS], - [wlroots >= 0.15 wayland-server xkbcommon pixman-1], + [wlroots-0.19 wayland-server xkbcommon pixman-1], [have_wlroots=yes], - [have_wlroots=no]) + [PKG_CHECK_MODULES([WLROOTS], + [wlroots >= 0.15 wayland-server xkbcommon pixman-1], + [have_wlroots=yes], + [have_wlroots=no])]) AS_IF([test "x$have_wlroots" = "xyes"], [AC_DEFINE([USE_WAYLAND_BACKEND], [1], [Define to 1 to build the wlroots Wayland compositor backend]) diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4 index 94b0829..25caa89 100644 --- a/m4/ltoptions.m4 +++ b/m4/ltoptions.m4 @@ -1,14 +1,14 @@ # Helper functions for option handling. -*- Autoconf -*- # -# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software -# Foundation, Inc. +# Copyright (C) 2004-2005, 2007-2009, 2011-2019, 2021-2024 Free +# Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. -# serial 8 ltoptions.m4 +# serial 10 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) @@ -128,7 +128,7 @@ LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in -*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) +*-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) @@ -323,29 +323,39 @@ dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_AIX_SONAME([DEFAULT]) # ---------------------------------- -# implement the --with-aix-soname flag, and support the `aix-soname=aix' -# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT -# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. +# implement the --enable-aix-soname configure option, and support the +# `aix-soname=aix' and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. +# DEFAULT is either `aix', `both', or `svr4'. If omitted, it defaults to `aix'. m4_define([_LT_WITH_AIX_SONAME], [m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[[5-9]]*,yes) AC_MSG_CHECKING([which variant of shared library versioning to provide]) - AC_ARG_WITH([aix-soname], - [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], + AC_ARG_ENABLE([aix-soname], + [AS_HELP_STRING([--enable-aix-soname=aix|svr4|both], [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], - [case $withval in - aix|svr4|both) - ;; - *) - AC_MSG_ERROR([Unknown argument to --with-aix-soname]) - ;; - esac - lt_cv_with_aix_soname=$with_aix_soname], - [AC_CACHE_VAL([lt_cv_with_aix_soname], - [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) - with_aix_soname=$lt_cv_with_aix_soname]) + [case $enableval in + aix|svr4|both) + ;; + *) + AC_MSG_ERROR([Unknown argument to --enable-aix-soname]) + ;; + esac + lt_cv_with_aix_soname=$enable_aix_soname], + [_AC_ENABLE_IF([with], [aix-soname], + [case $withval in + aix|svr4|both) + ;; + *) + AC_MSG_ERROR([Unknown argument to --with-aix-soname]) + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname], + [AC_CACHE_VAL([lt_cv_with_aix_soname], + [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)]) + enable_aix_soname=$lt_cv_with_aix_soname]) + with_aix_soname=$enable_aix_soname AC_MSG_RESULT([$with_aix_soname]) if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member @@ -376,30 +386,50 @@ LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) # _LT_WITH_PIC([MODE]) # -------------------- -# implement the --with-pic flag, and support the 'pic-only' and 'no-pic' +# implement the --enable-pic flag, and support the 'pic-only' and 'no-pic' # LT_INIT options. # MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. m4_define([_LT_WITH_PIC], -[AC_ARG_WITH([pic], - [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], +[AC_ARG_ENABLE([pic], + [AS_HELP_STRING([--enable-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} - case $withval in - yes|no) pic_mode=$withval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, - for lt_pkg in $withval; do - IFS=$lt_save_ifs - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS=$lt_save_ifs - ;; - esac], - [pic_mode=m4_default([$1], [default])]) + case $enableval in + yes|no) pic_mode=$enableval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [dnl Continue to support --with-pic and --without-pic, for backward + dnl compatibility. + _AC_ENABLE_IF([with], [pic], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $withval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [pic_mode=m4_default([$1], [default])])] + ) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4 index 48bc934..5b5c80a 100644 --- a/m4/ltsugar.m4 +++ b/m4/ltsugar.m4 @@ -1,6 +1,6 @@ # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # -# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software +# Copyright (C) 2004-2005, 2007-2008, 2011-2019, 2021-2024 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # diff --git a/m4/ltversion.m4 b/m4/ltversion.m4 index fa04b52..228df3f 100644 --- a/m4/ltversion.m4 +++ b/m4/ltversion.m4 @@ -1,6 +1,7 @@ # ltversion.m4 -- version numbers -*- Autoconf -*- # -# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. +# Copyright (C) 2004, 2011-2019, 2021-2024 Free Software Foundation, +# Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives @@ -9,15 +10,15 @@ # @configure_input@ -# serial 4179 ltversion.m4 +# serial 4441 ltversion.m4 # This file is part of GNU Libtool -m4_define([LT_PACKAGE_VERSION], [2.4.6]) -m4_define([LT_PACKAGE_REVISION], [2.4.6]) +m4_define([LT_PACKAGE_VERSION], [2.5.4]) +m4_define([LT_PACKAGE_REVISION], [2.5.4]) AC_DEFUN([LTVERSION_VERSION], -[macro_version='2.4.6' -macro_revision='2.4.6' +[macro_version='2.5.4' +macro_revision='2.5.4' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4 index c6b26f8..22b5346 100644 --- a/m4/lt~obsolete.m4 +++ b/m4/lt~obsolete.m4 @@ -1,7 +1,7 @@ # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # -# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software -# Foundation, Inc. +# Copyright (C) 2004-2005, 2007, 2009, 2011-2019, 2021-2024 Free +# Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 25f5872..2177d4a 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -131,6 +131,7 @@ #include /* Phase 18: scene graph compositing */ #include /* Phase 18: buffer allocator */ #include /* Phase 29+: WM-owned SHM surface buffers */ +#include /* wlr_buffer_init/wlr_buffer_impl */ #include /* Phase 29+: DRM_FORMAT_ARGB8888 */ #include /* Phase 29+: software pixel rendering */ #include /* Phase 23: hardware cursor tracking */ @@ -164,9 +165,9 @@ #include "protocols/wlr-layer-shell-unstable-v1-protocol.h" #include /* Phase 36: zwlr_layer_shell_v1 (panels, docks) */ #include /* Phase 37: zwlr_data_control_manager_v1 (clipboard mgr) */ -#include /* Phase 37: zwlr_input_inhibitor_v1 (lock screen input) */ #include /* Phase 37: zwlr_virtual_pointer_manager_v1 (remote desktop) */ -#include /* Phase 37: org_kde_kwin_idle (legacy idle protocol) */ +/* wlr_input_inhibitor and wlr_idle (org_kde_kwin_idle) were removed in + * wlroots 0.18 — use wlr_session_lock_v1 / wlr_idle_notify_v1 instead. */ #include /* Phase 37: xdg-foreign registry (shared state) */ #include /* Phase 37: zxdg_exporter_v2 / zxdg_importer_v2 */ #include @@ -221,8 +222,8 @@ struct wl_toplevel_view { struct wlr_xwayland_surface *xw_surface; /* Path 1: geometry listener — keeps scene node in sync when X11 window moves. */ struct wl_listener xw_geometry_listener; - /* Phase 18: scene graph node for this surface (NULL if scene unavailable). */ - struct wlr_scene_node *scene_node; + /* Phase 18: scene graph tree for this surface (NULL if scene unavailable). */ + struct wlr_scene_tree *scene_node; WNativeWindow id; /* synthetic handle, >= 0x10000000 */ int x, y; /* Phase 55: WM-assigned position */ long *wm_state; /* Phase 56: saved WM state or NULL */ @@ -240,7 +241,7 @@ struct wl_toplevel_view { */ struct wl_layer_view { struct wlr_layer_surface_v1 *layer_surface; - struct wlr_scene_node *scene_node; + struct wlr_scene_tree *scene_node; struct wl_listener map_listener; struct wl_listener unmap_listener; struct wl_listener destroy_listener; @@ -286,11 +287,12 @@ struct wl_compositor_state { struct wl_list layer_list; /* wl_layer_view.link */ struct wl_list ctx_lists[3]; /* one per WContextKey */ unsigned long next_synthetic_id; /* >= 0x10000000 */ - /* Phase 43: headless keyboard device for seat keyboard focus */ + /* Phase 43: first real keyboard device (set by handle_backend_new_input) */ struct wlr_input_device *keyboard_dev; + struct xkb_keymap *xkb_keymap; /* default keymap for keysym lookup */ struct wl_listener keyboard_key_listener; /* Phase 78 */ struct wl_listener keyboard_modifiers_listener; /* Phase 78 */ - /* Phase 53: headless pointer device so seat advertises pointer capability */ + /* Phase 53: first real pointer device (set by handle_backend_new_input) */ struct wlr_input_device *pointer_dev; /* Phase 54: virtual pointer position (screen coordinates) */ int pointer_x, pointer_y; @@ -397,12 +399,8 @@ struct wl_compositor_state { struct wl_listener layer_shell_new_surface_listener; /* Phase 37: clipboard manager, input inhibitor, virtual pointer, idle, xdg-foreign. */ struct wlr_data_control_manager_v1 *data_control_mgr; - struct wlr_input_inhibit_manager *input_inhibit_mgr; - struct wl_listener input_inhibit_activate_listener; - struct wl_listener input_inhibit_deactivate_listener; struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; struct wl_listener virtual_pointer_new_listener; - struct wlr_idle *idle; struct wlr_xdg_foreign_registry *xdg_foreign_registry; struct wlr_xdg_foreign_v2 *xdg_foreign_v2; /* Phase 29 axis listeners (headless pointer + real nested pointer). */ @@ -421,6 +419,8 @@ struct wl_compositor_state { int icon_w, icon_h; } dock_apps[WM_DOCK_MAX_APPS]; int dock_app_count; + /* Phase 81: full-screen overlay surface for XOR animation drawing */ + struct wm_shm_surface *overlay_surf; /* NULL until first draw */ }; static struct wl_compositor_state wl_state; @@ -505,9 +505,7 @@ static void handle_virtual_keyboard_new(struct wl_listener *listener, void *data static void handle_xdg_activation_request(struct wl_listener *listener, void *data); /* Phase 36: layer shell new_surface handler. */ static void handle_layer_shell_new_surface(struct wl_listener *listener, void *data); -/* Phase 37: input inhibitor activate/deactivate + virtual pointer handlers. */ -static void handle_input_inhibit_activate(struct wl_listener *listener, void *data); -static void handle_input_inhibit_deactivate(struct wl_listener *listener, void *data); +/* Phase 37: virtual pointer handler. */ static void handle_virtual_pointer_new(struct wl_listener *listener, void *data); /* Phase 17: XWayland new surface forward declaration. */ static void handle_xwayland_new_surface(struct wl_listener *listener, void *data); @@ -581,7 +579,7 @@ wl_set_cursor_image(const char *name) { if (!wl_state.cursor || !wl_state.xcursor_mgr) return; - wlr_xcursor_manager_set_cursor_image(wl_state.xcursor_mgr, name, wl_state.cursor); + wlr_cursor_set_xcursor(wl_state.cursor, wl_state.xcursor_mgr, name); } /* @@ -709,7 +707,7 @@ wl_grab_apply_motion(void) int ny = wl_state.grab_start_win_y + dy; v->x = nx; v->y = ny; if (v->scene_node) - wlr_scene_node_set_position(v->scene_node, nx, ny); + wlr_scene_node_set_position(&v->scene_node->node, nx, ny); if (v->xw_surface) wlr_xwayland_surface_configure(v->xw_surface, (int16_t)nx, (int16_t)ny, @@ -741,13 +739,13 @@ wl_grab_apply_motion(void) v->x = nx; v->y = ny; if (v->scene_node) - wlr_scene_node_set_position(v->scene_node, nx, ny); + wlr_scene_node_set_position(&v->scene_node->node, nx, ny); if (v->xw_surface) { wlr_xwayland_surface_configure(v->xw_surface, (int16_t)nx, (int16_t)ny, (uint16_t)nw, (uint16_t)nh); } else if (v->xdg_surface) { - wlr_xdg_toplevel_set_size(v->xdg_surface, (uint32_t)nw, (uint32_t)nh); + wlr_xdg_toplevel_set_size(v->xdg_surface->toplevel, (uint32_t)nw, (uint32_t)nh); wlr_xdg_surface_schedule_configure(v->xdg_surface); } } @@ -882,9 +880,9 @@ handle_toplevel_map(struct wl_listener *listener, void *data) /* Phase 18: add XDG surface to the scene graph. */ if (wl_state.scene && !view->scene_node) { view->scene_node = wlr_scene_xdg_surface_create( - &wl_state.scene->node, view->xdg_surface); + &wl_state.scene->tree, view->xdg_surface); if (view->scene_node) - wlr_scene_node_set_position(view->scene_node, + wlr_scene_node_set_position(&view->scene_node->node, view->x, view->y); } @@ -982,7 +980,7 @@ handle_toplevel_destroy(struct wl_listener *listener, void *data) wl_list_remove(&view->link); /* Phase 18: remove scene node. */ if (view->scene_node) { - wlr_scene_node_destroy(view->scene_node); + wlr_scene_node_destroy(&view->scene_node->node); view->scene_node = NULL; } wl_state.managed_surface_count--; @@ -1027,7 +1025,7 @@ handle_xwayland_set_geometry(struct wl_listener *listener, void *data) struct wlr_xwayland_surface *xw = view->xw_surface; (void)data; if (view->scene_node) - wlr_scene_node_set_position(view->scene_node, xw->x, xw->y); + wlr_scene_node_set_position(&view->scene_node->node, xw->x, xw->y); } /* @@ -1052,9 +1050,9 @@ handle_xwayland_map(struct wl_listener *listener, void *data) * sent; the set_geometry listener keeps them in sync thereafter. */ if (wl_state.scene && !view->scene_node && xw->surface) { view->scene_node = wlr_scene_subsurface_tree_create( - &wl_state.scene->node, xw->surface); + &wl_state.scene->tree, xw->surface); if (view->scene_node) - wlr_scene_node_set_position(view->scene_node, view->x, view->y); + wlr_scene_node_set_position(&view->scene_node->node, view->x, view->y); } else if (!xw->surface) { wwarning("wl_backend: xwayland map id=0x%lx: surface is NULL, window will not render", view->id); @@ -1100,7 +1098,7 @@ handle_xwayland_unmap(struct wl_listener *listener, void *data) wm_dock_app_remove(view->id); if (view->scene_node) { - wlr_scene_node_destroy(view->scene_node); + wlr_scene_node_destroy(&view->scene_node->node); view->scene_node = NULL; } @@ -1132,7 +1130,7 @@ handle_xwayland_destroy(struct wl_listener *listener, void *data) wl_list_remove(&view->link); /* Phase 18: remove scene node (may already be gone from unmap). */ if (view->scene_node) { - wlr_scene_node_destroy(view->scene_node); + wlr_scene_node_destroy(&view->scene_node->node); view->scene_node = NULL; } wl_state.managed_surface_count--; @@ -1226,9 +1224,9 @@ handle_xwayland_new_surface(struct wl_listener *listener, void *data) view->title_listener.notify = handle_xwayland_set_class; view->xw_geometry_listener.notify = handle_xwayland_set_geometry; - wl_signal_add(&xw->events.map, &view->map_listener); - wl_signal_add(&xw->events.unmap, &view->unmap_listener); - wl_signal_add(&xw->events.destroy, &view->destroy_listener); + wl_signal_add(&xw->events.associate, &view->map_listener); + wl_signal_add(&xw->events.dissociate, &view->unmap_listener); + wl_signal_add(&xw->events.destroy, &view->destroy_listener); wl_signal_add(&xw->events.set_class, &view->title_listener); wl_signal_add(&xw->events.set_geometry, &view->xw_geometry_listener); @@ -1292,8 +1290,8 @@ handle_xdg_new_surface(struct wl_listener *listener, void *data) view->request_minimize_listener.notify = handle_toplevel_request_minimize; /* Phase 16 */ view->set_app_id_listener.notify = handle_toplevel_set_app_id; /* Phase 16 */ - wl_signal_add(&xdg_surface->events.map, &view->map_listener); - wl_signal_add(&xdg_surface->events.unmap, &view->unmap_listener); + wl_signal_add(&xdg_surface->surface->events.map, &view->map_listener); + wl_signal_add(&xdg_surface->surface->events.unmap, &view->unmap_listener); wl_signal_add(&xdg_surface->events.destroy, &view->destroy_listener); wl_signal_add(&xdg_surface->toplevel->events.set_title, &view->title_listener); wl_signal_add(&xdg_surface->toplevel->events.request_move, &view->request_move_listener); @@ -1329,20 +1327,14 @@ handle_xdg_new_surface(struct wl_listener *listener, void *data) static void handle_keyboard_key(struct wl_listener *listener, void *data) { - struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard_key_event *event = data; (void)listener; if (!wl_state.seat) return; - /* Use the seat's active keyboard — in headless mode that is the headless - * keyboard; in nested mode it is the real host keyboard (updated at the - * end of wl_display_open after handle_backend_new_input runs). */ struct wlr_keyboard *kb = wl_state.seat->keyboard_state.keyboard; - if (!kb) { - if (!wl_state.keyboard_dev || !wl_state.keyboard_dev->keyboard) return; - kb = wl_state.keyboard_dev->keyboard; - } + if (!kb) return; /* Update modifier state */ wlr_seat_keyboard_notify_modifiers(wl_state.seat, &kb->modifiers); @@ -1367,10 +1359,7 @@ handle_keyboard_modifiers(struct wl_listener *listener, void *data) (void)listener; (void)data; if (!wl_state.seat) return; struct wlr_keyboard *kb = wl_state.seat->keyboard_state.keyboard; - if (!kb) { - if (!wl_state.keyboard_dev || !wl_state.keyboard_dev->keyboard) return; - kb = wl_state.keyboard_dev->keyboard; - } + if (!kb) return; wlr_seat_keyboard_notify_modifiers(wl_state.seat, &kb->modifiers); } @@ -1392,48 +1381,51 @@ handle_backend_new_input(struct wl_listener *listener, void *data) struct wlr_input_device *dev = data; (void)listener; - /* Skip headless synthetic devices — they never generate events. */ - if (wlr_input_device_is_headless(dev)) - return; - - /* Real device from the nested Wayland backend. */ + /* In wlroots 0.19 the headless backend has no input devices, so every + * device that arrives here is a real device from the nested Wayland + * backend (or a virtual device). No need to skip headless devices. */ switch (dev->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - if (!dev->keyboard) break; - /* wlroots' nested backend auto-receives the host keymap via the - * wl_keyboard.keymap event — no need to set XKB manually here. */ + case WLR_INPUT_DEVICE_KEYBOARD: { + struct wlr_keyboard *kb = wlr_keyboard_from_input_device(dev); + /* Apply our default XKB keymap unless the backend already set one + * (nested backend receives the host keymap via wl_keyboard.keymap). */ + if (wl_state.xkb_keymap && !kb->keymap) + wlr_keyboard_set_keymap(kb, wl_state.xkb_keymap); wl_state.real_keyboard_dev = dev; + wl_state.keyboard_dev = dev; + wlr_seat_set_keyboard(wl_state.seat, kb); wl_state.real_keyboard_key_listener.notify = handle_keyboard_key; - wl_signal_add(&dev->keyboard->events.key, + wl_signal_add(&kb->events.key, &wl_state.real_keyboard_key_listener); wl_state.real_keyboard_modifiers_listener.notify = handle_keyboard_modifiers; - wl_signal_add(&dev->keyboard->events.modifiers, + wl_signal_add(&kb->events.modifiers, &wl_state.real_keyboard_modifiers_listener); wwarning("wl_backend: real keyboard wired from nested backend"); break; - - case WLR_INPUT_DEVICE_POINTER: - if (!dev->pointer) break; + } + case WLR_INPUT_DEVICE_POINTER: { + struct wlr_pointer *ptr = wlr_pointer_from_input_device(dev); /* Nested backend delivers absolute motion events (host cursor * position normalised to [0,1]); no relative motion needed. */ wl_state.real_pointer_dev = dev; + wl_state.pointer_dev = dev; wl_state.real_pointer_motion_abs_listener.notify = handle_pointer_motion_absolute; - wl_signal_add(&dev->pointer->events.motion_absolute, + wl_signal_add(&ptr->events.motion_absolute, &wl_state.real_pointer_motion_abs_listener); wl_state.real_pointer_button_listener.notify = handle_pointer_button; - wl_signal_add(&dev->pointer->events.button, + wl_signal_add(&ptr->events.button, &wl_state.real_pointer_button_listener); wl_state.real_pointer_frame_listener.notify = handle_pointer_frame; - wl_signal_add(&dev->pointer->events.frame, + wl_signal_add(&ptr->events.frame, &wl_state.real_pointer_frame_listener); /* Phase 29: axis (scroll wheel) from real nested pointer. */ wl_state.real_pointer_axis_listener.notify = handle_pointer_axis; - wl_signal_add(&dev->pointer->events.axis, + wl_signal_add(&ptr->events.axis, &wl_state.real_pointer_axis_listener); wwarning("wl_backend: real pointer wired from nested backend"); break; - + } default: break; } @@ -1458,7 +1450,7 @@ handle_output_frame(struct wl_listener *listener, void *data) if (wl_state.allocator) { /* Full scene commit — renders client surfaces and fires * wl_surface.frame callbacks so clients can submit next buffer. */ - wlr_scene_output_commit(wl_state.scene_output); + wlr_scene_output_commit(wl_state.scene_output, NULL); } else { /* No GPU allocator available (e.g. headless without DRI access). * Skip rendering but still fire wl_surface.frame callbacks so @@ -1491,18 +1483,16 @@ handle_backend_new_output(struct wl_listener *listener, void *data) if (wl_state.allocator && wl_state.renderer) wlr_output_init_render(output, wl_state.allocator, wl_state.renderer); - /* Enable the output: select preferred mode, then commit. */ + /* Enable the output: select preferred mode, then commit via state API. */ { + struct wlr_output_state state; + wlr_output_state_init(&state); + wlr_output_state_set_enabled(&state, true); struct wlr_output_mode *mode = wlr_output_preferred_mode(output); - if (mode) wlr_output_set_mode(output, mode); - } - wlr_output_enable(output, true); - if (!wlr_output_commit(output)) { - wwarning("wl_backend: initial output commit failed"); - /* Send wl_output.done so Wayland clients (e.g. weston-info) do - * not wait indefinitely for output configuration to be finalised. - * On a failed commit wlroots does not send done automatically. */ - wlr_output_schedule_done(output); + if (mode) wlr_output_state_set_mode(&state, mode); + if (!wlr_output_commit_state(output, &state)) + wwarning("wl_backend: initial output commit failed"); + wlr_output_state_finish(&state); } /* Register with the output layout. */ @@ -1517,8 +1507,7 @@ handle_backend_new_output(struct wl_listener *listener, void *data) * cursor appears at the right location from the first frame. */ if (wl_state.cursor && wl_state.xcursor_mgr) { wlr_xcursor_manager_load(wl_state.xcursor_mgr, output->scale); - wlr_xcursor_manager_set_cursor_image(wl_state.xcursor_mgr, - "left_ptr", wl_state.cursor); + wlr_cursor_set_xcursor(wl_state.cursor, wl_state.xcursor_mgr, "left_ptr"); wlr_cursor_warp(wl_state.cursor, NULL, (double)wl_state.pointer_x, (double)wl_state.pointer_y); @@ -1545,7 +1534,7 @@ handle_backend_new_output(struct wl_listener *listener, void *data) * classic WindowMaker desktop colour. */ { float bg[4] = { 0.35f, 0.35f, 0.35f, 1.0f }; - wlr_scene_rect_create(&wl_state.scene->node, + wlr_scene_rect_create(&wl_state.scene->tree, (int)output->width, (int)output->height, bg); wwarning("wl_backend: root background created (%dx%d, grey)", (int)output->width, (int)output->height); @@ -1595,8 +1584,9 @@ wl_display_open(const char *name) wl_state.is_nested = (wayland_display && wayland_display[0]) ? 1 : 0; } - /* Always create a headless backend for input devices. */ - wl_state.headless_inner = wlr_headless_backend_create(wl_state.display); + /* Always create a headless backend for the output in headless mode. */ + wl_state.headless_inner = wlr_headless_backend_create( + wl_display_get_event_loop(wl_state.display)); if (!wl_state.headless_inner) { wwarning("wl_backend: failed to create headless backend"); wl_display_destroy(wl_state.display); @@ -1606,7 +1596,8 @@ wl_display_open(const char *name) if (wl_state.is_nested) { /* Nested: multi-backend wrapping nested Wayland + headless. */ - wl_state.wl_backend_inner = wlr_wl_backend_create(wl_state.display, NULL); + wl_state.wl_backend_inner = wlr_wl_backend_create( + wl_display_get_event_loop(wl_state.display), NULL); if (!wl_state.wl_backend_inner) { wwarning("wl_backend: failed to create nested Wayland backend; falling back to headless"); wl_state.is_nested = 0; @@ -1614,7 +1605,8 @@ wl_display_open(const char *name) } if (wl_state.is_nested && wl_state.wl_backend_inner) { - struct wlr_backend *multi = wlr_multi_backend_create(wl_state.display); + struct wlr_backend *multi = wlr_multi_backend_create( + wl_display_get_event_loop(wl_state.display)); wlr_multi_backend_add(multi, wl_state.wl_backend_inner); wlr_multi_backend_add(multi, wl_state.headless_inner); wl_state.backend = multi; @@ -1652,7 +1644,7 @@ wl_display_open(const char *name) /* Phase 34: output layout for multi-head geometry tracking. * Must be created before backend start so handle_backend_new_output * can add the output to the layout when it fires. */ - wl_state.output_layout = wlr_output_layout_create(); + wl_state.output_layout = wlr_output_layout_create(wl_state.display); /* Phase 23: create hardware cursor tracker and load xcursor theme. * wlr_cursor tracks the logical cursor position across the output @@ -1731,11 +1723,13 @@ wl_display_open(const char *name) } snprintf(wl_state.socket_name, sizeof(wl_state.socket_name), "%s", sock); setenv("WAYLAND_DISPLAY", wl_state.socket_name, 1); - wwarning("wl_backend: compositor socket WAYLAND_DISPLAY=%s", wl_state.socket_name); + wwarning("wl_backend: compositor socket WAYLAND_DISPLAY=%s DISPLAY=%s", + wl_state.socket_name, + getenv("DISPLAY") ? getenv("DISPLAY") : "(unset)"); /* Phase 35: advertise core Wayland protocol globals. */ wl_state.compositor = - wlr_compositor_create(wl_state.display, wl_state.renderer); + wlr_compositor_create(wl_state.display, 6, wl_state.renderer); wl_state.seat = wlr_seat_create(wl_state.display, "seat0"); wl_state.data_device_mgr = wlr_data_device_manager_create(wl_state.display); @@ -1828,7 +1822,7 @@ wl_display_open(const char *name) * All three are purely passive globals: wlroots handles the protocol * implementation internally; no event listeners are required. */ wl_state.linux_dmabuf = - wlr_linux_dmabuf_v1_create(wl_state.display, wl_state.renderer); + wlr_linux_dmabuf_v1_create_with_renderer(wl_state.display, 4, wl_state.renderer); if (wl_state.linux_dmabuf) wwarning("wl_backend: linux-dmabuf created (zwp_linux_dmabuf_v1)"); else @@ -1864,7 +1858,7 @@ wl_display_open(const char *name) wl_state.gamma_control_mgr = wlr_gamma_control_manager_v1_create(wl_state.display); if (wl_state.gamma_control_mgr) wwarning("wl_backend: gamma-control created (zwlr_gamma_control_manager_v1)"); - wl_state.presentation = wlr_presentation_create(wl_state.display, wl_state.backend); + wl_state.presentation = wlr_presentation_create(wl_state.display, wl_state.backend, 1); if (wl_state.presentation) wwarning("wl_backend: presentation-time created (wp_presentation)"); @@ -1910,7 +1904,7 @@ wl_display_open(const char *name) } /* Phase 36: layer shell — panels, docks, wallpapers, lock screens. */ - wl_state.layer_shell = wlr_layer_shell_v1_create(wl_state.display); + wl_state.layer_shell = wlr_layer_shell_v1_create(wl_state.display, 4); if (wl_state.layer_shell) { wl_state.layer_shell_new_surface_listener.notify = handle_layer_shell_new_surface; @@ -1927,19 +1921,7 @@ wl_display_open(const char *name) if (wl_state.data_control_mgr) wwarning("wl_backend: data-control created (zwlr_data_control_manager_v1)"); - wl_state.input_inhibit_mgr = - wlr_input_inhibit_manager_create(wl_state.display); - if (wl_state.input_inhibit_mgr) { - wl_state.input_inhibit_activate_listener.notify = - handle_input_inhibit_activate; - wl_signal_add(&wl_state.input_inhibit_mgr->events.activate, - &wl_state.input_inhibit_activate_listener); - wl_state.input_inhibit_deactivate_listener.notify = - handle_input_inhibit_deactivate; - wl_signal_add(&wl_state.input_inhibit_mgr->events.deactivate, - &wl_state.input_inhibit_deactivate_listener); - wwarning("wl_backend: input-inhibitor created (zwlr_input_inhibitor_v1)"); - } + /* zwlr_input_inhibitor_v1 removed from wlroots 0.18 — use ext-session-lock-v1 */ wl_state.virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(wl_state.display); @@ -1951,9 +1933,7 @@ wl_display_open(const char *name) wwarning("wl_backend: virtual-pointer created (zwlr_virtual_pointer_manager_v1)"); } - wl_state.idle = wlr_idle_create(wl_state.display); - if (wl_state.idle) - wwarning("wl_backend: idle created (org_kde_kwin_idle)"); + /* org_kde_kwin_idle (wlr_idle) removed from wlroots 0.18 — use ext-idle-notify-v1 */ wl_state.xdg_foreign_registry = wlr_xdg_foreign_registry_create(wl_state.display); @@ -1965,7 +1945,7 @@ wl_display_open(const char *name) wwarning("wl_backend: xdg-foreign-v2 created (zxdg_exporter/importer_v2)"); } - wl_state.xdg_shell = wlr_xdg_shell_create(wl_state.display); + wl_state.xdg_shell = wlr_xdg_shell_create(wl_state.display, 3); /* Phase 64: advertise zxdg_decoration_manager_v1 so clients that * support server-side decorations can negotiate; we respond with @@ -1983,75 +1963,26 @@ wl_display_open(const char *name) wlr_renderer_init_wl_shm(wl_state.renderer, wl_state.display); /* wl_output global is created in handle_backend_new_output. */ - /* Phase 43: create a headless keyboard and attach it to the seat so - * wlr_seat_keyboard_notify_enter() can deliver keyboard focus. - * Always use headless_inner regardless of nested/headless mode. */ - wl_state.keyboard_dev = - wlr_headless_add_input_device(wl_state.headless_inner, WLR_INPUT_DEVICE_KEYBOARD); - if (wl_state.keyboard_dev) { - /* Phase 77: set a default XKB keymap on the headless keyboard so that - * wl_keysym_to_keycode() can populate wKeyBindings during StartUp(). - * The xkb_keymap_new_from_names(NULL) produces the system default - * layout (usually "us"), giving us the same keycode space as X11. */ - struct wlr_keyboard *kb = wl_state.keyboard_dev ? wl_state.keyboard_dev->keyboard : NULL; - if (kb) { - struct xkb_context *xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (xkb_ctx) { - struct xkb_keymap *keymap = xkb_keymap_new_from_names( - xkb_ctx, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS); - if (keymap) { - wlr_keyboard_set_keymap(kb, keymap); - xkb_keymap_unref(keymap); - wwarning("wl_backend: XKB keymap set on headless keyboard"); - } - xkb_context_unref(xkb_ctx); - } - } - wlr_seat_set_keyboard(wl_state.seat, wl_state.keyboard_dev); - - /* Phase 78: wire keyboard key + modifier listeners so WM shortcuts - * are dispatched and non-shortcut keys reach the focused client. */ - if (wl_state.keyboard_dev->keyboard) { - wl_state.keyboard_key_listener.notify = handle_keyboard_key; - wl_signal_add(&wl_state.keyboard_dev->keyboard->events.key, - &wl_state.keyboard_key_listener); - wl_state.keyboard_modifiers_listener.notify = handle_keyboard_modifiers; - wl_signal_add(&wl_state.keyboard_dev->keyboard->events.modifiers, - &wl_state.keyboard_modifiers_listener); - wwarning("wl_backend: keyboard key+modifiers listeners wired"); - } - } - - /* Phase 53: create a headless pointer so the seat advertises pointer - * capability to clients (required for clients that bind wl_pointer). - * Always use headless_inner regardless of nested/headless mode. */ - wl_state.pointer_dev = - wlr_headless_add_input_device(wl_state.headless_inner, WLR_INPUT_DEVICE_POINTER); - - /* Phase 14: wire pointer motion/button listeners to the headless pointer - * device so real pointer hardware (if added later) dispatches events. */ - if (wl_state.pointer_dev && wl_state.pointer_dev->pointer) { - struct wlr_pointer *ptr = wl_state.pointer_dev->pointer; - wl_state.pointer_motion_listener.notify = handle_pointer_motion; - wl_signal_add(&ptr->events.motion, &wl_state.pointer_motion_listener); - wl_state.pointer_motion_abs_listener.notify = handle_pointer_motion_absolute; - wl_signal_add(&ptr->events.motion_absolute, &wl_state.pointer_motion_abs_listener); - wl_state.pointer_button_listener.notify = handle_pointer_button; - wl_signal_add(&ptr->events.button, &wl_state.pointer_button_listener); - wl_state.pointer_frame_listener.notify = handle_pointer_frame; - wl_signal_add(&ptr->events.frame, &wl_state.pointer_frame_listener); - /* Phase 29: axis (scroll wheel) listener. */ - wl_state.pointer_axis_listener.notify = handle_pointer_axis; - wl_signal_add(&ptr->events.axis, &wl_state.pointer_axis_listener); - wwarning("wl_backend: pointer motion/button/frame listeners wired"); - } - + /* Phase 43/53: In wlroots 0.19, the headless backend has no input devices. + * Real keyboard/pointer devices arrive via handle_backend_new_input when + * the nested Wayland backend starts. We pre-create the default XKB keymap + * here so wl_keysym_to_keycode() can resolve key bindings during StartUp() + * before any real keyboard device has been received. */ { - uint32_t caps = 0; - if (wl_state.keyboard_dev) caps |= WL_SEAT_CAPABILITY_KEYBOARD; - if (wl_state.pointer_dev) caps |= WL_SEAT_CAPABILITY_POINTER; - if (caps) wlr_seat_set_capabilities(wl_state.seat, caps); + struct xkb_context *xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (xkb_ctx) { + wl_state.xkb_keymap = xkb_keymap_new_from_names( + xkb_ctx, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS); + xkb_context_unref(xkb_ctx); + if (wl_state.xkb_keymap) + wwarning("wl_backend: default XKB keymap created for key binding resolution"); + } } + /* Advertise keyboard+pointer capability unconditionally so clients do not + * need to wait for a real device to appear before binding wl_keyboard / wl_pointer. */ + if (wl_state.seat) + wlr_seat_set_capabilities(wl_state.seat, + WL_SEAT_CAPABILITY_KEYBOARD | WL_SEAT_CAPABILITY_POINTER); /* Phase 38: initialise per-toplevel tracking and context store. */ wl_list_init(&wl_state.toplevel_list); @@ -2155,7 +2086,8 @@ wl_display_open(const char *name) * must happen after the headless keyboard setup above (which may have * called wlr_seat_set_keyboard with the headless device). */ if (wl_state.real_keyboard_dev) - wlr_seat_set_keyboard(wl_state.seat, wl_state.real_keyboard_dev); + wlr_seat_set_keyboard(wl_state.seat, + wlr_keyboard_from_input_device(wl_state.real_keyboard_dev)); wl_state.started = 1; @@ -2325,9 +2257,7 @@ wl_display_close(void) WL_LISTENER_REMOVE(wl_state.xdg_activation_request_listener); /* Phase 36: layer shell new_surface listener */ WL_LISTENER_REMOVE(wl_state.layer_shell_new_surface_listener); - /* Phase 37: input inhibitor + virtual pointer listeners */ - WL_LISTENER_REMOVE(wl_state.input_inhibit_activate_listener); - WL_LISTENER_REMOVE(wl_state.input_inhibit_deactivate_listener); + /* Phase 37: virtual pointer listener */ WL_LISTENER_REMOVE(wl_state.virtual_pointer_new_listener); #undef WL_LISTENER_REMOVE @@ -2661,7 +2591,7 @@ wm_shm_surface_fill(struct wm_shm_surface *s, /* * Commit the surface to the scene graph. * - * parent — scene-graph parent node (e.g. &wl_state.scene->node) + * parent — scene-graph parent node (e.g. &wl_state.scene->tree.node) * x, y — position in the compositor coordinate space * * First call creates the scene_buffer node; subsequent calls just @@ -2670,7 +2600,7 @@ wm_shm_surface_fill(struct wm_shm_surface *s, */ static void wm_shm_surface_commit(struct wm_shm_surface *s, - struct wlr_scene_node *parent, + struct wlr_scene_tree *parent, int x, int y) { if (!s) @@ -2807,7 +2737,7 @@ wm_dock_create(WScreen *scr) } wm_dock_render(s, icon_sz, n_slots); - wm_shm_surface_commit(s, &wl_state.scene->node, sw - dw, 0); + wm_shm_surface_commit(s, &wl_state.scene->tree, sw - dw, 0); wl_state.dock_surface = s; wl_state.dock_width = dw; @@ -2846,9 +2776,9 @@ static void wm_shm_surface_repaint(struct wm_shm_surface *s) { if (!s || !s->scene_buf) return; - int x = s->scene_buf->node.state.x; - int y = s->scene_buf->node.state.y; - struct wlr_scene_node *parent = s->scene_buf->node.parent; + int x = s->scene_buf->node.x; + int y = s->scene_buf->node.y; + struct wlr_scene_tree *parent = s->scene_buf->node.parent; wlr_scene_node_destroy(&s->scene_buf->node); s->scene_buf = NULL; if (parent) { @@ -3162,7 +3092,7 @@ static void handle_pointer_motion(struct wl_listener *listener, void *data) { (void)listener; - struct wlr_event_pointer_motion *ev = data; + struct wlr_pointer_motion_event *ev = data; int ow = wl_state.output ? (int)wl_state.output->width : 1920; int oh = wl_state.output ? (int)wl_state.output->height : 1080; wl_state.pointer_x += (int)ev->delta_x; @@ -3184,12 +3114,12 @@ static void handle_pointer_motion_absolute(struct wl_listener *listener, void *data) { (void)listener; - struct wlr_event_pointer_motion_absolute *ev = data; + struct wlr_pointer_motion_absolute_event *ev = data; /* Phase 23: use wlr_cursor_warp_absolute so wlroots maps the 0..1 * device-normalized coordinates to layout pixels and updates the * hardware cursor in the nested window automatically. */ if (wl_state.cursor) { - wlr_cursor_warp_absolute(wl_state.cursor, ev->device, ev->x, ev->y); + wlr_cursor_warp_absolute(wl_state.cursor, &ev->pointer->base, ev->x, ev->y); wl_state.pointer_x = (int)wl_state.cursor->x; wl_state.pointer_y = (int)wl_state.cursor->y; } else { @@ -3288,7 +3218,7 @@ static void handle_pointer_axis(struct wl_listener *listener, void *data) { (void)listener; - struct wlr_event_pointer_axis *ev = data; + struct wlr_pointer_axis_event *ev = data; if (!wl_state.seat) return; /* Drop axis events during a compositor grab so the grabbed window @@ -3300,7 +3230,8 @@ handle_pointer_axis(struct wl_listener *listener, void *data) ev->orientation, ev->delta, ev->delta_discrete, - ev->source); + ev->source, + ev->relative_direction); } /* @@ -3383,8 +3314,11 @@ handle_output_power_set_mode(struct wl_listener *listener, void *data) (void)listener; struct wlr_output_power_v1_set_mode_event *ev = data; bool enable = (ev->mode == ZWLR_OUTPUT_POWER_V1_MODE_ON); - wlr_output_enable(ev->output, enable); - wlr_output_commit(ev->output); + struct wlr_output_state state; + wlr_output_state_init(&state); + wlr_output_state_set_enabled(&state, enable); + wlr_output_commit_state(ev->output, &state); + wlr_output_state_finish(&state); wwarning("wl_backend: output power set_mode %s", enable ? "ON" : "OFF"); } @@ -3465,7 +3399,7 @@ handle_xdg_activation_request(struct wl_listener *listener, void *data) WWindow *wwin = (WWindow *)desc->parent; wSetFocusTo(wScreenWithNumber(0), wwin); if (view->scene_node) - wlr_scene_node_raise_to_top(view->scene_node); + wlr_scene_node_raise_to_top(&view->scene_node->node); /* Move to front of toplevel list (Z-order). */ wl_list_remove(&view->link); wl_list_insert(wl_state.toplevel_list.prev, &view->link); @@ -3571,7 +3505,7 @@ handle_layer_surface_unmap(struct wl_listener *listener, void *data) struct wl_layer_view *lv = LAYER_VIEW_FROM(listener, unmap_listener); wwarning("wl_backend: layer surface unmapped"); if (lv->scene_node) { - wlr_scene_node_destroy(lv->scene_node); + wlr_scene_node_destroy(&lv->scene_node->node); lv->scene_node = NULL; } } @@ -3585,7 +3519,7 @@ handle_layer_surface_destroy(struct wl_listener *listener, void *data) wl_list_remove(&lv->unmap_listener.link); wl_list_remove(&lv->destroy_listener.link); if (lv->scene_node) { - wlr_scene_node_destroy(lv->scene_node); + wlr_scene_node_destroy(&lv->scene_node->node); lv->scene_node = NULL; } wl_list_remove(&lv->link); @@ -3617,7 +3551,7 @@ handle_layer_shell_new_surface(struct wl_listener *listener, void *data) /* Add to scene graph if available. */ if (wl_state.scene) { lv->scene_node = wlr_scene_subsurface_tree_create( - &wl_state.scene->node, ls->surface); + &wl_state.scene->tree, ls->surface); } /* Compute and send initial configure. */ @@ -3634,16 +3568,16 @@ handle_layer_shell_new_surface(struct wl_listener *listener, void *data) if (lv->scene_node) { int sx, sy; layer_surface_compute_position(ls, ow, oh, fw, fh, &sx, &sy); - wlr_scene_node_set_position(lv->scene_node, sx, sy); + wlr_scene_node_set_position(&lv->scene_node->node, sx, sy); } /* Wire lifecycle listeners. */ lv->map_listener.notify = handle_layer_surface_map; lv->unmap_listener.notify = handle_layer_surface_unmap; lv->destroy_listener.notify = handle_layer_surface_destroy; - wl_signal_add(&ls->events.map, &lv->map_listener); - wl_signal_add(&ls->events.unmap, &lv->unmap_listener); - wl_signal_add(&ls->events.destroy, &lv->destroy_listener); + wl_signal_add(&ls->surface->events.map, &lv->map_listener); + wl_signal_add(&ls->surface->events.unmap, &lv->unmap_listener); + wl_signal_add(&ls->events.destroy, &lv->destroy_listener); wl_list_insert(&wl_state.layer_list, &lv->link); @@ -3657,28 +3591,6 @@ handle_layer_shell_new_surface(struct wl_listener *listener, void *data) /* xdg-foreign */ /* ------------------------------------------------------------------ */ -/* - * handle_input_inhibit_activate — a lock screen client grabbed exclusive input. - * We log it; a real lock screen implementation would also hide all other - * surfaces and prevent any focus delivery outside the lock client. - */ -static void -handle_input_inhibit_activate(struct wl_listener *listener, void *data) -{ - (void)listener; (void)data; - wwarning("wl_backend: input inhibitor activated (lock screen grabbed input)"); -} - -/* - * handle_input_inhibit_deactivate — the lock screen released exclusive input. - */ -static void -handle_input_inhibit_deactivate(struct wl_listener *listener, void *data) -{ - (void)listener; (void)data; - wwarning("wl_backend: input inhibitor deactivated (lock screen released input)"); -} - /* * handle_virtual_pointer_new — a client created a virtual pointer device * (e.g. a VNC / remote desktop server injecting cursor events). @@ -3694,7 +3606,7 @@ static void handle_pointer_button(struct wl_listener *listener, void *data) { (void)listener; - struct wlr_event_pointer_button *ev = data; + struct wlr_pointer_button_event *ev = data; if (!wl_state.seat) return; /* Phase 22: any button release ends an active grab. */ @@ -3723,7 +3635,7 @@ handle_pointer_button(struct wl_listener *listener, void *data) /* Raise the window in scene Z-order by moving its scene node * to the top of the scene root's child list. */ if (view->scene_node) - wlr_scene_node_raise_to_top(view->scene_node); + wlr_scene_node_raise_to_top(&view->scene_node->node); /* Also raise it in our toplevel list so view_surface_at() * returns it first on subsequent hits. */ wl_list_remove(&view->link); @@ -3781,7 +3693,7 @@ view_surface_at(int px, int py, double *sx_out, double *sy_out, /* Phase 17: XWayland window — simple bounds check on the surface. */ if (v->xw_surface) { - if (!v->xw_surface->mapped || !v->xw_surface->surface) + if (!v->xw_surface->surface || !v->xw_surface->surface->mapped) continue; if (sx >= 0 && sy >= 0 && sx < (double)v->xw_surface->width && @@ -3795,7 +3707,7 @@ view_surface_at(int px, int py, double *sx_out, double *sy_out, } /* XDG toplevel path. */ - if (!v->xdg_surface || !v->xdg_surface->mapped) + if (!v->xdg_surface || !v->xdg_surface->surface || !v->xdg_surface->surface->mapped) continue; double sub_sx, sub_sy; struct wlr_surface *sub = wlr_xdg_surface_surface_at( @@ -3940,12 +3852,256 @@ wl_pointer_change_grab(unsigned int event_mask, int cursor_id, static int wl_keyboard_grab(WNativeWindow win) { (void)win; return 0; } static void wl_keyboard_ungrab(void) {} +/* ------------------------------------------------------------------ */ +/* Phase 81: Overlay animation surface — XOR pixel engine + bitmap */ +/* font for geometry display (miniaturize zoom, transparent */ +/* move/resize frames, position/size readouts). */ +/* ------------------------------------------------------------------ */ + +/* + * XOR mask: 0xFFFFFFFF XOR 0x00000000 (transparent) = 0xFFFFFFFF (opaque + * white); XOR 0xFFFFFFFF again = 0x00000000 (transparent, i.e. erased). + * The overlay scene buffer is composited OVER all client windows via + * standard alpha blending, so transparent pixels show through to the + * desktop and opaque-white pixels appear on top. + */ +#define OVL_MASK 0xFFFFFFFFu + +/* + * 5-wide × 9-tall bitmap font for printable ASCII (0x20–0x7E). + * Encoding: bit 7 = column 0 (left), bit 3 = column 4 (right), bits 2–0 + * unused. Cell width = 6 px (glyph 5 + 1 gap); cell height = 10 px. + */ +#define OVL_GW 5 /* glyph pixel width */ +#define OVL_GH 9 /* glyph pixel height */ +#define OVL_CW 6 /* cell width (px) */ +#define OVL_CH 10 /* cell height (px) */ + +static const uint8_t ovl_font[96][OVL_GH] = { + /*20 ' '*/{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + /*21 '!'*/{0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00}, + /*22 '"'*/{0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00}, + /*23 '#'*/{0x50,0x50,0xF8,0x50,0xF8,0x50,0x50,0x00,0x00}, + /*24 '$'*/{0x20,0x70,0xA0,0x70,0x28,0x70,0x20,0x00,0x00}, + /*25 '%'*/{0xC0,0xC8,0x10,0x20,0x40,0x98,0x18,0x00,0x00}, + /*26 '&'*/{0x60,0x90,0x60,0xA0,0x98,0x90,0x68,0x00,0x00}, + /*27'\''*/ {0x60,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00}, + /*28 '('*/{0x10,0x20,0x40,0x40,0x40,0x20,0x10,0x00,0x00}, + /*29 ')'*/{0x40,0x20,0x10,0x10,0x10,0x20,0x40,0x00,0x00}, + /*2A '*'*/{0x00,0x88,0x50,0xF8,0x50,0x88,0x00,0x00,0x00}, + /*2B '+'*/{0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00,0x00}, + /*2C ','*/{0x00,0x00,0x00,0x00,0x60,0x20,0x40,0x00,0x00}, + /*2D '-'*/{0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00}, + /*2E '.'*/{0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00}, + /*2F '/'*/{0x08,0x08,0x10,0x20,0x40,0x80,0x80,0x00,0x00}, + /*30 '0'*/{0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00}, + /*31 '1'*/{0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00,0x00}, + /*32 '2'*/{0x70,0x88,0x08,0x30,0x40,0x80,0xF8,0x00,0x00}, + /*33 '3'*/{0x70,0x88,0x08,0x30,0x08,0x88,0x70,0x00,0x00}, + /*34 '4'*/{0x10,0x30,0x50,0x90,0xF8,0x10,0x10,0x00,0x00}, + /*35 '5'*/{0xF8,0x80,0xF0,0x08,0x08,0x88,0x70,0x00,0x00}, + /*36 '6'*/{0x38,0x40,0x80,0xF0,0x88,0x88,0x70,0x00,0x00}, + /*37 '7'*/{0xF8,0x08,0x10,0x20,0x20,0x20,0x20,0x00,0x00}, + /*38 '8'*/{0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00,0x00}, + /*39 '9'*/{0x70,0x88,0x88,0x78,0x08,0x08,0x70,0x00,0x00}, + /*3A ':'*/{0x00,0x60,0x60,0x00,0x60,0x60,0x00,0x00,0x00}, + /*3B ';'*/{0x00,0x60,0x60,0x00,0x60,0x20,0x40,0x00,0x00}, + /*3C '<'*/{0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x00,0x00}, + /*3D '='*/{0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00,0x00}, + /*3E '>'*/{0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00,0x00}, + /*3F '?'*/{0x70,0x88,0x08,0x10,0x20,0x00,0x20,0x00,0x00}, + /*40 '@'*/{0x70,0x88,0x98,0xA8,0x98,0x80,0x70,0x00,0x00}, + /*41 'A'*/{0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00,0x00}, + /*42 'B'*/{0xF0,0x88,0x88,0xF0,0x88,0x88,0xF0,0x00,0x00}, + /*43 'C'*/{0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00,0x00}, + /*44 'D'*/{0xE0,0x90,0x88,0x88,0x88,0x90,0xE0,0x00,0x00}, + /*45 'E'*/{0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00,0x00}, + /*46 'F'*/{0xF8,0x80,0x80,0xF0,0x80,0x80,0x80,0x00,0x00}, + /*47 'G'*/{0x70,0x88,0x80,0xB8,0x88,0x88,0x70,0x00,0x00}, + /*48 'H'*/{0x88,0x88,0x88,0xF8,0x88,0x88,0x88,0x00,0x00}, + /*49 'I'*/{0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00}, + /*4A 'J'*/{0x38,0x10,0x10,0x10,0x10,0x90,0x60,0x00,0x00}, + /*4B 'K'*/{0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88,0x00,0x00}, + /*4C 'L'*/{0x80,0x80,0x80,0x80,0x80,0x80,0xF8,0x00,0x00}, + /*4D 'M'*/{0x88,0xD8,0xA8,0x88,0x88,0x88,0x88,0x00,0x00}, + /*4E 'N'*/{0x88,0xC8,0xA8,0x98,0x88,0x88,0x88,0x00,0x00}, + /*4F 'O'*/{0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00}, + /*50 'P'*/{0xF0,0x88,0x88,0xF0,0x80,0x80,0x80,0x00,0x00}, + /*51 'Q'*/{0x70,0x88,0x88,0x88,0xA8,0x90,0x68,0x00,0x00}, + /*52 'R'*/{0xF0,0x88,0x88,0xF0,0xA0,0x90,0x88,0x00,0x00}, + /*53 'S'*/{0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00,0x00}, + /*54 'T'*/{0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00}, + /*55 'U'*/{0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00}, + /*56 'V'*/{0x88,0x88,0x88,0x88,0x50,0x50,0x20,0x00,0x00}, + /*57 'W'*/{0x88,0x88,0x88,0xA8,0xA8,0xD8,0x88,0x00,0x00}, + /*58 'X'*/{0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00,0x00}, + /*59 'Y'*/{0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00,0x00}, + /*5A 'Z'*/{0xF8,0x08,0x10,0x20,0x40,0x80,0xF8,0x00,0x00}, + /*5B '['*/{0x70,0x40,0x40,0x40,0x40,0x40,0x70,0x00,0x00}, + /*5C'\\'*/ {0x80,0x80,0x40,0x20,0x10,0x08,0x08,0x00,0x00}, + /*5D ']'*/{0x70,0x10,0x10,0x10,0x10,0x10,0x70,0x00,0x00}, + /*5E '^'*/{0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00,0x00}, + /*5F '_'*/{0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x00}, + /*60 '`'*/{0x40,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00}, + /*61 'a'*/{0x00,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00}, + /*62 'b'*/{0x80,0x80,0xF0,0x88,0x88,0x88,0xF0,0x00,0x00}, + /*63 'c'*/{0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00,0x00}, + /*64 'd'*/{0x08,0x08,0x78,0x88,0x88,0x88,0x78,0x00,0x00}, + /*65 'e'*/{0x00,0x00,0x70,0x88,0xF8,0x80,0x70,0x00,0x00}, + /*66 'f'*/{0x30,0x48,0x40,0xE0,0x40,0x40,0x40,0x00,0x00}, + /*67 'g'*/{0x00,0x00,0x78,0x88,0x88,0x78,0x08,0x70,0x00}, + /*68 'h'*/{0x80,0x80,0xF0,0x88,0x88,0x88,0x88,0x00,0x00}, + /*69 'i'*/{0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00}, + /*6A 'j'*/{0x10,0x00,0x30,0x10,0x10,0x10,0x90,0x60,0x00}, + /*6B 'k'*/{0x80,0x80,0x90,0xA0,0xC0,0xA0,0x90,0x00,0x00}, + /*6C 'l'*/{0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00}, + /*6D 'm'*/{0x00,0x00,0xD8,0xA8,0xA8,0xA8,0x88,0x00,0x00}, + /*6E 'n'*/{0x00,0x00,0xF0,0x88,0x88,0x88,0x88,0x00,0x00}, + /*6F 'o'*/{0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00}, + /*70 'p'*/{0x00,0x00,0xF0,0x88,0x88,0xF0,0x80,0x80,0x00}, + /*71 'q'*/{0x00,0x00,0x78,0x88,0x88,0x78,0x08,0x08,0x00}, + /*72 'r'*/{0x00,0x00,0xB0,0xC8,0x80,0x80,0x80,0x00,0x00}, + /*73 's'*/{0x00,0x00,0x70,0x80,0x70,0x08,0xF0,0x00,0x00}, + /*74 't'*/{0x40,0x40,0xF0,0x40,0x40,0x48,0x30,0x00,0x00}, + /*75 'u'*/{0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00,0x00}, + /*76 'v'*/{0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00,0x00}, + /*77 'w'*/{0x00,0x00,0x88,0x88,0xA8,0xD8,0x88,0x00,0x00}, + /*78 'x'*/{0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00}, + /*79 'y'*/{0x00,0x00,0x88,0x88,0x78,0x08,0x70,0x00,0x00}, + /*7A 'z'*/{0x00,0x00,0xF8,0x10,0x20,0x40,0xF8,0x00,0x00}, + /*7B '{'*/{0x18,0x20,0x20,0x40,0x20,0x20,0x18,0x00,0x00}, + /*7C '|'*/{0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00,0x00}, + /*7D '}'*/{0x60,0x10,0x10,0x08,0x10,0x10,0x60,0x00,0x00}, + /*7E '~'*/{0x40,0xA8,0x18,0x00,0x00,0x00,0x00,0x00,0x00}, +}; + +/* Lazily allocate (or resize) the full-screen overlay buffer. */ +static void +overlay_ensure(WScreen *scr) +{ + int w, h; + if (scr && scr->scr_width > 0 && scr->scr_height > 0) { + w = scr->scr_width; + h = scr->scr_height; + } else if (wl_state.output) { + w = (int)wl_state.output->width; + h = (int)wl_state.output->height; + } else { + w = 1920; h = 1080; + } + if (wl_state.overlay_surf && + wl_state.overlay_surf->width == w && + wl_state.overlay_surf->height == h) + return; + if (wl_state.overlay_surf) { + wm_shm_surface_destroy(wl_state.overlay_surf); + wl_state.overlay_surf = NULL; + } + wl_state.overlay_surf = wm_shm_surface_create(w, h); +} + +/* XOR a single pixel on the overlay buffer (clipped). */ +static inline void +ovl_plot(struct wm_shm_surface *s, int x, int y) +{ + if ((unsigned)x < (unsigned)s->width && (unsigned)y < (unsigned)s->height) + s->data[y * (int)(s->stride >> 2) + x] ^= OVL_MASK; +} + +/* XOR a horizontal run of `len` pixels starting at (x, y). */ +static void +ovl_hline(struct wm_shm_surface *s, int x, int y, int len) +{ + if ((unsigned)y >= (unsigned)s->height || len <= 0) return; + int x0 = x < 0 ? 0 : x; + int x1 = x + len; if (x1 > s->width) x1 = s->width; + if (x0 >= x1) return; + uint32_t *p = s->data + y * (int)(s->stride >> 2) + x0; + for (int i = x0; i < x1; i++) *p++ ^= OVL_MASK; +} + +/* XOR a vertical run of `len` pixels starting at (x, y). */ +static void +ovl_vline(struct wm_shm_surface *s, int x, int y, int len) +{ + if ((unsigned)x >= (unsigned)s->width || len <= 0) return; + int y0 = y < 0 ? 0 : y; + int y1 = y + len; if (y1 > s->height) y1 = s->height; + int stride = (int)(s->stride >> 2); + for (int j = y0; j < y1; j++) + s->data[j * stride + x] ^= OVL_MASK; +} + +/* Bresenham line (with fast h/v paths). */ +static void +ovl_line(struct wm_shm_surface *s, int x0, int y0, int x1, int y1) +{ + if (x0 == x1) { + int y = y0 < y1 ? y0 : y1; + ovl_vline(s, x0, y, abs(y1 - y0) + 1); + return; + } + if (y0 == y1) { + int x = x0 < x1 ? x0 : x1; + ovl_hline(s, x, y0, abs(x1 - x0) + 1); + return; + } + int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1; + int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1; + int err = dx + dy; + for (;;) { + ovl_plot(s, x0, y0); + if (x0 == x1 && y0 == y1) break; + int e2 = 2 * err; + if (e2 >= dy) { err += dy; x0 += sx; } + if (e2 <= dx) { err += dx; y0 += sy; } + } +} + +/* Render one glyph at cell origin (cx, cy) using XOR. */ +static void +ovl_draw_glyph(struct wm_shm_surface *s, int cx, int cy, unsigned char ch) +{ + if (ch < 0x20 || ch > 0x7E) ch = '?'; + const uint8_t *g = ovl_font[ch - 0x20]; + for (int row = 0; row < OVL_GH; row++) { + uint8_t bits = g[row]; + if (!bits) continue; + int py = cy + row; + if (py < 0 || py >= s->height) continue; + for (int col = 0; col < OVL_GW; col++) { + if (bits & (0x80u >> col)) + ovl_plot(s, cx + col, py); + } + } +} + +/* Push the modified overlay buffer to the scene and render a frame. */ +static void +overlay_flush(void) +{ + struct wm_shm_surface *s = wl_state.overlay_surf; + if (!s || !wl_state.scene) return; + /* First call creates the scene_buffer node; subsequent calls reposition. */ + wm_shm_surface_commit(s, &wl_state.scene->tree, 0, 0); + if (s->scene_buf) { + /* Notify wlroots that the pixel data has changed. */ + wlr_scene_buffer_set_buffer(s->scene_buf, &s->wlr_buf); + /* Keep the overlay above all client windows. */ + wlr_scene_node_raise_to_top(&s->scene_buf->node); + } + /* Commit the scene immediately so the animation step is visible + * before the caller's wusleep() delay. */ + if (wl_state.scene_output && wl_state.allocator) + wlr_scene_output_commit(wl_state.scene_output, NULL); +} + /* ------------------------------------------------------------------ */ /* Server grab */ /* ------------------------------------------------------------------ */ -static void wl_server_grab(void) {} -static void wl_server_ungrab(void) {} +static void wl_server_grab(void) {} /* no-op: Wayland double-buffers for us */ +static void wl_server_ungrab(void) { overlay_flush(); } /* ------------------------------------------------------------------ */ /* Stacking */ @@ -4035,7 +4191,7 @@ wl_prop_get_normal_hints(WNativeWindow win, WNormalHints *out, int *pre_icccm) /* Phase 17: XWayland size_hints path. */ if (v->xw_surface) { - struct wlr_xwayland_surface_size_hints *sh = v->xw_surface->size_hints; + xcb_size_hints_t *sh = v->xw_surface->size_hints; if (sh) { if (sh->min_width > 0 || sh->min_height > 0) { out->flags |= WNH_P_MIN_SIZE; @@ -4166,10 +4322,10 @@ wl_prop_get_transient_for(WNativeWindow win) } if (!v->xdg_surface || !v->xdg_surface->toplevel) return WNATIVE_NONE; - struct wlr_xdg_surface *parent = v->xdg_surface->toplevel->parent; - if (!parent) + struct wlr_xdg_toplevel *ptl = v->xdg_surface->toplevel->parent; + if (!ptl || !ptl->base) return WNATIVE_NONE; - struct wl_toplevel_view *pv = wl_find_view_by_xdg_surface(parent); + struct wl_toplevel_view *pv = wl_find_view_by_xdg_surface(ptl->base); if (!pv) return WNATIVE_NONE; return pv->id; @@ -4211,7 +4367,7 @@ wl_window_map(WNativeWindow win) /* Show the scene node for this window (workspace switch arriving on workspace). */ struct wl_toplevel_view *v = wl_find_view_by_id(win); if (v && v->scene_node) - wlr_scene_node_set_enabled(v->scene_node, true); + wlr_scene_node_set_enabled(&v->scene_node->node, true); } static void wl_window_map_raised(WNativeWindow win) { (void)win; } @@ -4223,7 +4379,7 @@ wl_window_unmap(WNativeWindow win) /* Hide the scene node for this window (workspace switch leaving workspace). */ struct wl_toplevel_view *v = wl_find_view_by_id(win); if (v && v->scene_node) - wlr_scene_node_set_enabled(v->scene_node, false); + wlr_scene_node_set_enabled(&v->scene_node->node, false); } static void wl_window_move(WNativeWindow win, int x, int y) { @@ -4234,7 +4390,7 @@ static void wl_window_move(WNativeWindow win, int x, int y) v->x = x; v->y = y; /* Phase 18: keep scene node in sync with WM position. */ if (v->scene_node) - wlr_scene_node_set_position(v->scene_node, x, y); + wlr_scene_node_set_position(&v->scene_node->node, x, y); if (v->xw_surface) wlr_xwayland_surface_configure(v->xw_surface, (int16_t)x, (int16_t)y, v->xw_surface->width, v->xw_surface->height); @@ -4251,8 +4407,8 @@ static void wl_window_resize(WNativeWindow win, int w, int h) (int16_t)v->x, (int16_t)v->y, (uint16_t)w, (uint16_t)h); return; } - if (!v->xdg_surface) return; - wlr_xdg_toplevel_set_size(v->xdg_surface, (uint32_t)w, (uint32_t)h); + if (!v->xdg_surface || !v->xdg_surface->toplevel) return; + wlr_xdg_toplevel_set_size(v->xdg_surface->toplevel, (uint32_t)w, (uint32_t)h); wlr_xdg_surface_schedule_configure(v->xdg_surface); } static void wl_window_set_border(WNativeWindow win, unsigned long pixel) { (void)win; (void)pixel; } @@ -4305,12 +4461,66 @@ static void wl_window_shape_set(WWindow *wwin) { (void)wwin; } /* Overlays */ /* ------------------------------------------------------------------ */ -static void wl_overlay_draw_line(WScreen *scr, int x1, int y1, int x2, int y2) { (void)scr; (void)x1; (void)y1; (void)x2; (void)y2; } -static void wl_overlay_draw_lines(WScreen *scr, WPoint *pts, int n) { (void)scr; (void)pts; (void)n; } -static void wl_overlay_draw_rect(WScreen *scr, int x, int y, int w, int h) { (void)scr; (void)x; (void)y; (void)w; (void)h; } -static void wl_overlay_draw_segments(WScreen *scr, WSegment *segs, int n) { (void)scr; (void)segs; (void)n; } -static void wl_overlay_draw_string(WScreen *scr, int x, int y, const char *str, int len) { (void)scr; (void)x; (void)y; (void)str; (void)len; } -static int wl_overlay_text_width(WScreen *scr, const char *str, int n) { (void)scr; (void)str; (void)n; return 0; } +static void +wl_overlay_draw_line(WScreen *scr, int x1, int y1, int x2, int y2) +{ + overlay_ensure(scr); + if (wl_state.overlay_surf) + ovl_line(wl_state.overlay_surf, x1, y1, x2, y2); +} + +static void +wl_overlay_draw_lines(WScreen *scr, WPoint *pts, int n) +{ + overlay_ensure(scr); + struct wm_shm_surface *s = wl_state.overlay_surf; + if (!s || n < 2) return; + for (int i = 0; i < n - 1; i++) + ovl_line(s, pts[i].x, pts[i].y, pts[i+1].x, pts[i+1].y); +} + +static void +wl_overlay_draw_rect(WScreen *scr, int x, int y, int w, int h) +{ + overlay_ensure(scr); + struct wm_shm_surface *s = wl_state.overlay_surf; + if (!s || w <= 0 || h <= 0) return; + /* Matching XDrawRectangle semantics: corners are shared between + * adjacent edges and therefore XOR'd twice (become transparent). */ + ovl_hline(s, x, y, w + 1); /* top */ + ovl_hline(s, x, y + h, w + 1); /* bottom */ + ovl_vline(s, x, y, h + 1); /* left */ + ovl_vline(s, x + w, y, h + 1); /* right */ +} + +static void +wl_overlay_draw_segments(WScreen *scr, WSegment *segs, int n) +{ + overlay_ensure(scr); + struct wm_shm_surface *s = wl_state.overlay_surf; + if (!s) return; + for (int i = 0; i < n; i++) + ovl_line(s, segs[i].x1, segs[i].y1, segs[i].x2, segs[i].y2); +} + +static void +wl_overlay_draw_string(WScreen *scr, int x, int y, const char *str, int len) +{ + overlay_ensure(scr); + struct wm_shm_surface *s = wl_state.overlay_surf; + if (!s || !str) return; + /* y is the text baseline; render from the top of the cell. */ + int top = y - (OVL_GH - 2); + for (int i = 0; i < len; i++) + ovl_draw_glyph(s, x + i * OVL_CW, top, (unsigned char)str[i]); +} + +static int +wl_overlay_text_width(WScreen *scr, const char *str, int n) +{ + (void)scr; (void)str; + return n * OVL_CW; +} /* ------------------------------------------------------------------ */ /* Client */ @@ -4324,7 +4534,7 @@ wl_window_get_client_attrs(WNativeWindow win, WClientAttributes *out) struct wl_toplevel_view *v = wl_find_view_by_id(win); memset(out, 0, sizeof(*out)); if (v && v->xw_surface) { - if (v->xw_surface->mapped) { + if (v->xw_surface->surface && v->xw_surface->surface->mapped) { out->map_state = WCLIENT_VIEWABLE; out->width = v->xw_surface->width; out->height = v->xw_surface->height; @@ -4372,7 +4582,7 @@ wl_client_synth_configure(WNativeWindow client_win, v->y = y; /* Phase 18: keep scene node in sync. */ if (v->scene_node) - wlr_scene_node_set_position(v->scene_node, x, y); + wlr_scene_node_set_position(&v->scene_node->node, x, y); if (v->xw_surface) { wlr_xwayland_surface_configure(v->xw_surface, (int16_t)x, (int16_t)y, @@ -4380,9 +4590,9 @@ wl_client_synth_configure(WNativeWindow client_win, height > 0 ? (uint16_t)height : v->xw_surface->height); return; } - if (!v->xdg_surface) return; + if (!v->xdg_surface || !v->xdg_surface->toplevel) return; if (width > 0 && height > 0) - wlr_xdg_toplevel_set_size(v->xdg_surface, (uint32_t)width, (uint32_t)height); + wlr_xdg_toplevel_set_size(v->xdg_surface->toplevel, (uint32_t)width, (uint32_t)height); wlr_xdg_surface_schedule_configure(v->xdg_surface); } @@ -4398,8 +4608,8 @@ wl_client_close(WNativeWindow win) if (!v) return; if (v->xw_surface) wlr_xwayland_surface_close(v->xw_surface); - else if (v->xdg_surface) - wlr_xdg_toplevel_send_close(v->xdg_surface); + else if (v->xdg_surface && v->xdg_surface->toplevel) + wlr_xdg_toplevel_send_close(v->xdg_surface->toplevel); } static void wl_client_query_shaped(WNativeWindow win, int *shaped_out) @@ -4528,7 +4738,19 @@ wl_screen_create_internals(WScreen *scr) wm_dock_create(scr); } static void wl_screen_create_pixmaps(WScreen *scr) { (void)scr; } -static void wl_screen_load_tech_font(WScreen *scr) { (void)scr; } +static void +wl_screen_load_tech_font(WScreen *scr) +{ + if (!scr || scr->tech_draw_font) return; + /* Provide font metrics matching our embedded 5×9 bitmap font so that + * callers computing text height (ascent + descent) get correct values + * without crashing on a NULL pointer. */ + scr->tech_draw_font = calloc(1, sizeof(*scr->tech_draw_font)); + if (scr->tech_draw_font) { + scr->tech_draw_font->ascent = OVL_GH - 2; /* 7 */ + scr->tech_draw_font->descent = 2; + } +} static void wl_screen_show_mini_screenshot(WScreen *scr, RImage *img) { (void)scr; (void)img; } static RImage *wl_screen_capture_area(WScreen *scr) { (void)scr; return NULL; } static RImage *wl_screen_capture_window(WScreen *scr, WWindow *wwin) { (void)scr; (void)wwin; return NULL; } @@ -4553,13 +4775,13 @@ wl_monitors_query(WScreen *scr, WHeadGeometry **heads_out, int *count_out) WHeadGeometry *heads = wmalloc(sizeof(WHeadGeometry)); if (wl_state.output_layout) { - const struct wlr_box *box = - wlr_output_layout_get_box(wl_state.output_layout, wl_state.output); - if (box) { - heads[0].x = box->x; - heads[0].y = box->y; - heads[0].width = box->width; - heads[0].height = box->height; + struct wlr_box box = {0}; + wlr_output_layout_get_box(wl_state.output_layout, wl_state.output, &box); + if (box.width > 0 || box.height > 0) { + heads[0].x = box.x; + heads[0].y = box.y; + heads[0].width = box.width; + heads[0].height = box.height; } else { heads[0].x = heads[0].y = 0; heads[0].width = (int)wl_state.output->width; @@ -4598,28 +4820,32 @@ wl_workspace_badge_update(WScreen *scr, WNativeWindow badge_win, RImage *img) static WKeyCode wl_keysym_to_keycode(unsigned long keysym) { - /* Phase 77: scan the XKB keymap on the headless keyboard to find the first - * keycode that produces the given keysym at any level/layout. - * The XKB keycode == evdev_scancode + 8, which equals the X11 keycode — - * so the values stored in wKeyBindings are directly compatible. */ - if (!wl_state.keyboard_dev || !wl_state.keyboard_dev->keyboard) - return 0; - struct wlr_keyboard *kb = wl_state.keyboard_dev->keyboard; - if (!kb->keymap) + /* Phase 77: scan the XKB keymap to find the first keycode that produces + * the given keysym at any level/layout. The XKB keycode == + * evdev_scancode + 8, which equals the X11 keycode — so the values stored + * in wKeyBindings are directly compatible. + * Use the real keyboard's keymap if available; fall back to the default + * keymap created at startup (before any real keyboard arrives). */ + struct xkb_keymap *km = wl_state.xkb_keymap; + if (wl_state.keyboard_dev) { + struct wlr_keyboard *kb = wlr_keyboard_from_input_device(wl_state.keyboard_dev); + if (kb && kb->keymap) km = kb->keymap; + } + if (!km) return 0; - xkb_keycode_t min_kc = xkb_keymap_min_keycode(kb->keymap); - xkb_keycode_t max_kc = xkb_keymap_max_keycode(kb->keymap); + xkb_keycode_t min_kc = xkb_keymap_min_keycode(km); + xkb_keycode_t max_kc = xkb_keymap_max_keycode(km); for (xkb_keycode_t kc = min_kc; kc <= max_kc; kc++) { - xkb_layout_index_t nlayouts = xkb_keymap_num_layouts_for_key(kb->keymap, kc); + xkb_layout_index_t nlayouts = xkb_keymap_num_layouts_for_key(km, kc); xkb_layout_index_t layout; for (layout = 0; layout < nlayouts; layout++) { - xkb_level_index_t nlevels = xkb_keymap_num_levels_for_key(kb->keymap, kc, layout); + xkb_level_index_t nlevels = xkb_keymap_num_levels_for_key(km, kc, layout); xkb_level_index_t level; for (level = 0; level < nlevels; level++) { const xkb_keysym_t *syms = NULL; - int n = xkb_keymap_key_get_syms_by_level(kb->keymap, kc, layout, level, &syms); + int n = xkb_keymap_key_get_syms_by_level(km, kc, layout, level, &syms); int si; for (si = 0; si < n; si++) { if (syms[si] == (xkb_keysym_t)keysym) @@ -4635,13 +4861,15 @@ static unsigned long wl_keysym_from_keycode(unsigned int keycode, unsigned int index) { /* Phase 77: reverse lookup — return the keysym at the given keycode/level. */ - if (!wl_state.keyboard_dev || !wl_state.keyboard_dev->keyboard) - return 0; - struct wlr_keyboard *kb = wl_state.keyboard_dev->keyboard; - if (!kb->keymap) + struct xkb_keymap *km = wl_state.xkb_keymap; + if (wl_state.keyboard_dev) { + struct wlr_keyboard *kb = wlr_keyboard_from_input_device(wl_state.keyboard_dev); + if (kb && kb->keymap) km = kb->keymap; + } + if (!km) return 0; const xkb_keysym_t *syms = NULL; - int n = xkb_keymap_key_get_syms_by_level(kb->keymap, (xkb_keycode_t)keycode, + int n = xkb_keymap_key_get_syms_by_level(km, (xkb_keycode_t)keycode, 0, (xkb_level_index_t)index, &syms); if (n > 0 && syms) return (unsigned long)syms[0]; diff --git a/src/startup.c b/src/startup.c index 1583d69..5f0293f 100644 --- a/src/startup.c +++ b/src/startup.c @@ -33,6 +33,7 @@ #endif +#include /* XrmUniqueQuark — needed by XUniqueContext() */ #include "WindowMaker.h" #include "GNUstep.h" #include "texture.h"