This PR is a follow-up to the discussion in #6372 .
I'm not too familiar with the internals of X11, but it seems that sequence numbers are sometimes of type `uint16_t` and sometimes of type `unsigned int` or `uint32_t`. In some places XCB provides the field `full_sequence` (for example as part of `xcb_generic_event_t`), but other structs only have the 16-bit sequence. Then there is also `xcb_void_cookie_t` which has `unsigned int` for `sequence`.
The current code for tracking ignored events mixes these different data types. This works fine, as long as the sequence number doesn't overflow a `uint16_t`. Afterwards, the tracking of ignored events will fail. This appears to be the reason for #6372 and probably also #6364 . There is also the open PR https://github.com/i3/i3/pull/6559 which notes: "[...] add the sequence to the ignore list, but under some (unknown) circumstances, that does not seem to work reliably."
This problem already existed in 4.23 (and before), but only became visible in 4.24, because it seems that is was masked by using `XCB_GRAB_MODE_SYNC` when executing key bindings. This seems to mask the bug, but sending a command via `i3-msg` also triggers it in 4.23 . Commit b42dc21068 changed `XCB_GRAB_MODE_SYNC` to `XCB_GRAB_MODE_ASYNC` and surfaced the bug. Additionally, the commit https://github.com/i3/i3/commit/cfa4cf16 increased the number of messages being sent and sequence numbers being used, which triggers this bug more quickly than before.
The first commit in this PR introduces a test for #6372 . I found a more performant way of overflowing the uint16_t sequence number (using sync_with_i3 to create fairly cheap messages). The test runs in 1.3 seconds on my system.
The second commit fixes the problem. It defines a new data type `ignore_event_sequence_t` and a macro `ENSURE_FULL_SEQUENCE` which is then used at every call site for `add_ignore_event` and `event_is_ignored`. This way the compiler checks that a full sequence number is used everywhere. Perhaps this is over-engineered? Please let me know - I don't work much in C.
This change makes the test pass and also fixes#6372 for me in my manual testing.
Looking forward to feedback!
Disclosure of AI assistance: I used Claude Fable 5 and GPT-5.6 Sol as sparring partners, but everything here is hand-written.
This commit reverses the default:
Previously, test case authors had to call sync_with_i3 explicitly
whenever they wanted to verify the X11 effects of an i3 command.
With this commit, cmd calls sync_with_i3 by default. Test case authors
no longer need to worry about this, only about the few cases where the
opposite is needed: cmd_nosync.
Created with help by Claude Opus 4.6
(for prototyping this change, but all words in this commit are my own)
related to https://github.com/i3/i3/issues/3009
This package used to be included transitively, but no longer is.
Test cases like t/555-i3bar-workspace-output-assignment.t
which use XTEST need crypt.h available (via Inline::C).
I am not making this conditional because we intend to switch to a different JSON
library soon anyway, which will make locale switching unnecessary entirely.
fixes https://github.com/i3/i3/issues/6566
Without this change, I see the following (harmless but annoying)
compiler warnings when building i3 after `meson setup build`:
[3/106] Compiling C object libi3.a.p/libi3_g_utf8_make_valid.c.o
In file included from /nix/store/gi4cz4ir3zlwhf1azqfgxqdnczfrwsr7-glibc-2.40-66-dev/include/bits/libc-header-start.h:33,
from /nix/store/gi4cz4ir3zlwhf1azqfgxqdnczfrwsr7-glibc-2.40-66-dev/include/stdio.h:28,
from ../include/libi3.h:17,
from ../libi3/g_utf8_make_valid.c:20:
/nix/store/gi4cz4ir3zlwhf1azqfgxqdnczfrwsr7-glibc-2.40-66-dev/include/features.h:422:4: warning: #warning _FORTIFY_SOURCE requires compiling with optimization (-O) [-Wcpp]
422 | # warning _FORTIFY_SOURCE requires compiling with optimization (-O)
| ^~~~~~~
This makes it possible to build i3 (for development)
on any system on which Nix can be installed (= most Linux systems).
For example, I start Emacs using `nix develop --command emacs`
and that Emacs process is in an environment with all i3 build deps.
See also:
https://michael.stapelberg.ch/posts/2025-07-27-dev-shells-with-nix-4-quick-examples/
This file is provided best-effort, but PRs are welcome.
While users can already run `nix develop nixpkgs#i3`,
for nix-direnv integration it is required to declare a flake.nix
in the project directory (otherwise direnv cannot find it).
similar to https://github.com/i3/i3lock/pull/372
related to https://github.com/i3/i3/pull/6549
Rename 554-crash-floating-enable.t to 554-commands-crash-for-window.t
and convert it to a table-driven test. This isn't based on any existing
bugs, just to prevent unexpected failures or change of behaviour.
These were supposed to fail quickly instead of hanging,
but in practice that is prone to flakiness.
Let’s remove the timers to reduce flakiness.
related to https://github.com/i3/i3/issues/3009
This test was flaky because it issued a 'kill' command through i3
and assumed that focus would immediately be different afterwards.
However, the 'kill' command (via x_window_kill) only results in an
xcb_destroy_window() request to X11, not in a focus change.
Only when i3 processes the X11 server response to this request
will focus change back to the window that should be changed with
the 'border normal 0' command.
related to https://github.com/i3/i3/issues/3009
When running 'floating toggle' (or enable/disable) on an empty
workspace, the focused container is the workspace itself, which has
window=NULL. The command would call run_assignments(workspace->window),
which would pass NULL to match_matches_window(), causing a crash when
trying to access window->id.
Add a NULL check at the beginning of `run_assignments` to immediately
skip assignments for that case.
Fixes: #6561
This reverts commit c5d0d5e837.
By starting i3 in a systemd unit, the user’s environment is lost.
This breaks too many workflows.
Blanket-importing the environment using systemctl import-environment
(without arguments) is explicitly discouraged in the systemctl man page.
It’s not clear how to fix this issue cleanly, so revert to unblock the release.
related to https://github.com/i3/i3/issues/5186
On Linux systems using systemd, we should activate graphical-session.target.
We conceptually need our i3.desktop file to do a
blockingly-run-via-systemd action (this is what scopes the activation of
graphical-session.target to the X session), and shipping an i3.service
is the best way to define the systemd unit we use for that.
Based on https://github.com/i3/i3/pull/5591 by David Sansome.
fixes https://github.com/i3/i3/issues/5186
I noticed that the Nix build does not actually work when using the
“#!/usr/bin/env $^X” shebang because /usr/bin/env is not present in the
Nix build sandbox.
$Config{perlpath} is always absolute, so let’s prefer that.
Tested both inside and outside a Nix build sandbox.
related to https://github.com/i3/i3/pull/6537
Calling `feature->import(":5.10")` without loading feature.pm first
produces a warning in Nix derivation sandbox environments:
Attempt to call undefined import method with arguments (":5.10")
via package "feature" (Perhaps you forgot to load the package?)
Unlike the `strict` and `warnings` packages, which are loaded
by the use statements at the top of i3test.pm, the `use v5.10` line
does not load the `feature` package, but is handled directly by perl(1).
This commit adds explicit require statements for correctness.
The test creates a fake i3-msg Perl script at runtime. Previously it
used `#!/usr/bin/env perl` as the shebang, but this can fail in certain
build environments (e.g., Nix sandboxed builds) where the `perl` found
via `/usr/bin/env` may not have the same module paths as the `perl`
running the test suite.
Use `$^X` instead, which contains the path to the Perl interpreter
currently running the test. This ensures the generated script uses the
same Perl with the same `PERL5LIB` environment, guaranteeing that
`JSON::XS` and other required modules are available.
Before this commit, we used setlocale(LC_NUMERIC, "");,
but that is not correct because it doesn’t nest:
load_layout.c (sets LC_NUMERIC=C) calls con_mark(),
which calls ipc_send_window_event() (sets LC_NUMERIC=C),
which calls setlocale(LC_NUMERIC, ""); when returning,
but now load_layout has LC_NUMERIC set per the environment,
whereas the function expects to remain in LC_NUMERIC=C.
Using newlocale and uselocale just swaps handles,
which is a little cleaner than querying the locale with
strdup(setlocale(LC_NUMERIC, NULL)); and restoring it later.
The test only fails with certain locales, e.g. LC_NUMERIC=de_DE.
I don’t think it’s important to set a locale in our test runner,
(which locales are available is very system-dependent),
as I am personally regularly testing with LC_NUMERIC=de_DE ;)
fixes https://github.com/i3/i3/issues/6391
This fixes issues with display link displays not working on i3 and
should not affect any other features from my testing.
Co-authored-by: FedGuy699 <bytebustersco@gmail.com>
We only added that for people who use doxygen to browse code bases. That
was before the age of LSP support in editors, which does a much better
job of that nowadays.
Distributions like Fedora have for some reason started shipping the full
doxygen-generated HTML, which is many megabytes in size. This was never
our intent, so remove the file to prevent it.
fixes https://github.com/i3/i3/issues/6436
This PR is a pure linting and code cleanup effort with no functional
changes, focusing on improving code quality and consistency.
The bulk of the changes involve:
* Code Formatting: The entire codebase was reformatted after updating
our `clang-format` version.
* Compiler Warnings: Addressed `-Wsuggest-attribute` warnings from GCC
by applying `pure`, `const`, and `format` attributes where appropriate.
This helps the compiler with optimizations and bug detection.
* Code Modernization:
* Variable declarations were moved closer to their first use or into
tighter scopes.
* `memset` calls were replaced with C99 zero-initializers (`= {0}`).
* Redundant `struct` keywords, unnecessary type casts, and some
superfluous `return` statements were removed.
* CI Adjustments: The GitHub Actions workflow was updated to correctly
apply compiler flags for both GCC and Clang.
The command and config parsers both used a similar stack implementation
for handling tokens. This resulted in duplicated code.
This commit extracts the common stack implementation (push/get/clear
functions for strings and longs) into a new `parser_util` module.
This resolves a long standing TODO comment.
exec* calls return when an error occurs, this is unexpected but would
still leave the forked process in a broken state. This commit fixes that
by ensuring they are followed by an immediate exit.
In theory, if `/proc/sys/kernel/core_pattern` is 1024 or more bytes, the
null character terminating the buffer can be overwritten.
Note: Found with [bugfinder](https://github.com/stanek-michal/bugfinder)
Before the xcb_randr_get_crtc_info() call fails, `new` has been already
added to `outputs with `TAILQ_INSERT_TAIL(&outputs, new, outputs);`.
Note: Found with [bugfinder](https://github.com/stanek-michal/bugfinder)