segmented_button: fix internal tab reorder end-to-end
Two independent bugs prevented tab drag-and-drop reorder from working on cosmic-comp (and likely other compositors): 1. allow_reorder required DndAction::Move to be negotiated via OfferEvent::SelectedAction, which cosmic-comp does not always emit for self-drops (the SelectedAction event either never arrives or arrives with DndAction::empty()). Add a fallback: accept self-drops whenever state.dragging_tab is set. dragging_tab is only populated by start_tab_drag on this same widget, so this is safe; mime match and on_reorder presence are checked below. 2. reorder_event_for_drop preferred drop_hint.side over positional swap, producing counter-intuitive no-ops: dropping A (pos 0) on the left half of B (pos 1) resolved to "Before B" which, after removing A, lands at pos 0 again — the tab appeared not to move. Always use default_insert_position, which derives direction from dragged vs target positions (Konsole/Firefox/Chrome-style swap semantics). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
108441ef61
commit
a322516f33
1 changed files with 14 additions and 6 deletions
|
|
@ -406,11 +406,12 @@ where
|
|||
{
|
||||
return None;
|
||||
}
|
||||
let position = state
|
||||
.drop_hint
|
||||
.filter(|hint| hint.entity == target)
|
||||
.map(|hint| InsertPosition::from(hint.side))
|
||||
.unwrap_or_else(|| self.default_insert_position(dragged, target));
|
||||
// Always use positional swap (Konsole/Firefox/Chrome semantics):
|
||||
// dropping onto any part of a different tab swaps it with the dragged
|
||||
// tab. drop_hint.side-based Before/After is counter-intuitive: dropping
|
||||
// A (pos 0) on the left half of B (pos 1) resolves to "Before B" which,
|
||||
// after removing A, lands at pos 0 — so the tab appears not to move.
|
||||
let position = self.default_insert_position(dragged, target);
|
||||
Some(ReorderEvent {
|
||||
dragged,
|
||||
target,
|
||||
|
|
@ -1201,7 +1202,14 @@ where
|
|||
.dnd_state
|
||||
.drag_offer
|
||||
.as_ref()
|
||||
.is_some_and(|offer| offer.selected_action.contains(DndAction::Move));
|
||||
.is_some_and(|offer| offer.selected_action.contains(DndAction::Move))
|
||||
// Self-drop fallback: some compositors (cosmic-comp
|
||||
// observed) do not emit OfferEvent::SelectedAction for
|
||||
// internal drags, leaving selected_action empty.
|
||||
// dragging_tab is only set by start_tab_drag on this
|
||||
// same widget, so this covers the self-drop case
|
||||
// safely; mime and on_reorder are checked below.
|
||||
|| state.dragging_tab.is_some();
|
||||
let pending_reorder = if allow_reorder
|
||||
&& self.on_reorder.is_some()
|
||||
&& self.tab_drag.as_ref().is_some_and(|d| d.mime == *mime_type)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue