Rather than maintain copies of the entire focus stack, this PR
transactionises the focus by introducing two new properties to the
container state and using those when rendering.
* `bool focused` means this container has actual focus. Only one
container should have this equalling true in its current state.
* `struct sway_container *focus_inactive_child` points to the immediate
child that was most recently focused (eg. for tabbed and stacked
containers).
This PR changes the way we handle transactions to a more simple method.
The new method is to mark containers as dirty from low level code
(eg. arranging, or container_destroy, and eventually seat_set_focus),
then call transaction_commit_dirty which picks up those containers and
runs them through a transaction. The old methods of using transactions
(arrange_and_commit, or creating one manually) are now no longer
possible.
The highest-level code (execute_command and view implementation
handlers) will call transaction_commit_dirty, so most other code just
needs to set containers as dirty. This is done by arranging, but can
also be done by calling container_set_dirty.
When you spawn a process with the exec command, sway now notes the
workspace you had focused and the pid of the child process, then assigns
that workspace to the child when its window appears.
Some of this is carried over from sway 0.15, but with some major
refactoring and centralization of state.
Rather than allocate a structure and expect callers to free it, take a
pointer to an existing struct as an argument.
This function is no longer called anywhere though.
* The arrange_foo functions are now replaced with arrange_and_commit, or
with manually created transactions and arrange_windows x2.
* The arrange functions are now only called from the highest level
functions rather than from both high level and low level functions.
* Due to the previous point, view_set_fullscreen_raw and
view_set_fullscreen are both merged into one function again.
* Floating and fullscreen are now working with transactions.
* Add and use lenient_strcat and lenient_strncat functions
* Rename `concatenate_child_titles` function as that's no longer what it
does
* Rename `container_notify_child_title_changed` because we only need to
notify that the tree structure has changed, not titles
* Don't notify parents when a child changes its title
* Update ancestor titles when changing a container's layout
* Eg. create nested tabs and change the inner container to stacking
* No need to store tree presentation in both container->name and
formatted_title
The criteria struct now uses properties for each token type rather than
the list_t list of tokens. The reason for this is that different token
types have different data types: pcre, string and number to name a few.
This solution should be more flexible moving forward. A bonus of this is
that criteria is now easier to understand when looking at the struct
definition.
The criteria parser has been rewritten because the previous one didn't
support valueless pairs (eg. [class="foo" floating]).
Criteria now has types. Types at the moment are CT_COMMAND,
CT_ASSIGN_WORKSPACE and CT_ASSIGN_OUTPUT. i3 uses types as well.
Previously the assign command was creating a criteria with 'move to
workspace <name>' as its command, but this caused the window to appear
briefly on the focused workspace before being moved to the assigned
workspace. It now creates the view directly in the assigned workspace.
Each view will only execute a given criteria once. This is achieved by
storing a list of executed criteria in the view. This is the same
strategy used by i3.
Escaping now works properly. Previously you could do things like
[class="Fire\"fox"] and the stored value would be 'Fire\"fox', but it
should be (and now is) 'Fire"fox'.
The public functions in criteria.c are now all prefixed with criteria_.
Xwayland views now listen to the set_title, set_class and
set_window_type events and criteria will be run when these happen. XDG
shell has none of these events so it continues to update the title in
handle_commit.
Each view type's get_prop function has been split into get_string_prop
and get_int_prop because some properties like the X11 window ID and
window type are numeric.
The following new criteria tokens are now supported:
* id (X11 window ID)
* instance
* tiling
* workspace
This implements the title_format command, with a new placeholder %shell
which gets substituted with the view type (xwayland, xdg_shell_v6 or
wl_shell).
Example config:
for_window [title=".*"] title_format %title (class=%class instance=%instance shell=%shell)
Implements rendering of borders. Title text is still to do.
Implements the following configuration directives:
* client.focused
* client.focused_inactive
* client.unfocused
* client.urgent
* border
* default_border
Replaces arrange_windows() with arrange_root(), arrange_output(),
arrange_workspace() and arrange_children_of().
Also makes fullscreen views save and restore their dimensions, which
allows it to preserve any custom resize and is also a requirement for
floating views once they are implemented.
The exact semantics of this command are complicated. I'll describe each
test scenario as s-expressions. Everything assumes L_HORIZ if not
specified, but if you rotate everything 90 degrees the same test cases
hold.
```
(container (view a) (view b focus) (view c))
-> move left
(container (view b focus) (view a) (view c))
(container (view a) (view b focus) (view c))
-> move right
(container (view a) (view c) (view b focus))
(container L_VERT (view a))
(container L_HORIZ
(view b) (view c focus))
-> move up
(container L_VERT
(view a) (view c focus))
(container L_HORIZ (view b))
(workspace
(view a) (view b focus) (view c))
-> move up
(workspace [split direction flipped]
(view b focus)
(container (view a) (view c)))
(workspace
(view a) (view b focus) (view c))
-> move down
(workspace [split direction flipped]
(container (view a) (view c))
(view b focus)))
Note: outputs use wlr_output_layout instead of assuming that i+/-1 is
the next output in the move direction.
(root
(output X11-1
(workspace 1))
(output X11-2
(workspace 1 (view a focus) (view b)))))
-> move left
(root
(output X11-1
(workspace 1 (view a focus)))
(output X11-2
(workspace 1 (view b)))))
(root
(output X11-1
(workspace 1
(container (view a) (view b)))
(output X11-2
(workspace 1 (view c focus)))))
-> move left
(root
(output X11-1
(workspace 1
(container (view a) (view b))
(view c focus)))
(output X11-2
(workspace 1)))
```