This fixes the following. Create these layouts and run move right:
(Initial layout -> expected result -> actual result)
* `H[S[unfocused focused] unfocused]` ->
`H[S[unfocused] focused unfocused]` ->
`H[H[S[unfocused] focused] unfocused]`
* `H[S[unfocused focused] V[unfocused]]` ->
`H[S[unfocused] V[unfocused focused]]` ->
`H[H[S[unfocused] focused] V[unfocused]]`
move_out_of_tabs_stacks was originally made to allow views to move out
of the tabbed/stacked container in the parallel direction, but at some
point this has started working using the regular logic.
If you have swaybar docked to the top, and you create a floating sticky
container and switch workspaces on the same output, the sticky container
would move down by the height of swaybar on each switch.
This happens because when creating the workspace we set the dimensions
to the same as the output, then the subsequent arrange corrects it.
During this arrange, floating containers are translated so they stay
relative to the workspace. This translation needs to not occur for the
initial arrange.
This patch makes workspaces have a zero width and height when first
created, so we can detect whether this is the initial arrange and avoid
translating the floating containers if so.
This adds a `con` argument to `execute_command` which allows you to
specify the container to execute the command on. In most cases it leaves
it as `NULL` which makes it use the focused node. We only set it when
executing `for_window` criteria such as when a view maps. This means we
don't send unnecessary IPC focus events, and fixes a crash when the
criteria command is `move scratchpad` (because we can't give focus to a
hidden scratchpad container).
Each of the shell map handlers now check to see if the view has a
workspace. It won't have a workspace if criteria has moved it to the
scratchpad.
Fixes#2674.
The cause of the issue was in get_pango_layout. When we call
pango_parse_markup, `text` is the escaped string, and the unescaped
string is then computed and written to `buf`. We were then passing the
unescaped string to pango_layout_set_markup, but this function needs the
escaped string. `buf` is not needed and has been removed.
The other part of this PR refactors escape_markup_text to remove the
dest_length argument and removes the -1 return value on error. It now
assumes that you've allocated dest to the correct length.
Firstly, a change had to be made to the container_at functions. If you
create layout `T[view H[view view]]` and hover the second tab, the
container_at functions would return the focus_inactive child. They now
return the split container itself. To compensate for this,
dispatch_cursor_button has been adjusted to find the focus_inactive
child before focusing it.
The actual implementation of wheel scrolling is pretty straightforward.
This uses handle_cursor_axis, so I took a similar approach to
handle_cursor_button (ie. creating a dispatch_cursor_axis function).
root_for_each_container and root_find_container were using incorrect
logic to determine if a container was hidden in the scratchpad.
Containers will have a NULL parent if they are a direct child of a
workspace. Containers will have a NULL workspace if they are hidden in
the scratchpad.
The incorrect check meant that root_for_each_container would run the
callback on scratchpad containers twice. This meant that executing a
command such as `[class="$something"] scratchpad show` would cause the
command to run twice, resulting in the container being shown and hidden
again which is effectively a no op.
Fixes#2655.
When destroying an idle-inhibiting client, idle_inhibit_v1_check_active can get
called from transaction_progress_queue on a view with a null container.
view_is_visible does not handle a view in this state.
seat_get_active_child is used to get the active tiling child in a few
places, such as outputs getting their active workspace and
tabbed/stacked containers getting their visible child. When a workspace
uses a tabbed or stacked layout and contains a focused floating view,
calling seat_get_active_child on the workspace would incorrectly return
the floating view. This changes it so it will return the tiling child.
This fixes the following bug:
* Create layout T[view view] then float one of the views
* Attempt to click the tiling view to give it focus - it wouldn't work
because seat_get_active_child would return the floating view
* Create layout T[view view]
* Move the cursor into the title bar area
* Close both views
Sway would crash because container_at_tabbed would attempt to divide by
zero when there are no children.
The children check isn't needed for the stacked function because it
doesn't divide anything by the number of children.
Fixes#2636.
wordexp p is now initialized to {0} to prevent a segfault on wordfree
in the failure case.
File paths with single quotes and double quotes are now supported. The
quote can either be wrapped in the other quote or escaped with three
backslashes.
Additionally to make passing file paths with double quotes to swaybg
easier, instead of enclosing the path given to swaybg in quotes, all
spaces, single quotes, and double quotes in the resulting path are now
escaped with a single backslash.
The assertion can be (rightfully) triggered by creating layout
V[H[view view] view] and moving the top right view to the right.
After removing the assertion I found the container being moved needs its
size reset to prevent it from being sized wrongly after arranging.
Since the `client.{focused,focused_inactive,unfocused,urgent}` commands
change colors, the textures need to be updated otherwise the textures
and the rest of the title bar may utilize different colors.
* Make container_add_sibling's `after` argument a boolean.
* Use a constant for drop layout border
* Make thickness an int
* Add button state check
* Move comments in seat_end_move_tiling
When workspace_wrap_children is called on a workspace which has a
fullscreen child and the fullscreen child is a direct child of the
workspace, sway would crash.
The workspace's fullscreen pointer is unset when the fullscreen
container is detached and applied again when added to a parent, but in
this case the parent hadn't yet been added to the workspace which meant
con->workspace was NULL.
The fix makes container_handle_fullscreen_reparent return if there's no
workspace, and the fullscreen pointer is reapplied in
workspace_wrap_children.
Fixes#2401 (aka #2558)
Previously, when switching windows, pointer focus was not changed until the pointer was moved. This makes the pointer enter happen immediately, without the side effects of other attempted fixes.
Added default values for all nodes, because the i3 get_tree always returns
all fields inside the json objects.
Add geometry and window for views. Window is only availabel on
x11 windows otherwise it's NULL.
Calculate percent only if parent is not empty to avoid division by 0.
This does the following:
* Adds a baseline argument to get_text_size (the baseline is the
distance from the top of the texture to the baseline).
* Stores the baseline in the container when calculating the title
height.
* Takes the baseline into account when calculating the config's max font
height.
* When rendering, pads the textures according to the baseline so they
line up.
There was code that attempted to fill in the gap below the title texture
when the texture isn't tall enough, but this only worked when the output
was positioned at 0,0. The reason is that render_rect expects a box
passed in a hybrid layout-local/output-buffer-local system, and we were
passing purely output-buffer-local. I've added a comment documenting
this.
By the way, we can't use layout-local coordinates for the rectangle box
because in some cases we set the box based on a texture size. Texture
sizes are buffer-local, and we'd have to divide them to bring it back to
layout-local which means losing precision. We could use
output-buffer-local coordinates for the box, but this would require
translating the coordinates from layout-local to output-buffer-local in
many places during rendering.
This patch also vertically centers the text inside the title bar.
This fixes pinentry-gtk-2, but might make other views floating which
would otherwise be tiled. This patch is more of a trial which could end
up becoming a permanent fix.
To reproduce the problem this is fixing, create H[view view view],
fullscreen one of the views and close it. The entire workspace will be
given focus rather than one of the siblings.
This happens because we emit the destroy event, so the seat code tries
to find a new focus, but the view it finds is still believed to be
hidden by the fullscreen view so it's discarded and the workspace is
used instead.
This clears the workspace's fullscreen pointer prior to emitting the
destroy event so that the seat code finds an appropriate new focus.
When rendering, the workspace for the output needs to be retrieved from
the output's `current` state. output_get_active_workspace returns the
pending workspace, which crashes if the pending workspace is new and
hasn't completed a transaction yet.
These are the same as seat_set_focus, but accept a specific type rather
than using nodes. Doing this adds more typesafety and lets us avoid
using &con->node which looks a little ugly.
This fixes a crash that pretty much nobody would ever come across. If
you have a bindsym for "focus" with no arguments and run it from an
empty workspace, sway would crash because it assumes `container` is not
NULL.
* Fullscreen a view
* Run `focus <direction>` where there is no output in that direction
The output returned was rightfully NULL, which needs to be handled.
It was incorrectly determining that the container being moved and the
destination had the same parent, which resulted in tree corruption. Both
parents can be NULL but the containers may belong to different
workspaces.
To reproduce, create layout H[V[view] view] in one workspace then move a
view left or right from another output into that workspace.
Suppose the following:
* Transactions are already in progress - say transaction A.
* View A maps, which creates transaction B and appends it to the
transaction queue.
* View B maps, which creates transaction C and appends it to the queue.
* View A unmaps, which creates transaction D and appends it to the
queue.
* Transaction A completes, so transaction B attempts to save View A's
buffer, but this doesn't exist so it saves nothing.
* Rendering code attempts to render View A, but there is no saved buffer
nor live buffer that it can use.
Rather than implement an elaborate solution for a rare circumstance,
I've take the safe option of just not rendering anything for that view.
It means that if you reproduce the scenario above, you might get the
title and borders rendered but no surface.
Prior to f5b9815128, children of tabbed
and stacked containers would have their container size and position set
to the same as the tabbed/stacked container. Normally this would be a
problem for a layout such as T[V[view]], but there was some code in the
arrange functions which would check if the grandparent of the view was a
tabbed or stacked container and would offset the view's Y accordingly.
Commit f5b9815128 changed the box to
exclude the titlebar for all tabbed/stacked children so that the
grandparent check could be removed. But this meant the title was not
covered in the container and wasn't damaged when the child changed its
title.
This patch changes it so that a child of a tabbed/stacked container will
have its box include the title bar if the child is a view, but not if
it's a layout container. This fixes the title damage issue while
avoiding the grandparent check in the arrange functions, and matches
what we see visually.
seat_execute_command needs to check the flags on `binding_copy`, as
`binding` will be a dangling pointer after a reload command.
handle_keyboard_key needs to set the next_repeat_binding for
non-reloads prior to executing the command in case the binding is
freed by the reload command.
* Was crashing when a view was moved to the scratchpad (prev focus had
no parent).
* Was crashing when a hidden scratchpad view unmaps because it has no
workspace.
When changing focus from a view in one workspace to an empty workspace
using `focus <direction>`, the view in the previous workspace would keep
focused styling. This is because the check to unfocus it was only done
in the container case and not workspace case, so it's been moved out of
both.
This commit changes the meaning of sway_container so that it only refers
to layout containers and view containers. Workspaces, outputs and the
root are no longer known as containers. Instead, root, outputs,
workspaces and containers are all a type of node, and containers come in
two types: layout containers and view containers.
In addition to the above, this implements type safe variables. This
means we use specific types such as sway_output and sway_workspace
instead of generic containers or nodes. However, it's worth noting that
in a few places places (eg. seat focus and transactions) referring to
them in a generic way is unavoidable which is why we still use nodes in
some places.
If you want a TL;DR, look at node.h, as well as the struct definitions
for root, output, workspace and container. Note that sway_output now
contains a workspaces list, and workspaces now contain a tiling and
floating list, and containers now contain a pointer back to the
workspace.
There are now functions for seat_get_focused_workspace and
seat_get_focused_container. The latter will return NULL if a workspace
itself is focused. Most other seat functions like seat_get_focus and
seat_set_focus now accept and return nodes.
In the config->handler_context struct, current_container has been
replaced with three pointers: node, container and workspace. node is the
same as what current_container was, while workspace is the workspace
that the node resides on and container is the actual container, which
may be NULL if a workspace itself is focused.
The global root_container variable has been replaced with one simply
called root, which is a pointer to the sway_root instance.
The way outputs are created, enabled, disabled and destroyed has
changed. Previously we'd wrap the sway_output in a container when it is
enabled, but as we don't have containers any more it needs a different
approach. The output_create and output_destroy functions previously
created/destroyed the container, but now they create/destroy the
sway_output. There is a new function output_disable to disable an output
without destroying it.
Containers have a new view property. If this is populated then the
container is a view container, otherwise it's a layout container. Like
before, this property is immutable for the life of the container.
Containers have both a `sway_container *parent` and
`sway_workspace *workspace`. As we use specific types now, parent cannot
point to a workspace so it'll be NULL for containers which are direct
children of the workspace. The workspace property is set for all
containers, except those which are hidden in the scratchpad as they have
no workspace.
In some cases we need to refer to workspaces in a container-like way.
For example, workspaces have layout and children, but when using
specific types this makes it difficult. Likewise, it's difficult for a
container to get its parent's layout when the parent could be another
container or a workspace. To make it easier, some helper functions have
been created: container_parent_layout and container_get_siblings.
container_remove_child has been renamed to container_detach and
container_replace_child has been renamed to container_replace.
`container_handle_fullscreen_reparent(con, old_parent)` has had the
old_parent removed. We now unfullscreen the workspace when detaching the
container, so this function is simplified and only needs one argument
now.
container_notify_subtree_changed has been renamed to
container_update_representation. This is more descriptive of its
purpose. I also wanted to be able to call it with whatever container was
changed rather than the container's parent, which makes bubbling up to
the workspace easier.
There are now state structs per node thing. ie. sway_output_state,
sway_workspace_state and sway_container_state.
The focus, move and layout commands have been completely refactored to
work with the specific types. I considered making these a separate PR,
but I'd be backporting my changes only to replace them again, and it's
easier just to test everything at once.
Fixes#2568
The binding that gets stored in the keyboard's `repeat_binding` would
get freed on reload, leaving a dangling pointer.
Rather than attempt to unset the keyboard's `repeat_binding` along with
the other bindings, I opted to just not set it for the reload command
because there's no point in reloading repeatedly by holding the binding.
This disables repeat bindings for the reload command.
As we now need to detect whether it's a reload command in two places,
I've added a binding flag to track whether it's a reload or not.
Depends on https://github.com/swaywm/wlroots/pull/1222.
I don't know of a program that sets the state to modal without setting
the window type, but I know the modal property works because logging the
property shows it's true for the Firefox Open File dialog.
May as well make it as easy as possible for users who are coming from
i3.
This also changes the `border` command to accept a thickness when
setting the border to normal. This makes it work the same way as the
`default_border` command. Eg. `border normal 5`
If sway is reloaded using a bindsym which has multiple commands, it
failed to detect the reload command, didn't create a duplicate of the
binding and would crash because the reload command frees the bindings.
For example:
mode system {
bindsym r reload, mode default
}
In this example, the binding->command is "reload, mode default".
Fixes#2545
This moves the arrange_windows call into the arrange_layers function,
where we know the output actually needs to be arranged.
Additionally, we shouldn't set focus to the parent of an unknown
container type, because the parent may be an output and this causes a
crash because outputs can't have direct focus.
Fixes#2543
Rootston calls "wlr_xwayland_destroy" and "wl_display_destroy_clients"
on shutdown, but these were not called by Sway. Without them, Sway
crashes on exit before the display destroy event handler could be
called. This causes two problems:
- The TTY is not reset, and it locks up after exiting Sway.
- drmDropMaster is not called, and the implicit drop (that should
occur when the DRM fd is closed) seems not to be working in some
scenarios (e.g. if you have a tmux session running - maybe the fd
is retained somehow by tmux?). In other words, it you exit Sway,
you can't start it (or any other program that wants to be DRM
master) again until you close all your tmux sessions.
When collecting focus to save into the transaction state, the workspace
needs to look in the tiling list only.
As seat_get_focus_inactive_tiling returns any descendant, the list also
needs to be traversed back up to the direct child of the workspace.
Fixes#2532
When there's multiple transactions in the queue, sway can take a
shortcut by checking if they all operate on the same set of containers.
If they do, it can skip all but the last transaction. The way we tested
for transactions which used the same containers was to exclusive-or
their con IDs together, but this has proved not only to be ineffective
but also has the potential to make sway crash.
This patch replaces the exclusive-or with a loop and container
comparison.
When moving a container to an inactive workspace on a different output, this will change the focus on the destination output back to its last active workspace
* In layout command, arrange parent of parent - not sure why this is
needed but it is
* Remove gap adjustment when rendering
* Workspace should use outer gaps, not inner
* Add exceptions for tabbed and stacked containers
* Don't mess with gap state when splitting a container
This commit changes the arrange code in a way that will support type
safe arguments.
The arrange_output et al functions are now public, however I opted not
to use them directly yet. I've kept the generic arrange_windows there
for convenience until type safety is fully implemented. This means this
patch has much less risk of breaking things as it would otherwise.
To be type safe, arrange_children_of cannot exist in its previous form
because the thing passed to it could be either a workspace or a
container. So it's now renamed to arrange_children and accepts a list_t,
as well as the parent layout and parent's box.
There was some code which checked the grandparent's layout to see if it
was tabbed or stacked and adjusted the Y offset of the grandchild
accordingly. Accessing the grandparent layout isn't easy when using type
safe arguments, and it seemed odd to even need to do this. I determined
that this was needed because a child of a tabbed container would have a
swayc Y matching the top of the tab bar. I've changed this so a child of
a tabbed container will have a swayc Y matching the bottom of the tab
bar, which means we don't need to access the grandparent layout. Some
tweaks to the rendering and autoconfigure code have been made to
implement this, and the container_at code appears to work without
needing any changes.
arrange_children_of (now arrange_children) would check if the parent had
gaps and would copy them to the child, effectively making the
workspace's gaps recurse into all children. We can't do this any more
without passing has_gaps, gaps_inner and gaps_outer as arguments to
arrange_children, so I've changed the add_gaps function to retrieve it
from the workspace directly.
apply_tabbed_or_stacked_layout has been split into two functions, as it
had different logic depending on the layout.
Lastly, arrange.h had an unnecessary include of transaction.h. I've
removed it, which means I've had to add it to several other files.
When we have type safety we'll need to have functions for
workspace_add_tiling and so on. This means the existing container
functions will be just for containers, so they are being moved to
container.c. At this point layout.c doesn't contain much else, so I've
relocated everything and removed the file.
* container_swap and its static functions have been moved to the swap
command and made static.
* container_recursive_resize has been moved to the resize command and
made static.
* The following have been moved to container.c:
* container_handle_fullscreen_reparent
* container_insert_child
* container_add_sibling
* container_add_child
* container_remove_child
* container_replace_child
* container_split
* enum movement_direction and sway_dir_to_wlr have been moved to util.c.
Side note: Several commands included layout.h which then included
root.h. With layout.h gone, root.h has to be included by those commands.
This list includes disabled outputs.
When sway_container is demoted, we'll need to store the root's children
(ie. enabled outputs) in the sway_root. It makes sense to put these in a
list called `outputs`, so I'm renaming the existing list in advance.
* container_move is only called from the move command
* container_move_to was called from both the move command and the sticky
command, but the sticky command can easily not call it
* container_get_in_direction is only called from the focus command
Moving these functions to their respective commands gives better
separation of code and removes bloat from layout.c. These functions will
need to be refactored to take advantage of type safety, so separating
them will make this easier to refactor.
The following static functions have also been moved:
* is_parellel
* invert_movement
* move_offs
* container_limit
* workspace_rejigger
* move_out_of_tabs_stacks
* get_swayc_in_output_direction
They were all used by the move functions, except for the last one which
is used by focus.
Other changes:
* index_child has been renamed to container_sibling_index, moved to
container.c and made public
* sway_output_from_wlr has been renamed to output_from_wlr_output, moved
to output.c and made public
* container_handle_fullscreen_reparent has been made public
* sway_dir_to_wlr has been made public
No changes have been made to any of the moved functions, other than
updating calls to functions that have been renamed.
This changes the destroy functions to the following:
* output_begin_destroy
* output_destroy
* workspace_begin_destroy
* workspace_destroy
* container_begin_destroy
* container_destroy
* view_begin_destroy
* view_destroy
The terminology was `destroy` and `free`, and it has been changed to
`begin_destroy` and `destroy` respectively.
When the last output is disconnected, its workspaces will now be stashed
in the root. Upon connection of a new output they will be restored.
There is a new function `workspace_consider_destroy` which decides
whether the given workspace should be destroyed or not (ie. empty and
not visible).
Calling container_begin_destroy will no longer automatically reap the
parents. In some places we want to reap the parents and in some we
don't, so this is left to the caller.
container_reap_empty_recursive and container_reap_empty have been
combined into one function and it will recurse up the tree.
When a workspace is moved to another output, or the output it's on
changes its global layout position, the floating containers on that
workspace should be translated by the same amount as the workspace. This
keeps the floating containers in the same position relative to the
workspace.
A check is done to make sure the floating container's center point isn't
being moved off screen. If it is, it is centered within the workspace.
Fixes part of #2500.
Improves upon 18e425ed by using the first assigned workspace instead of
the last one. The order isn't explicitly guaranteed to be the same as in
the config, but in general works.
Fixes#2490.
To be honest I'm not sure why this fixes the issue.
I observed that I could only make the view jump if I resized it to the
smallest possible size first. Then I had a suspicion that we were
accidentally factoring in the title and border sizes into the view size
when it uses CSD. So I changed that and it appears to have fixed the
jumping issue.
I guess when we factor the title and borders in, we send a configure to
the surface with a size smaller than the minimum, and it comes back with
a surface at the minimum size. We interpret this as an unexpected
resize, and this somehow makes it jump.
Previously we used a reparent event to detect when a view changes
parent, then sent an output enter/leave to the surfaces if needed. This
worked for tiling views but not floating views, as floating views can
intersect another output without changing parent.
The solution implemented for floating views also applies cleanly to
tiling views, so the previous method has been completely replaced and
the reparent event has been removed.
This introduces a new function container_discover_outputs. This function
compares the container's `current` position to the outputs, sends enter
and leave events as needed, and keeps track of which outputs it's
intersecting in a new `container->outputs` list. If it has entered a new
output with a different scale then the title and marks textures will
also be recreated at the new scale.
The function is called when a transaction applies. This is convenient as
it means we don't have to call it from various places.
There is imperfect rendering when a floating view overlaps two outputs
with different scales. It renders correctly for the most recently
entered output, but there is only one title texture so it renders
incorrectly on the old output.
Fixes#2482
We were removing the saved buffer when one transaction applies, then
didn't have a new buffer to save when the next transaction ran. This
made the rendering code crash as it had no surface to use.
This commit makes it continue to hold the buffer if the view is
destroying and has more transactions. Additionally, a check is added
when saving the buffer to make sure there's no one already there.