Skip to content

Animations invoked through LUA scripts do not get interrupted #385

Description

@eghere

Please fill out the following:

Scroll Version:
1.12.21
Description:
There has recently been work done in the codebase to prevent animations from "queuing" if multiple commands are sent together. I have noticed this behavior still remains if commands are executed through a LUA script. For example, here's a script I use to cycle sizes based on monitor layout:

local scroll = require("scroll")
-- cycle_size_smart.lua
local args, state = ...
local direction = args[1] -- "prev" or "next"
local invert = args[2] == "true" -- whether to use opposite axis

local workspace = scroll.focused_workspace()
if workspace then
	local layout_type = scroll.workspace_get_layout_type(workspace)

	-- In vertical layout, we cycle widths (h)
	-- In horizontal layout, we cycle heights (v)
	local axis = (layout_type == "vertical") and "v" or "h"

	-- If invert is true, use the opposite axis
	if invert then
		axis = (axis == "h") and "v" or "h"
	end

	local command = string.format("cycle_size %s %s", axis, direction)
	scroll.command(nil, command)
end

I use this script in my config as:

    bindsym --inhibited $mod+u lua $scripts/smart_cycle_size.lua prev false
    bindsym --inhibited $mod+i lua $scripts/smart_cycle_size.lua next false
    bindsym --inhibited $mod+Shift+u lua $scripts/smart_cycle_size.lua prev true
    bindsym --inhibited $mod+Shift+i lua $scripts/smart_cycle_size.lua next true

Steps to Reproduce

  1. Apply the configuration and script provided above to Scroll.
  2. Enable an animation, preferably one with a long duration to better see the bug.
  3. Send consecutive, rapid keybinds, i.e. four quick mod+u keystrokes in a row.
  4. Animations are queued instead of interrupted based on keypress.

(Disclaimer: I used LLM to assist the following root cause analysis + rough implementation plan. It contains information retrieved by an LLM, but it has been reviewed by me prior to posting.)

Root cause
The direct IPC path and the Lua binding path commit resize transactions differently:

  1. scrollmsg cycle_size ... runs the command in ipc_client_handle_command().
    Its outer transaction_commit_dirty() runs after execute_command() has
    restored server.delay_transaction, so it both collects and commits the
    dirty layout nodes.
  2. The keybindings launch scrollmsg lua .... The Lua script calls
    scroll.command(nil, command), which nests another execute_command().
    execute_command() sets server.delay_transaction = true; the nested
    scroll.command() calls transaction_commit_dirty() while that flag is
    still true. The dirty nodes are moved into server.pending_transaction, but
    the commit is deferred.
  3. When the nested command returns, the outer IPC handler calls
    transaction_commit_dirty() again. Because the dirty-node list is now
    empty, _transaction_commit_dirty() returns immediately and does not flush
    the already-created pending transaction.
  4. animation_animate() eventually calls transaction_commit_delayed() when
    the current animation finishes, so the next resize starts only then.

Relevant files to this bug
sway/commands.c
sway/lua.c
sway/desktop/transaction.c
sway/desktop/animation.c

Implementation Suggestion

  • Make the transaction commit boundary handle an existing pending transaction
    when an explicit, non-delayed commit occurs after dirty nodes were already
    collected by a nested command.
  • Preserve the recent behavior that client-only transactions remain deferred
    while an animation is active; only an explicit command transaction should
    force the pending resize through.
  • Add a regression test covering repeated cycle_size commands through a Lua
    script invoked over IPC, alongside the existing animation transaction tests.
  • Validate that direct scrollmsg cycle_size behavior remains unchanged and that
    repeated Lua-triggered resizes start the incoming animation immediately.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions