Using the wrong X11 connection breaks the libev event handling model:
xcb_flush() must be called immediately before handing control to libev.
Before this fix:
1. xcb_prepare_cb would read and flush conn
2. restore_xcb_prepare_cb would read and flush restore_conn,
BUT also inadvertantly call xcb_flush(conn), resulting in new
events being filled into the XCB event queue
3. libev waits for new events
4. after 1 minute, libev times out and the events are processed
Diagnosed using strace on testcases/complete-run.pl.
related to commit 0d8b6714e3
related to #3510
Basic idea: if the window has a shape, set the parent container shape as
the union of the window shape and the shape of the frame borders.
Co-authored-by: Uli Schlachter <psychon@znc.in>
- ICCCM says: > If a base size is not provided, the minimum size is to
be used in its place and vice versa.
i3 didn't obey the "vice versa" part. Min size and base size are both
saved without replacements in window_update_normal_hints,
floating_check_size makes the needed replacements if either was not
provided.
- Aspect ratio is now saved correctly in manage_window because
window_update_normal_hints is called.
- i3 didn't save the aspect ratio if the window conformed the given
aspect ratio range when handle_normal_hints was called. If the window
was resized to a size outside of the given bounds, i3 didn't correct it.
- Aspect ratio now affects only tiling windows, like the rest of the
normal size hints
- The aspect ratio calculation is now done without a loop
A real life example of how these changes affect the workflow:
An mpv window, when playing a video, sets its min == max aspect ratio
during mapping. i3 ignored these hints. When resized, the window's
aspect ratio was not preserved. With this commit, resizing floating mpv
windows will always preserve the aspect ratio.
Previously, it first calculated one of the containers' next percentage, and then subtracted the previous percentage to find the actual change.
Now it directly calculates the change, and subtracts and adds the change to the two affected containers.
Added util function con_rect_size_in_orientation.
Removed px_resize_to_percent; inlined, using con_rect_size_in_orientation.
Also, prematurely return when pixel diff is 0, as no action is necessary.
This is related to [this issue on i3-gaps](https://github.com/Airblader/i3/issues/247).
Example problematic layout:
{
"layout": "splith",
"marks": ["H1"],
"nodes": [
{
"swallows": [
{
"class": "^a$"
}
]
}
]
}
Since the marks were added to the json_node during end_map, the
container that ended up getting the "H1" mark was the child instead of
the parent.
This fixes a regression introduced in 6d983b5. Consider 2 outputs:
fake-0: workspace '1'
fake-1: workspaces '2','3'
Workspace 1 focused, workspace 2 visible.
Open a floating window in 1 and move it to 3. Now, the floating window
appears in workspace 2 and disappears once focus is switched to
that workspace.
Instead of focusing 'old_focus' which might refer to a container in a
different output, we should restore focus by focusing the previously
focused workspace of the output.
Controls the window titles alignment in title bars. Possible values are:
- left
- center
- right
Co-authored-by: Orestis Floros <orestisf1993@gmail.com>
- Made title_align a config directive instead of a command. Helps with
some tree_render() issues we had.
- Made title_max_width the same for all 3 cases.
- Modified title offset calculations and added explanations for each
case.
- Append title_padding to mark_width if a mark exists.
Fixes#1750
Benefits are that we don't open a fake container and don't call many
complicated functions that can lead to redraws (x_push_changes calls) as
discussed in #2954.
Fixes#2810:
Windows exchange floating mode & window rects.
Swap will still not work with CT_FLOATING_CONs but this doesn't make
much sense.
Fixes#3280:
The behaviour is not very user friendly but swap behaves exactly as it
should. The rest is a tree_flatten issue. Attached pictures in #2954.
- Use workspace_show that correctly updates _NET_CURRENT_DESKTOP, warps
mouse.
- Use TAILQ_INSERT_TAIL only for focus_head. Focus order is not related
to direction.
- Call con_focus only if con was focused before. See testcase for
directional move with command criteria.
- Correct first call of move_to_output_directed in tree_move which
didn't call ipc_send_window_event("move", con) and
ewmh_update_wm_desktop().
- Don't produce events when the move doesn't happen. Correct
276-ipc-window-move.t as well.
For compatiblity reasons, Wine will request iconic state and cannot
ensure that the WM has agreed on it; immediately revert to normal to
avoid being stuck in a paused state.
con_detach and con_attach modify the focus stack.
This will make sure that the currently focused workspace will remain
focused after disabling an output.
This fixes a crash produced with the following config:
# i3 config file (v4)
workspace 1 output $screen1
workspace 2 output $screen2
exec --no-startup-id "i3-msg workspace 1, open && i3-msg workspace 2 && xrandr --output $screen2 --off && xrandr --output $screen1 --auto --output $screen2 --auto --right-of $screen1 "
Which results in:
ERROR: AddressSanitizer: heap-use-after-free on address …
READ of size 8 at 0x614000001f48 thread T0
#0 0x5563df6e73a8 in init_ws_for_output i3/src/randr.c:468
#1 0x5563df6ef3b4 in randr_query_outputs i3/src/randr.c:940
#2 0x5563df68dbe1 in handle_screen_change i3/src/handlers.c:450
… is located 264 bytes inside of 448-byte region …
freed by thread T0 here:
#1 0x5563df634b0a in con_free i3/src/con.c:96
#2 0x5563df7151e6 in tree_close_internal i3/src/tree.c:344
#3 0x5563df7280fe in workspace_show i3/src/workspace.c:499
#4 0x5563df6e7315 in init_ws_for_output i3/src/randr.c:457
#5 0x5563df6ef3b4 in randr_query_outputs i3/src/randr.c:940
#6 0x5563df68dbe1 in handle_screen_change i3/src/handlers.c:450
Which is similar to #3228, #3248.
- Improve / add various error messages.
- Replace all `LOG(…); ysuccess(false);` with `yerror(…);`.
- switch_mode: Remove redundant "ERROR:" ELOG string.
- cmd_move_con_to_workspace*: Make sure that we don't try to move an
empty workspace to another workspace. This can be problematic when we
match a workspace using command criteria (eg marks) and the target is a
non-existing workspace. We create the new workspace but since nothing is
moved there, we are left with an empty workspace. See added testcase.
Fixes#3156.
I couldn't reproduce the problem in a "natural" way so I cheated:
1. Start i3 with gdb
2. Set breakpoing on tree_restore
3. Run, open window, i3-msg restart
5. Open the file in *path with a hex editor
6. Edit the "name" field of the window and insert bytes that are not
valid UTF8
7. Continue
After parsing fails, all nodes including croot are incomplete, meaning
they have to be deleted. We can't recover in any reasonable way so we
have to allow non-UTF8 characters to avoid this situation altogether.
Introduces resize_neighboring_cons in resize.c which is also used by
resize_graphical_handler.
Co-authored-by: Andrew Laucius <andrewla@gmail.com>
Authored original code and tests in #3240. I rewrote most of the
resizing code and fixed the failing tests.
These are the changes that clang-format 6.0.1 makes to the codebase that
clang-format-3.8 doesn't change back.
Useful for those that use a more recent version of clang-format in their
local machines.
This commit will also fix the following bugs:
1. click.c: Users could drag global fullscreen floating containers.
2. render.c: Floating containers would get rendered with a global fullscreen container in another
workspace.
The first issue is that there seems to be a typo: fullscreen->window
should have been child->window. The corrected check is redundant since
the while loop checks if the transient_con has a window.
The second issue is that popup_during_fullscreen is never checked even
though the behaviour should be exclusive to the "smart" option.
A race condition is possible. For example, if we first receive a
XCB_MOTION_NOTIFY event and then, while drain_drag_events is still
running, a XCB_BUTTON_RELEASE event the first event is never handled
because we return.
This fixes the flakiness of the tests in #3085.
Right now tree_render() is called twice on DRAG_REVERT since
floating_reposition calls it.
Also, on DRAG_REVERT the scratchpad state shouldn't change since the
user canceled the action.
This change only affects clients that are subscribed to events, which
should be the main cause of our problems.
In the common case (no buffered data) the behaviour doesn't change at
all: the message is sent directly, no ev_io / ev_timeout callback is
enabled. Once a write to a client's socket is not completed fully
(returns with EAGAIN error), we put the message in the tail of a queue
and init an ev_io callback and a corresponding timer. If the timer is
triggered first, the socket is closed and the client connection is
removed. If the socket becomes writeable before the timeout we either
reset the timer if we couldn't push all the buffered data or completely
remove it if everything was pushed.
We could also replace ipc_send_message() for all client connections in
i3, not just those subscribed to events.
Furthermore, we could limit the amount of messages stored and increase
the timeout (or use multiple timeouts): eg it's ok if a client is not
reading for 10 seconds and we are only holding 5KB of messages for them
but it is not ok if they are inactive for 5 seconds and we have 30MB of
messages held.
Closes#2999Closes#2539
This commit makes multiple changes in tree_close_internal. I didn't
split them because they are not completely independent.
- Remove force_set_focus parameter
This parameter was always set to `false` throughout the code base except
for one case where it was set to `(con == focused)`, when killing a
floating con's parent (the one with type CT_FLOATING_CON). But this case
is not needed anymore since the special handling of CT_FLOATING_CONs in
con_next_focused was removed in #2941.
- Assume that con_next_focused does not returned a container of type
CT_DOCKAREA. This is reasonable since con_next_focused uses the
focus_head stack and has special handling of CT_DOCKAREA containers.
- Remove is_mapped
This variable was only used in the if block towards the end of
tree_close_internal. Ignoring the, now removed, dockarea code and the
use of force_set_focus this block performed only one useful action:
focus the `next` container when `con == focused`. `con == focused` was a
necessary and sufficient condition for the con_activate call:
if `con != focused` we could reach the inner if blocks because of the
other conditions but would never focus another container. If `con ==
focused` then all other conditions would be irrelevant.
- Remove special handling of floating containers
Since the `next` focused container is calculated through the parent for
floating containers, I moved this code to con_next_focused.
Also, because of the removal of force_set_focus, it appears that we can
call con_on_remove_child for floating containers as well.
This was introduced in 252db3b8c (#3245). That commit moved the
con_activate line inside the loop, meaning it wouldn't always be called.
When the mouse moved after a rename with focus_follows_mouse enabled,
check_crossing_screen_boundary (src/handlers.c:111) called
con_descend_focused that used the wrong focus order.
I also change con_activate to con_focus since we don't really want to
raise floating containers there.
Fixes#3325
This prohibits the usage of workspaces assigned to other outputs in
create_workspace_on_output.
Eg, with config:
workspace 1 output fake-0
workspace 2 output fake-0
and 2 screens workspace 2 would be used for the second screen even
though it is assigned to the first one.
Also introduces a test for workspace assignments that includes the case
described above and some tests that don't fail in the next branch.
This also replaces code in create_workspace_on_output() that is
theoretically more efficient but:
1. It isn't a huge difference since it depends on the number of outputs,
that shouldn't be high.
2. get_assigned_output will be modified and used for #555, then its
logic should be followed in create_workspace_on_output() too.
Another note for create_workspace_on_output: if assigned is not NULL the
condition (assigned != output->con) should never be false, ie if there
is an assigned output to this name, it isn't the current one. This
happens because the current callers check for assignments before calling
create_workspace_on_output().
https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Detectable_Autorepeat
Detectable autorepeat should only affect --release bindings. Currently,
when a user keeps a key pressed, we get multiple KeyPress and KeyRelease
events. With this change, we still get multiple KeyPress events, which
means that you can still keep a key pressed to repeatedly execute a
normal binding, but only one KeyRelease event when the key is physically
released.
Unfortunately, this change is not currently testable because detectable
autorepeat doesn't seem to work under Xephyr. AwesomeWM experienced the
same problem:
6f2424e901Fixes#3306
X will not allow a window with ParentRelative background to be created
or reparented under a window with mismatching color depth.
Deal with this by destroying the container frame and creating a new one
with the right depth upon swallowing.
Defer destruction of the frame window until after the updated tree has
been rendered to avoid some distracting flickering.
Fixes#3297
fbce834b introduced a bug where scrolling over the decoration while
another container is focused would not focus the tabbed/stacked
container itself, but would instead move focus through the currently
focused container.
When moving a workspace to the current output by way of a rename, if the
current workspace is empty, it will be removed by `workspace_show`.
Attempting to restore focus to this removed workspace causes a crash.
Follow the pattern in workspace.c:996 to only restore the original focus if the
original workspace still exists.
Add a test to ensure that the renamed workspace moves to its appropriate
output and that a crash does not occur.
Fixes#3228
handle_screen_change() and handle_configure_notify() call
randr_query_outputs() where root_output is not initialized because
randr_init() is never called when config.fake_outputs is not NULL.
When we don't modify the focus we aren't risking giving focus to a
container behind the current fullscreen one.
_con_move_to_con can with ignore_focus is called through the swap
command or through con_move_to_workspace for floating containers. This
change shouldn't break the expectations of the callers there.
Fixes issue #3259.
This is enough to fix the crash discussed in #3259 even though the next
commit can fix it independently. This commit is useful because it
generally makes sense to abort the command when the first call to
_con_move_to_con fails.
- 'border toggle' now accepts an optional pixel argument which will be
ignored when switching to BS_NONE.
- 'border pixel' now defaults to 1 pixel instead of 2.
- Calling 'border normal' or 'border pixel' will use the configured
default_border_width if one exists. Also applies to floating windows.
Fix the issue #3227(https://github.com/i3/i3/issues/3227).
1).Make cmd_scratchpad_show() use the information coming from scratchpad_show().
2).Add a test case 298-scratchpad-show.t.
Was used for the removed option 'terminal' and for 'font'. 'font' is no
longer this aggressive and doesn't use the macro.
Killing i3 when an option is missing would be super backwards
incompatible so I doubt we are going to use this ever again.
Was a small typo.
This also has the (positive) side-effect of allowing to move all the
content of a marked workspace next to the target container, see added
tests.
Currently when renaming outputs, an output assignment of "left" will
cause the workspace to move left. Treat this assignment as a proper name
instead (even though it is unlikely an output will be named "left").
Move logic for determining output to move to out of
`workspace_move_to_output`
Add test for ignoring direcionality during rename.
Fixes#3208.
Using 'default:' cases can hide logical errors which would lead to i3
crashes for users. With this change the compiler will print a warning
when a case is not handled. For example, if I add a new value in the
Font.type enum:
../../i3/libi3/font.c: In function ‘draw_text’:
../../i3/libi3/font.c:378:5: warning: enumeration value ‘NEWFONT’ not handled in switch [-Wswitch]
switch (savedFont->type) {
^~~~~~
The current behaviour is buggy in the following layout:
T [ A* V [ B C ] ], where the focus stack in V is B > C.
When the user scrolls down, focus correctly moves to B but if the user
scrolls down again the whole vertical container is focused.
This happens because 'bool scroll_next_possible' is false but
con_activate is called on the tabbed container's sibling - the vertical
container.
Sending the sync command via IPC ensures pending IPC messages are handled by i3
before the sync response is read. This is rarely useful for direct IPC
connections to i3, but becomes useful when synchronizing with i3bar, which might
have pending IPC messages in response to button clicks.
Explanation for the changed test:
After $third is switched to floating, the test moves focus to $second.
So, the parent of $second (the stacked container) is above $third in the
focus stack and it's children ($first, $second) should get focused
before $second. When $second is switched to floating the correct focus
order for the workspace should be $second->parent (floating con is the
parent) > $first->parent (stacked con) > $third.
Fixes#1975
Steps to reproduce:
1. Force the branch to be taken:
diff --git a/src/bindings.c b/src/bindings.c
index fe77bc8f..caa5848c 100644
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -941,7 +941,7 @@ bool load_keymap(void) {
struct xkb_keymap *new_keymap = NULL;
int32_t device_id;
- if (xkb_supported && (device_id = xkb_x11_get_core_keyboard_device_id(conn)) > -1) {
+ if (0) {
if ((new_keymap = xkb_x11_keymap_new_from_device(xkb_context, conn, device_id, 0)) == NULL) {
ELOG("xkb_x11_keymap_new_from_device failed\n");
return false;
2. Run `python2 ./xproperty.py _XKB_RULES_NAMES ''` (from
https://github.com/siemer/xproperty) in the xinitrc
3. Memory sanitizers detect memory leaks.
Note: We don't (and didn't) pass NULL in xkb_keymap_new_from_names() but
an xkb_rule_names structures with NULL fields (fill_rmlvo_from_root only
fills its argument when there are no errors) should be equivalent:
767fa86d42/NEWS (L349-L351)
> The function xkb_keymap_new_from_names() now accepts a NULL value for
the 'names' parameter, instead of failing. This is equivalent to passing
a 'struct xkb_rule_names' with all fields set to NULL.
Fixes#2535.
Seems to be the intention, indicated by this comment (con.c:1307-1309):
/* For split containers, we use the currently focused container within it.
* This allows setting marks on, e.g., tabbed containers which will move
* con to a new tab behind the focused tab. */
Related to #3085.
xkb_state_new uses calloc and may fail in a rare case, which would cause a memory leak.
Note that xkb_state_unref checks if the parameter given is not null (!state) before freeing.
Calls to xkb_state_new have been grouped to remove code duplication.
Signed-off-by: Elouan Martinet <exa@elou.world>
con_next_focused uses con's parent. But since con can be inside an
unfocused container this means that one of it's siblings could become
focused in the current workspace.
The current_ws is shown latter anyway:
if (!ignore_focus) {
workspace_show(current_ws);
...
This also causes the following bug:
- Open a window in an empty workspace
- Switch to another workspace
- seturgent to the first window
- Move another window to the first workspace
- Urgent flag is now reset
This significantly reduces the number of ELOGs while dragging floating
containers. The behaviour is improved since floating containers in the
edge of the screen will still get reassigned to their closest workspace.
For example, consider this setup:
fake-outputs 500x500+0+0,500x500+500+0
Now, open a window in the right output and run:
i3-msg floating enable, move position 0 px 450 px
The window is on the bottom edge of the left workspace but if you run:
i3-msg focus mode_toggle
focus will go to the right workspace since floating_maybe_reassign_ws
didn't change the assigned workspace of the floating container.
This allows the floating container's top left corner to be mapped
outside any output as long as they are contained partially by one. This,
for example, will allow:
mpv --geometry +1+1 video.mp4
For windows mapped to (0, 0) see comment in floating.c:270-273:
/* Some clients (like GIMP’s color picker window) get mapped
* to (0, 0), so we push them to a reasonable position
* (centered over their leader) */
The floating_reassign_ws call is removed since we try to place the new
floating container in the current output:
/* Sanity check: Are the coordinates on the appropriate output? If not, we
* need to change them */
Fixes#1341
_NET_WM_STATE_FOCUSED is set on _NET_WM_STATE to indicate that the
window is focused. It must be set when the window is newly focused and
removed once the window no longer has focus.
> _NET_WM_STATE_FOCUSED indicates whether the window's decorations are
> drawn in an active state. Clients MUST regard it as a read-only hint.
> It cannot be set at map time or changed via a _NET_WM_STATE client
> message.
For example, this is used by GTK applications to show the decoration in
an active or inactive state. This change can be tested by opening a GTK
application (like evince), focusing the window and unfocusing the
window, and observing a change in the window decorations.
Fixes#2273
For command:
move window to [absolute] position X px Y px
if the optional keyword 'absolute' is provided the end result is the
same even though it is implemented differently. Only difference is that
with absolute the floating window can move completely outside of any
output.
This commit removes the 'method' argument and only keeps the sane
implementation.
With example config:
mode "a_mode" {
bindcode 27 --release mode "default"
}
bindsym $mod+r mode "a_mode"
The first time $mod+r is pressed "a_mode" is activated like normal. When
r (bindcode 27) is pressed to exit the mode:
- On the KeyPress event the corresponding bind->release is correctly
marked as B_UPON_KEYRELEASE_IGNORE_MODS.
- On the KeyRelease event the command 'mode "default"' is executed but
bind->release is still B_UPON_KEYRELEASE_IGNORE_MODS since they are only
reset on KeyPress events.
The second time $mod+r is pressed and "a_mode" is activated and when the
r key is released the 'mode "default"' is executed even though the mods
are not matching since bind->release == B_UPON_KEYRELEASE_IGNORE_MODS.
This still doesn't catch 2 cases:
1. When the order is: press $mod -> press r -> release $mod -> release
r. Since 'r' is released without any modifiers the binding matches.
2. With:
mode "resize" {
bindsym --release r mode "default"
}
bindsym r mode "resize"
This is arguably correct: on the KeyPress event we switch to the mode and
on the KeyRelease we switch back.
Before this commit, get_binding() exited on the first match without
marking the rest --release bindings with B_UPON_KEYRELEASE_IGNORE_MODS.
Similarly, once it found a --release binding during a KeyPress event it
would stop searching for a matching key press binding.
Example config, placing the --release line first will trigger the second
problem:
# i3 config file (v4)
bindsym Super_L exec notify-send "press"
# or
# bindcode 133 exec notify-send "press"
bindsym --release Super_L exec notify-send "release"
# or
# bindcode --release 133 exec notify-send "release"
Fixes#2733
From 548d74015c50d7fae14bfb8bb1989acde5fc22ae:
> 1. press $mod, press x, release x, release $mod
> 2. press $mod, press x, release $mod, release x
case (2.) didn't work, now it should be fixed.
When we run 'reload' all the assignments are freed:
e3e09119bf/src/config.c (L99-L109)
Assignments are saved to each window after they are executed:
e3e09119bf/src/assignments.c (L41-L46)
This means that the pointers stored in window->ran_assignments are
invalid (shouldn't be dangerous currently but could lead to a segfault
if the code is modified) after a 'reload'.
Fixes:
- Issue where moving an urgent (unfocused) window resets it's urgency
hint.
- Moving an unfocused container to a new parent should not move it to
the top of the focus stack.