Skip to content

reorder is inert: zellij never delivers tab-drag (Hold/Release) to the non-selectable bar #102

Description

@GeneralD

type severity impact reproducibility root cause blocker

Part of #77. Blocks #93 (pane drag-to-move reuses the same DragState / Hold mechanism).

Update — root cause confirmed (was: "to verify"). Read straight from the zellij-server 0.44.3 source. This is a host limitation, not a plugin bug: zellij never delivers drag (Hold) or Release events to a non-selectable plugin pane, so the reorder gesture can never complete. It is not fixable in plugin code as a drag.

Problem

With reorder "true" set and RunActionsAsUser granted, dragging a tab block never reorders it — no tab ever moves. The rest of the bar works (click-to-switch #8, close button #86, wheel navigation #80), so event delivery and permissions are fine; only the drag-to-reorder gesture (#10) is inert.

Root Cause (confirmed from zellij-server 0.44.3)

The tab bar pins itself non-selectable (set_selectable(false), like the stock tab-bar), so it is never the active pane. zellij's mouse router gates drag/release delivery on exactly that:

zellij-server-0.44.3/src/tab/mouse_handler.rsdetermine_mouse_action:

// lines 1399-1414
let is_left_motion_or_release = event.left
    && (event.event_type == MouseEventType::Motion        // -> Mouse::Hold
        || event.event_type == MouseEventType::Release);  // -> Mouse::Release
if is_left_motion_or_release {
    let Some(details) = &ctx.clicked_pane else { return Ok(MouseAction::NoAction); };
    let is_active_pane = Some(details.pane_id) == ctx.active_pane_id;
    if is_active_pane && details.terminal_wants_mouse {   // bar: is_active_pane is ALWAYS false
        return Ok(MouseAction::SendToTerminal { .. });
    }
    return Ok(MouseAction::NoAction);                     // <- bar always lands here
}

The press is delivered through a different path, which is why click-to-switch/close work:

  • Pressis_plain_left_press → not active → MouseAction::FocusPaneexecute_focus_paneunselectable_pane_at_position(..).start_selection(..) (mouse_handler.rs:838-841). For a plugin pane, PluginPane::start_selection sends Event::Mouse(Mouse::LeftClick(..)) (zellij-server-0.44.3/src/panes/plugin_pane.rs:604-618). So LeftClick reaches the bar. (delivered)
  • That direct call does not set tab.selecting_with_mouse_in_pane, so ctx.selecting_with_mouse stays false. The only path that calls PluginPane::update_selection (→ Mouse::Hold, plugin_pane.rs:620-632) and end_selection (→ Mouse::Release, plugin_pane.rs:636-647) is the StartSelection/UpdateSelection/EndSelection flow, and StartSelection only fires for the active pane (mouse_handler.rs:1334-1345). The bar is never active. So Hold and Release never reach the bar. (NOT delivered)

Net: the bar receives LeftClick (which arms grab_at), but never the Hold that sets dragging = true (src/lib.rs:270, mark_dragging) nor the Release that commits (src/lib.rs:276, commit_drag_at). reorder_plan then short-circuits on .filter(|d| d.dragging) (src/lib.rs:744) and every release is a no-op. The reorder path is unit-tested with synthetic Mouse::Hold events, which is why it passed CI yet never worked live.

Impact beyond "it doesn't work"

reorder "true" makes the plugin request RunActionsAsUser (#23, #15). Because the feature can never fire, that permission buys nothing — but it still carries the zellij#4982 freeze risk (#15): a user who enables reorder and doesn't re-grant gets a frozen bar, in exchange for a dead feature.

Options

  1. Report upstream + neutralize reorder for now. File a zellij issue (deliver drag/release to non-selectable plugin panes, or arm selecting_with_mouse when a press lands on an unselectable plugin pane). Until then, either remove reorder or keep it but stop requesting RunActionsAsUser so it can't freeze the bar. Honest + removes the freeze trap.
  2. Replace drag with a click-only reorder (works today). LeftClick is reliably delivered, so a click-driven gesture works within the host's constraints — e.g. small / move affordances on the active tab, or a click-grab + click-drop mode. UX change, but functional now. (Also unblocks a click-based variant of feat: drag panes to move/swap, plus a clearer tab-drag affordance #93.)
  3. Check a newer zellij first. Confirm whether zellij > 0.44.3 changed this routing; if a later release delivers drag to plugins, the fix could be a version bump + docs rather than a redesign.

Relevant Code (plugin side)

  • src/lib.rs:270-283Hold / Release arms (mark_dragging / commit_drag_at)
  • src/lib.rs:744-772reorder_plan (the dragging gate) / reorder

Related

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions