diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8f0ee9a9..30fca07d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -98,11 +98,11 @@ variables:
# See the documentation here: #
# https://wayland.freedesktop.org/libinput/doc/latest/building.html #
###############################################################################
- FEDORA_PACKAGES: 'git-core gcc gcc-c++ pkgconf-pkg-config meson check-devel libudev-devel libevdev-devel doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx_rtd_theme python3-pytest-xdist libwacom-devel cairo-devel gtk4-devel glib2-devel mtdev-devel diffutils wayland-protocols-devel black clang clang-tools-extra jq rpmdevtools valgrind systemd-udev qemu-img qemu-system-x86-core qemu-system-aarch64-core jq python3-click python3-rich virtme-ng luajit-devel'
- DEBIAN_PACKAGES: 'git gcc g++ pkg-config meson check libudev-dev libevdev-dev doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme python3-pytest-xdist libwacom-dev libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev curl libluajit-5.1-dev'
- UBUNTU_PACKAGES: 'git gcc g++ pkg-config meson check libudev-dev libevdev-dev doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme python3-pytest-xdist libwacom-dev libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev libluajit-5.1-dev'
- ARCH_PACKAGES: 'git gcc pkgconfig meson check libsystemd libevdev python-pytest-xdist libwacom gtk4 mtdev diffutils luajit'
- ALPINE_PACKAGES: 'git gcc build-base pkgconfig meson check-dev eudev-dev libevdev-dev libwacom-dev cairo-dev gtk4.0-dev mtdev-dev bash luajit-dev'
+ FEDORA_PACKAGES: 'git-core gcc gcc-c++ pkgconf-pkg-config meson check-devel libudev-devel libevdev-devel doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx_rtd_theme python3-pytest-xdist libwacom-devel cairo-devel gtk4-devel glib2-devel mtdev-devel diffutils wayland-protocols-devel black clang clang-tools-extra jq rpmdevtools valgrind systemd-udev qemu-img qemu-system-x86-core qemu-system-aarch64-core jq python3-click python3-rich virtme-ng lua-devel'
+ DEBIAN_PACKAGES: 'git gcc g++ pkg-config meson check libudev-dev libevdev-dev doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme python3-pytest-xdist libwacom-dev libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev curl lua5.4-dev'
+ UBUNTU_PACKAGES: 'git gcc g++ pkg-config meson check libudev-dev libevdev-dev doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme python3-pytest-xdist libwacom-dev libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev lua5.4-dev'
+ ARCH_PACKAGES: 'git gcc pkgconfig meson check libsystemd libevdev python-pytest-xdist libwacom gtk4 mtdev diffutils lua'
+ ALPINE_PACKAGES: 'git gcc build-base pkgconfig meson check-dev eudev-dev libevdev-dev libwacom-dev cairo-dev gtk4.0-dev mtdev-dev bash lua5.4-dev'
FREEBSD_PACKAGES: 'git pkgconf meson libepoll-shim libudev-devd libevdev libwacom gtk3 libmtdev bash wayland'
############################ end of package lists #############################
@@ -110,12 +110,12 @@ variables:
# changing these will force rebuilding the associated image
# Note: these tags have no meaning and are not tied to a particular
# libinput version
- FEDORA_TAG: '2025-11-04.0'
- DEBIAN_TAG: '2025-11-04.0'
- UBUNTU_TAG: '2025-11-04.0'
- ARCH_TAG: '2025-11-04.0'
- ALPINE_TAG: '2025-11-04.0'
- FREEBSD_TAG: '2025-11-04.0'
+ FEDORA_TAG: '2025-11-17.0'
+ DEBIAN_TAG: '2025-11-17.0'
+ UBUNTU_TAG: '2025-11-17.0'
+ ARCH_TAG: '2025-11-17.0'
+ ALPINE_TAG: '2025-11-17.0'
+ FREEBSD_TAG: '2025-11-17.0'
FDO_UPSTREAM_REPO: libinput/libinput
diff --git a/.gitlab-ci/config.yml b/.gitlab-ci/config.yml
index 7401f19e..7edc2104 100644
--- a/.gitlab-ci/config.yml
+++ b/.gitlab-ci/config.yml
@@ -3,7 +3,7 @@
#
# We're happy to rebuild all containers when one changes.
-.default_tag: &default_tag '2025-11-04.0'
+.default_tag: &default_tag '2025-11-17.0'
distributions:
- name: fedora
@@ -50,7 +50,7 @@ distributions:
- python3-click
- python3-rich
- virtme-ng
- - luajit-devel
+ - lua-devel
- name: debian
tag: *default_tag
versions:
@@ -76,7 +76,7 @@ distributions:
- libglib2.0-dev
- libmtdev-dev
- curl # for the coverity job
- - libluajit-5.1-dev
+ - lua5.4-dev
- name: ubuntu
tag: *default_tag
versions:
@@ -101,7 +101,7 @@ distributions:
- libgtk-3-dev
- libglib2.0-dev
- libmtdev-dev
- - libluajit-5.1-dev
+ - lua5.4-dev
- name: arch
tag: *default_tag
versions:
@@ -119,7 +119,7 @@ distributions:
- gtk4
- mtdev
- diffutils
- - luajit
+ - lua
build:
extra_variables:
- "MESON_ARGS: '-Ddocumentation=false'" # python-recommonmark is no longer in the repos
@@ -140,7 +140,7 @@ distributions:
- gtk4.0-dev
- mtdev-dev
- bash
- - luajit-dev
+ - lua5.4-dev
build:
extra_variables:
- "MESON_ARGS: '-Ddocumentation=false' # alpine does not have python-recommonmark"
diff --git a/doc/user/lua-plugins.rst b/doc/user/lua-plugins.rst
index c2683266..d507b058 100644
--- a/doc/user/lua-plugins.rst
+++ b/doc/user/lua-plugins.rst
@@ -9,7 +9,7 @@ of devices. For example, a plugin may add or remove axes and/or buttons on a
device and/or modify the event stream seen by this device before it is passed
to libinput.
-Plugins are implemented in `Lua `_ (version 5.1)
+Plugins are implemented in `Lua `_ (version 5.4)
and are typically loaded from the following paths:
- ``/etc/libinput/plugins/*.lua``, and
@@ -29,7 +29,7 @@ before ``10-bar.lua``) and each plugin sees the state left by any previous
plugins. For example if ``00-foo.lua`` changes all left button events to right
button events, ``10-bar.lua`` only ever sees right button events.
-See the `Lua Reference manual `_ for
+See the `Lua Reference manual `_ for
details on the Lua language.
.. note:: Plugins are **not** loaded by default, it is up to the compositor
diff --git a/meson.build b/meson.build
index bb253c42..5d484790 100644
--- a/meson.build
+++ b/meson.build
@@ -168,7 +168,8 @@ dep_libevdev = dependency('libevdev', version: '>= 1.10.0')
dep_lm = cc.find_library('m', required : false)
dep_rt = cc.find_library('rt', required : false)
-dep_lua = dependency(get_option('lua-interpreter'),
+dep_lua = dependency('lua-5.4', 'lua5.4', 'lua',
+ version : '>= 5.4',
required : get_option('lua-plugins'))
have_lua = dep_lua.found()
if have_lua
@@ -193,11 +194,6 @@ summary({
section : 'Plugins',
bool_yn : true)
-if have_lua
- summary({'Lua Interpreter' : get_option('lua-interpreter')},
- section : 'Plugins')
-endif
-
# Include directories
includes_include = include_directories('include')
includes_src = include_directories('src')
diff --git a/meson_options.txt b/meson_options.txt
index de0b1c41..20d7e05e 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -50,7 +50,3 @@ option('lua-plugins',
type: 'feature',
value: 'auto',
description: 'Enable support for Lua plugins')
-option('lua-interpreter',
- type: 'string',
- value: 'luajit',
- description: 'The Lua interpreter to use (pkgconfig name)')
diff --git a/src/libinput-plugin-lua.c b/src/libinput-plugin-lua.c
index c11998f3..c7581236 100644
--- a/src/libinput-plugin-lua.c
+++ b/src/libinput-plugin-lua.c
@@ -296,18 +296,7 @@ libinput_lua_pcall(struct libinput_lua_plugin *plugin, int narg, int nres)
{
lua_State *L = plugin->L;
- lua_pushvalue(L, -(narg + 1)); /* Copy the function */
- lua_pushvalue(L, plugin->sandbox_table_idx);
- /* Now set the sandbox environment for the function we're about to call */
- int rc = lua_setfenv(L, -2) == 1 ? LUA_OK : LUA_ERRRUN;
- if (rc == LUA_OK) {
- /* Replace original function with sandboxed one */
- lua_replace(L, -(narg + 2));
- /* Now call the function */
- rc = lua_pcall(L, narg, nres, 0);
- } else {
- lua_pushstring(L, "Failed to set up sandbox");
- }
+ int rc = lua_pcall(L, narg, nres, 0);
if (rc != LUA_OK) {
auto libinput_plugin = plugin->parent;
const char *errormsg = lua_tostring(L, -1);
@@ -1120,6 +1109,22 @@ libinput_lua_plugin_run(struct libinput_plugin *libinput_plugin)
{
struct libinput_lua_plugin *plugin =
libinput_plugin_get_user_data(libinput_plugin);
+ struct lua_State *L = plugin->L;
+
+ assert(lua_isfunction(L, -1));
+
+ /* Main entry point into the plugin, so we need to push our sandbox
+ * as _ENV. This only needs to be done here because all other entry
+ * points into the Lua script are callbacks that are set up during
+ * this run (and thus share the _ENV)
+ */
+ lua_pushvalue(L, plugin->sandbox_table_idx);
+ const char *upval = lua_setupvalue(L, -2, 1);
+ if (!upval || !streq(upval, "_ENV")) {
+ plugin_log_bug_libinput(libinput_plugin, "Failed to set up sandbox\n");
+ libinput_plugin_unregister(libinput_plugin);
+ return;
+ }
if (libinput_lua_pcall(plugin, 0, 0) && !plugin->register_called) {
plugin_log_bug(libinput_plugin,
@@ -1206,7 +1211,7 @@ libinput_lua_plugin_init_lua(struct libinput *libinput,
if (!L)
return NULL;
- /* This will be our our global env later, see libinput_lua_pcall() */
+ /* This will be our _ENV later, see libinput_lua_pcall */
lua_newtable(L);
int sandbox_table_idx = lua_gettop(L);
plugin->sandbox_table_idx = sandbox_table_idx;
@@ -1219,36 +1224,34 @@ libinput_lua_plugin_init_lua(struct libinput *libinput,
* all have their own individual sandbox.
*/
- luaopen_base(L);
+ luaL_requiref(L, LUA_GNAME, luaopen_base, 0);
static const char *allowed_funcs[] = {
"assert", "error", "ipairs", "next", "pcall", "pairs", "print",
"select", "tonumber", "tostring", "type", "xpcall", "_VERSION",
};
ARRAY_FOR_EACH(allowed_funcs, func) {
- lua_getglobal(L, *func);
+ lua_getfield(L, -1, *func);
lua_setfield(L, sandbox_table_idx, *func);
}
+ lua_pop(L, 1);
/* Math is fine as a whole */
- luaopen_math(L);
- lua_getglobal(L, "math");
+ luaL_requiref(L, LUA_MATHLIBNAME, luaopen_math, 0);
lua_setfield(L, sandbox_table_idx, "math");
/* Table is fine as a whole */
- luaopen_table(L);
- lua_getglobal(L, "table");
+ luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 0);
lua_setfield(L, sandbox_table_idx, "table");
/* String is fine as a whole */
- luaopen_string(L);
- lua_getglobal(L, "string");
+ luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 0);
lua_setfield(L, sandbox_table_idx, "string");
/* Override metatable to prevent access to unregistered globals */
+ lua_pushvalue(L, sandbox_table_idx);
lua_newtable(L);
- lua_pushstring(L, "__index");
lua_pushnil(L);
- lua_settable(L, -3);
+ lua_setfield(L, -2, "__index");
lua_setmetatable(L, sandbox_table_idx);
/* Our objects */