3232 Commits

Author SHA1 Message Date
6f38bb6d5d use setlocale(3) (NetBSD lacks uselocale(3))
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
2026-02-06 08:20:11 +01:00
49a2d7a71e Fix ctype(3) function arguments.
Valid are unsigned char and EOF; add cast to make sure we're in the
allowed range.
2026-02-06 08:20:06 +01:00
d63093254b cmd_floating: Fix crash when running empty workspace (#6563)
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
2026-02-06 08:19:13 +01:00
5446ea33ef fix switching to/restoring from LC_NUMERIC (#6544)
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
2025-12-13 08:27:00 +01:00
b1e99d8ff0 Chore: Code cleanup and style improvements (#6516)
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.
2025-11-07 09:49:03 +00:00
d674090f96 commands_parser.c: Make re-entrant (#6523)
Refactor to work with various for_window matching related issues

Depends on https://github.com/i3/i3/pull/6514
Related to https://github.com/i3/i3/issues/3588#issuecomment-544186208
Related to https://github.com/i3/i3/issues/4346
Related to https://github.com/i3/i3/issues/6037
Reverts commit 1cc2548027 / #6509
2025-11-07 08:18:36 +01:00
e035d0c658 Refactor: Extract parser stack implementation to parser_util (#6514)
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.
2025-11-05 22:56:49 +01:00
14a84076aa commands: Simplify criteria matching by iterating over all_cons (#6515)
This avoids copying the list of all windows for each command.
2025-10-31 09:50:32 +01:00
c7344095ec Fix leak sanitizer memleaks (#6520)
```sh
export LSAN_OPTIONS=suppressions=lsan.supp
echo leak:libxcb.so >suppressions=lsan.supp
```

Before:
```sh
rg -l LeakSanitizer latest/i3-log-for-*
latest/i3-log-for-308-focus_wrapping.t
latest/i3-log-for-313-include.t
latest/i3-log-for-316-drag-container.t
latest/i3-log-for-525-i3bar-mouse-bindings.t
latest/i3-log-for-529-net-wm-desktop.t
latest/i3-log-for-533-randr15.t
latest/i3-log-for-538-i3bar-primary-output.t
```

After:
```sh
rg -l LeakSanitizer latest/i3-log-for-*
```

Closes: #4087
2025-10-31 07:38:41 +01:00
683c4f777e Ensure execl is followed by exit (#6510)
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.
2025-10-13 08:58:13 +02:00
5c321cc582 main: debug build: Avoid buffer over-read and simplify (#6507)
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)
2025-10-08 17:49:16 +02:00
45bfae0fc8 assignments: Avoid crash when using for_window reload (#6508)
Note: Found with [bugfinder](https://github.com/stanek-michal/bugfinder)
2025-10-07 17:36:09 +02:00
0d47ec22a9 randr: Avoid use-after-free in RandR <= 1.4 (#6506)
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)
2025-10-07 17:34:57 +02:00
389cf064e6 randr: Fix memleak (#6505)
`sasprintf` always allocates `oname` but it is only conditionally freed.

Note: Found with [bugfinder](https://github.com/stanek-michal/bugfinder)
2025-10-07 17:33:07 +02:00
b3329fbb02 tiling_drag: Fix crash when performing tree_move (#6503)
tree_move calls tree_flatten which can destroy redundant containers.

An example reproduction would be V[H[a V[b]]] where V[b] is focused
(parent of b) and a is moved away using the DT_PARENT target.

Note: Found with [bugfinder](https://github.com/stanek-michal/bugfinder)
2025-10-07 17:32:15 +02:00
e8e063cf00 Fix AdressSanitizer failures in tests (#6502)
Example in
https://github.com/i3/i3/actions/runs/18260895234/job/51988635887?pr=6502
`i3-log-for-124-move.t`:
```
../libi3/font.c:332:9: runtime error: signed integer overflow: 2147483641 + 11 cannot be represented in type 'int'
    #0 0x5611ce962d65 in draw_text_xcb ../libi3/font.c:332
    #1 0x5611ce962d65 in draw_text ../libi3/font.c:376
    #2 0x5611ce95de20 in draw_util_text ../libi3/draw_util.c:219
    #3 0x5611ce947e7a in x_draw_decoration ../src/x.c:751
    #4 0x5611ce94f93a in x_push_node ../src/x.c:1097
    #5 0x5611ce94e9d8 in x_push_node ../src/x.c:1204
    #6 0x5611ce94e9d8 in x_push_node ../src/x.c:1204
    #7 0x5611ce94e9d8 in x_push_node ../src/x.c:1204
    #8 0x5611ce952e9b in x_push_changes ../src/x.c:1373
    #9 0x5611ce922d1f in tree_render ../src/tree.c:468
    #10 0x5611ce8d1bbb in handle_run_command ../src/ipc.c:220
    #11 0x5611ce8c87fe in ipc_receive_message ../src/ipc.c:1481
    #12 0x7effc262b64a in ev_invoke_pending (/lib/x86_64-linux-gnu/libev.so.4+0x564a) (BuildId: cfcffb10ff16734dcc7d31d002a90940abff0323)
    #13 0x7effc262f22e in ev_run (/lib/x86_64-linux-gnu/libev.so.4+0x922e) (BuildId: cfcffb10ff16734dcc7d31d002a90940abff0323)
    #14 0x5611ce809d48 in ev_loop /usr/include/ev.h:841
    #15 0x5611ce809d48 in main ../src/main.c:1229
    #16 0x7effc1e41ca7  (/lib/x86_64-linux-gnu/libc.so.6+0x29ca7) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
    #17 0x7effc1e41d64 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29d64) (BuildId: def5460e3cee00bfee25b429c97bcc4853e5b3a8)
    #18 0x5611ce80e770 in _start (/usr/src/i3/build/i3+0x230770) (BuildId: 181abde9a3dd28a8a4be68b90b9b710c8e280633)

SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../libi3/font.c:332:9 
```

Unrelated but I fixed the build fails in `next` because of a
false-positive:
```
In file included from ../include/all.h:40,
                 from ../src/commands.c:10:
../src/commands.c: In function ‘cmd_floating’:
../include/log.h:30:33: error: ‘%s’ directive argument is null [-Werror=format-overflow=]
   30 | #define DLOG(fmt, ...) debuglog("%s:%s:%d - " fmt, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
      |                                 ^~~~~~~~~~~~~
../src/commands.c:1193:13: note: in expansion of macro ‘DLOG’
 1193 |             DLOG("should switch mode to %s\n", floating_mode);
      |             ^~~~
cc1: all warnings being treated as errors
ninja: build stopped: subcommand failed.
```
2025-10-06 08:09:17 +02:00
cfa4cf16be Set _NET_FRAME_EXTENTS according to the actual decoration size (#5944)
Inspired by #5384, but instead of just using the border width, this PR
reports the actual frame extents for the window, which may also include
the title bar (for floating windows and tiled windows in plain split
containers, but not for tiled windows in stacked/tabbed containers).

The existing `con_border_style_rect()` function should already handle
all configuration options which can affect the decoration sizes (if it
does not, that would also show up in other places); its result just
needs to be converted into the format used by the `_NET_FRAME_EXTENTS`
property.

This PR fixes #4292 probably in the best way possible (the reported
`_NET_FRAME_EXTENTS` values should always match the actual sizes of
window frame elements which are actually drawn into the X11 frame window
into which the client window is reparented). The only really problematic
case is with the stacked/tabbed containers, for which the title bar is
actually drawn into a completely separate window, therefore the title
bar size cannot be reported in `_NET_FRAME_EXTENTS` (actually I tried to
calculate the size of those decorations and add it to the top decoration
size, but that did not change the behavior of `picom`).

<details><summary>Large screenshots here (3840×2160)</summary>

Example of configuration with `hide_edge_borders smart` — a single
window does not have borders, so only the top frame size is non-zero:

![2024-03-09_21-41](https://github.com/i3/i3/assets/616082/d2f41206-89f8-465f-ba25-1f51075ba680)

but multiple windows have borders:

![2024-03-09_21-44](https://github.com/i3/i3/assets/616082/db7469e6-50eb-4687-83fd-88481691b361)

Changing border width works too (although with `border normal 8` you can
see that the top border overlaps the title text, because on the i3 side
that border does not really exists, and `picom` just draws it over; also
the pixel sizes reported by `xprop` and `xwininfo` are not identical to
what is specified in i3, because I use 168 dpi on this system, therefore
4 px in the i3 config = 7 dpx):

![2024-03-09_21-48](https://github.com/i3/i3/assets/616082/7f64d217-3218-4d03-ba15-3fe33e6161d1)

Handling of tabbed containers is less perfect though. Here is a single
tabbed container with `hide_edge_borders smart`, so it does not really
have a border — note that all frame extents are zero, and the titlebar
is rounded separately (although it could easily be excluded from
rounding, that does not really help much):

![2024-03-09_22-02](https://github.com/i3/i3/assets/616082/c6ea1106-b1d7-43b8-8354-bc6fbf45d87a)

Once the border actually appears, you may notice that the top part of
the `picom` border actually gets drawn over the top part of the window,
partially obscuring the top line in this terminal (`picom` does not mind
that the top frame size is reported as 0):

![2024-03-09_22-04](https://github.com/i3/i3/assets/616082/eb80fc5c-fa52-43f4-857e-94dc713221bf)

Some examples of floating windows (no major problems there):

![2024-03-09_22-09](https://github.com/i3/i3/assets/616082/3336c1cb-ee48-46ae-ab89-061be46bdb31)

Options like `hide_edge_borders both` work too when gaps are removed
(although the resulting behavior with `picom` is probably not very
useful — the rounded border gets drawn only if all of the left, bottom
and right borders are present):

![2024-03-09_22-15](https://github.com/i3/i3/assets/616082/9961db74-7c49-43f0-a90f-e9ab81474038)

The same with `border pixel 8` (note that windows with only the top
border hidden still get the rounded border treatment by `picom`, but the
border overlaps the top part of the window):

![2024-03-09_22-21](https://github.com/i3/i3/assets/616082/dd0a0fc6-701d-4e01-ba96-f3eb5131c95b)

</details>

---------

Signed-off-by: Sergey Vlasov <sigprof@gmail.com>
Co-authored-by: Orestis Floros <orestisflo@gmail.com>
2025-04-21 23:26:17 +02:00
44b67d1126 Fix typos via codespell (#6415)
There are some typos in the documentation, messages, etc.
Fix them via codespell.
2025-03-21 12:48:29 +00:00
4661e74b5e Fix: remove "dynamic" TWM (#6193)
related to https://github.com/i3/i3.github.io/issues/137
2024-08-05 18:23:55 +02:00
d05eed3c01 Consider fullscreen windows maximized (#6153)
Fixes #6148
2024-07-12 09:17:25 +02:00
05feaecf8a Remove v3 to v4 automatic migration logic (#6144)
Closes https://github.com/i3/i3/issues/6131
2024-07-09 18:03:57 +00:00
5413c15e97 Fix crash when reloading config with invalid criteria (#6142)
Came up in https://github.com/i3/i3/discussions/6141
2024-07-09 17:41:11 +02:00
be840af45c tiling_drag: Allow swapping containers (#6084)
This was originally mentioned in #3085 but left for a future PR.

One of the noticeable limitations is that pressing the modifier while
the drag is already initiated, will not swap the containers but instead
cancel the drag. This is because of how `drag_pointer()` is written and
would be quite an involved case to handle it.
2024-07-04 21:44:41 +02:00
1ee963ede9 Fix crash with focus output and scratchpad (#6079)
The crash was brought up in a comment in
https://github.com/i3/i3/discussions/6076#discussioncomment-9536969

The cause is that the command criteria are matching a window in the
scratchpad. In that case, the assertion in get_output_for_con() fails.
That happens because there is no `Output` for the `Con` output of a
scratchpad window.

I've decided to *not* remove the offending assertion but rather rely on
the caller not using the function with internal containers. My reasoning
is:
1. If get_output_for_con can return NULL then the caller will either
segfault (which is worse) or needs to check the return for NULL.
2. The case where the return can be NULL is already known, it happens
for internal containers.
3. Therefore, the caller should already prevent the situation with a
call to con_is_internal(). Thus, the `assert`ion can remain.

There is also the potential fix of con_get_workspace returning some
arbitrary output (e.g. first in the list or currently focused one)
instead of NULL. This can lead to more tricky to catch bugs.
2024-06-03 17:00:47 +02:00
1993b7e318 Add popup_during_fullscreen all option 2024-05-20 21:26:27 +02:00
9a69c1eecf Fix size_t format specifiers on 32 bit systems (#6065)
This fixes the following warnings on 32 bit systems

```
[60/108] Compiling C object i3.p/src_regex.c.o
In file included from ../include/all.h:40,
                 from ../src/regex.c:10:
../src/regex.c: In function ‘regex_new’:
../include/log.h:29:33: warning: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘size_t’ {aka ‘unsigned int’} [-Wformat=]
   29 | #define ELOG(fmt, ...) errorlog("ERROR: " fmt, ##__VA_ARGS__)
      |                                 ^~~~~~~~~
../src/regex.c:35:9: note: in expansion of macro ‘ELOG’
   35 |         ELOG("PCRE regular expression compilation failed at %lu: %s\n",
      |         ^~~~
[93/108] Compiling C object i3-input.p/i3-input_main.c.o
../i3-input/main.c: In function ‘finish_input’:
../i3-input/main.c:173:29: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘size_t’ {aka ‘unsigned int’} [-Wformat=]
  173 |     printf("occurrences = %ld\n", cnt);
      |                           ~~^     ~~~
      |                             |     |
      |                             |     size_t {aka unsigned int}
      |                             long int
      |                           %d 
```
2024-05-20 13:13:26 +02:00
caf5b32d5c Reap zombie children on i3 start (#5909)
One case when this might be useful is when i3 is restarted and there are
children that terminate after the previous i3 instance shut down but
before the new one set things up.

Fixes #5756
2024-05-17 21:49:54 +02:00
854696cfb5 Remove pledge() support for OpenBSD (#6048)
While this initially worked fine, at some point these patches broke
because libcairo started calling shmget(2) - a syscall not covered by
any pledge promise - and a common pitfall when using pledge with
graphics-oriented applications.

Various attempts were made to fix them, but at some time they were
simply disabled in the OpenBSD port:


a4a9f41dd7
5a03c386ba

This seems pointless and creates needless friction both for the i3 team
who was willing to carry ugly code and for the OpenBSD ports maintainers
who had to disable that code again.

Let's abandon this experiment.
2024-05-17 21:41:45 +02:00
1597ec27ee add WINDOW_TYPE_NOTIFICATION to floating list (#6017)
as explained in this discussion:
https://github.com/i3/i3/discussions/5966#discussioncomment-8961295
2024-05-16 07:50:06 +00:00
e020701df1 errorlog: Check errorfile exists (#6028)
Fixes #6027
2024-04-30 13:39:54 +02:00
47cab33aa8 Fix missing SIGUSR2 posix signal handling (#5960)
Since there is no separate error handling the `SIGUSR2` signal is
registered to get the write return code after exiting the program.

Fixes #5958

---------

Signed-off-by: Andre Werner <andre.werner@systec-electronic.com>
2024-03-20 12:58:56 +00:00
910e58585f Support multiple _NET_WM_STATE changes in one ClientMessage (#5910) 2024-02-12 08:40:39 +01:00
6a530de220 Create new workspaces to the right of existing ones with the same number
i.e. creating workspaces named "1", "2:a", "2:b", "3" should result in
that same order rather than "1", "2:b", "2:a", "3".
2024-02-06 20:28:20 +01:00
0639167185 Don't skip identically numbered workspaces when moving to next/prev (#4578)
eg if you have workspaces: { 1, 2:a, 2:b, 3 } and are on workspace 1,
then 'workspace next' should traverse 1 -> 2:a -> 2:b -> 3 -> 1 instead
of 1 -> 2:a -> 3 -> 1.

Fixes #4452
2024-02-06 20:07:21 +01:00
f8befe378a Avoid creating redundant containers when switching between tabbed/stacked and split layouts (#5469)
Fixes #3001
2024-01-31 08:14:32 +01:00
230147c815 smart_borders: Deprecate option (#5889)
This had pretty much identical behaviour to hide_edge_borders which made
it confusing. The `hide_edge_borders smart_no_gaps` implementation has an extra check
which fixes #5406.
2024-01-30 08:53:32 +01:00
f169624560 clang-format: enable InsertBraces (#5882)
Enforces a rule that we have followed for years now. Yes, the diff is
quite big but we get it over with once and we prevent having to nit-pick
future PRs.
2024-01-27 11:37:05 +01:00
5fdfb14530 con_is_maximized: Fix case where parent is workspace (#5880)
See added test for simple example.
2024-01-26 08:51:28 +01:00
b660d6a902 Add support for _NET_WM_STATE_MAXIMIZED_{HORZ, VERT} (#5840)
If a window occupies the entirety of its workspace vertically and/or horizontally, pass it the _NET_WM_STATE_MAXIMIZED_{HORZ, VERT} atoms. This helps applications like Google Chrome draw the tab bar correctly and handle tab clicks correctly (see https://crbug.com/1495853).

This change is based on work from @yshui in #2380.
2024-01-22 20:34:40 +01:00
69f68dcd74 focus workspace: consider workspace_auto_back_and_forth (#5754)
Additionally, adds some tests for the command.

Fixes #5744
2023-11-05 11:08:44 +01:00
b42dc21068 bindings: Do not grab pointer when executing bindings (#5755)
Grabing the pointer produces a `GrabFrozen` error in applications that
are run from key bindings. Since we don't need the pointer in such
cases, we can change the call to use ASYNC. This seems to be a
historical leftover.

I've tested locally that these still work:
- bindsym $mod+x ...
- bindsym --release $mod+x ...
- bindsym $mod+button1 ...
- bindsym --release $mod+button1 ...
- bindsym --release $mod+x exec program that grabs the keyboard
  now works (see original issue)

Even in the main branch, I actually couldn't get `import` and `xdotool`
to fail with the pointer being frozen, potentially because these
programs wait a bit for the pointer to be unfrozen like i3lock does.

This patch came up in
https://github.com/i3/i3/issues/5735#issuecomment-1781321011

I wonder why the pointer is actually grabbed.

The argument I change in `xcb_grab_key` there, is `pointer_mode`, from
https://www.x.org/releases/X11R7.7/doc/man/man3/xcb_grab_key.3.xhtml:
```
pointer_mode

One of the following values:
XCB_GRAB_MODE_SYNC

The state of the keyboard appears to freeze: No further keyboard events are generated by the server until the grabbing client issues a releasing AllowEvents request or until the keyboard grab is released.

XCB_GRAB_MODE_ASYNC

Keyboard event processing continues normally.
```

I traced via `git blame` the usage of `xcb_grab_key` throughout 14 years
of i3 development and it seems that `pointer_mode` was always set to
`XCB_GRAB_MODE_SYNC`, going all the way back to
b664456706.

Fixes #5735
2023-11-05 11:04:04 +01:00
5489db6bc8 motif hints: respect maximum border style in append_layout 2023-09-21 18:55:01 +02:00
f4959d5da4 Update to clang-format-15 2023-09-21 18:55:01 +02:00
908c86544b remanage_window: Refactor to make clearer when a swallowing happens 2023-09-06 17:24:53 +02:00
82b9821204 Remanage window after urgency flag change
Fixes #5658
2023-09-06 17:24:53 +02:00
c6f62f4695 Fix crashes when using machine criterion (#5650)
Fixes #5616
2023-09-03 19:32:42 +02:00
d6e2a38b5c Share graphics context globally (#4376)
Instead of creating a graphics context for every surface_t, this commit
adds a cache that allows to "remember" up to two GCs. Thus, the code
uses less GCs. When a GC from the cache can be used, this also gets rid
of a round-trip to the X11 server. Both of these are tiny, insignificant
savings, but so what?

Since GCs are per-depth, this code needs access to get_visual_depth().
To avoid a code duplication, this function is moved to libi3.

Fixes: https://github.com/i3/i3/issues/3478
Signed-off-by: Uli Schlachter <psychon@znc.in>
2023-07-22 10:24:13 +02:00
6fe98f7847 Remove focus workaround 2023-07-21 13:52:44 +02:00
9947890472 Fix gcc false-positive warning 2023-07-15 21:27:11 +02:00
e6b41172da Regrab buttons on mode change (#5554)
Unfortunately, grabbing / ungrabbing doesn't seem to work correctly in
xvfb so we can't really test this.

I also fixed the deduplication code in bindings_get_buttons_to_grab().
2023-06-30 08:57:19 +02:00