Skip to content

Commit ba74950

Browse files
authored
Keep dragged indicators under cursor (#96)
1 parent 505405d commit ba74950

3 files changed

Lines changed: 42 additions & 17 deletions

File tree

docking/ui/dnd.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,12 @@ def _on_drag_motion(
400400
self._model.reorder_visible(self.drag_index, new_index)
401401
self.drag_index = new_index
402402

403+
# Track cursor during drag so the renderer can pin the dragged item's
404+
# running-indicator dot under the drag ghost instead of letting it drift
405+
# to the layout slot center as the model reorders.
406+
self._window.cursor_x = float(x)
407+
self._window.cursor_y = float(y)
408+
403409
Gdk.drag_status(context, Gdk.DragAction.MOVE, time)
404410

405411
widget.queue_draw()

docking/ui/dock_window.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,9 @@ def _on_draw(self, widget: Gtk.DrawingArea, cr: cairo.Context) -> bool:
696696
]
697697
log.debug("draw items: %s", " | ".join(item_positions) or "<none>")
698698
self._sync_background_blur_hint(frame=frame)
699+
cursor_main_axis = (
700+
self.cursor_x if is_horizontal(pos=self.config.pos) else self.cursor_y
701+
)
699702
self.renderer.draw(
700703
cr,
701704
widget,
@@ -707,6 +710,7 @@ def _on_draw(self, widget: Gtk.DrawingArea, cr: cairo.Context) -> bool:
707710
drop_insert,
708711
hovered_id,
709712
drop_target_id=drop_target,
713+
cursor_main=cursor_main_axis,
710714
)
711715
# Update input region as hide state changes (shrink when hidden)
712716
self.update_input_region(frame=frame)

docking/ui/renderer.py

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,7 @@ def draw(
616616
drop_insert_index: int = -1,
617617
hovered_id: str = "",
618618
drop_target_id: str = "",
619+
cursor_main: float = -1.0,
619620
) -> None:
620621
"""Main draw entry point -- called on every 'draw' signal.
621622
@@ -651,6 +652,7 @@ def draw(
651652
drop_insert_index=drop_insert_index,
652653
hovered_id=hovered_id,
653654
drop_target_id=drop_target_id,
655+
cursor_main=cursor_main,
654656
)
655657
cr.set_operator(cairo.OPERATOR_SOURCE)
656658
cr.set_source_surface(offscreen, 0, 0)
@@ -667,6 +669,7 @@ def _draw_content(
667669
drop_insert_index: int,
668670
hovered_id: str,
669671
drop_target_id: str = "",
672+
cursor_main: float = -1.0,
670673
) -> None:
671674
"""Render all dock content to a Cairo context."""
672675
pos = config.pos
@@ -899,24 +902,36 @@ def _draw_content(
899902
)
900903

901904
# --- Draw indicators ---
905+
# While dragging, the dragged item's icon is rendered by GTK as a drag
906+
# image that follows the cursor, while its layout slot keeps advancing
907+
# as the model reorders. Drawing the dot at the slot drifts visibly
908+
# ahead of the cursor until the next reorder snap. Pin the dragged
909+
# item's indicator to the cursor instead so it tracks the drag ghost.
902910
for i, (item, li) in enumerate(zip(items, layout, strict=True)):
903-
if item.is_running:
904-
slide = self.slide_offsets.get(item.desktop_id, 0.0)
905-
drop_shift = (
906-
gap if drop_insert_index >= 0 and i >= drop_insert_index else 0
907-
)
908-
self._draw_indicator(
909-
cr=cr,
910-
item=item,
911-
li=li,
912-
show_window_count_numbers=config.show_window_count_numbers,
913-
base_size=icon_size,
914-
main_pos=icon_offset + slide + drop_shift,
915-
cross_size=cross_size,
916-
hide_cross=hide_cross,
917-
theme=theme,
918-
pos=pos,
919-
)
911+
if not item.is_running:
912+
continue
913+
slide = self.slide_offsets.get(item.desktop_id, 0.0)
914+
drop_shift = gap if drop_insert_index >= 0 and i >= drop_insert_index else 0
915+
if i == drag_index and cursor_main >= 0:
916+
# Center the indicator under the cursor by passing a main_pos
917+
# such that _draw_indicator's "li.x + main_pos + scaled/2"
918+
# resolves to cursor_main.
919+
scaled_size = icon_size * li.scale
920+
main_pos_indicator = cursor_main - li.x - scaled_size / 2
921+
else:
922+
main_pos_indicator = icon_offset + slide + drop_shift
923+
self._draw_indicator(
924+
cr=cr,
925+
item=item,
926+
li=li,
927+
show_window_count_numbers=config.show_window_count_numbers,
928+
base_size=icon_size,
929+
main_pos=main_pos_indicator,
930+
cross_size=cross_size,
931+
hide_cross=hide_cross,
932+
theme=theme,
933+
pos=pos,
934+
)
920935

921936
# --- Draw per-app overlays ---
922937
for i, (item, li) in enumerate(zip(items, layout, strict=True)):

0 commit comments

Comments
 (0)