From 73e050897b9e896be5c734822b0fb4e1125bef86 Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Mon, 3 Aug 2026 07:39:33 +0545 Subject: [PATCH] fix(desktop): repaint widgets during drag and drop A Gtk.Fixed child resize only bubbles to the toplevel when the window itself is queued, so move() kept the old allocation until a rebuild. Queue the window after each reposition so the dragged widget follows the cursor and lands at the drop position live. Dropped remove()+put() which never repainted in the layer-shell window. --- src/window/desktop/main.py | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/window/desktop/main.py b/src/window/desktop/main.py index 75cfc39..a0ba424 100644 --- a/src/window/desktop/main.py +++ b/src/window/desktop/main.py @@ -339,6 +339,15 @@ class DesktopWidgetWindow(WaylandWindow): sc.remove_class("edit-mode") eb.drag_source_unset() + if self._edit_mode: + # Full interactive surface while editing: drag-motion events are + # delivered across the whole desktop instead of only over the + # widget rectangles, so dragged widgets follow the cursor + # everywhere (as before the partial input region was added). + self.input_shape_combine_region(None) + else: + self._schedule_input_rebuild() + # GTK DnD def _setup_drag_dest(self) -> None: @@ -377,16 +386,25 @@ class DesktopWidgetWindow(WaylandWindow): def _on_applet_drag_end(self, eb, ctx, key: str) -> None: if not self._drag_drop_success: - self._fixed.remove(eb) - self._fixed.put( + # Reposition with move(), not remove()+put(): removing and + # re-adding a Gtk.Fixed child does not repaint in this window. + self._fixed.move( eb, getattr(eb, "_target_x", 0), getattr(eb, "_target_y", 0), ) + self._reposition_now() self._dragging_key = None self._dragging_eb = None self._schedule_input_rebuild() + def _reposition_now(self) -> None: + # A Gtk.Fixed child resize only bubbles up to the toplevel when the + # window itself is queued; fixed/child-level queue_resize() does not + # reach the layer-shell window, so the child would keep its old + # allocation until a full rebuild. queue the window to re-allocate. + self.queue_resize() + def _on_drag_motion(self, widget, ctx, x, y, time) -> bool: targets = [t.name() for t in ctx.list_targets()] if "text/plain" not in targets or self._dragging_key is None: @@ -399,6 +417,7 @@ class DesktopWidgetWindow(WaylandWindow): nx = max(0, min(self._win_w - aw, int(x - aw / 2))) ny = max(0, min(self._win_h - ah, int(y - ah / 2))) self._fixed.move(eb, nx, ny) + self._reposition_now() Gdk.drag_status(ctx, Gdk.DragAction.MOVE, time) return True @@ -433,8 +452,11 @@ class DesktopWidgetWindow(WaylandWindow): new_y / self._win_h, ) - self._fixed.remove(eb) - self._fixed.put(eb, new_x, new_y) + # move() instead of remove()+put(): the latter does not repaint in a + # layer-shell window, so the new position would only appear after a + # restart. move() on the already-attached child repaints immediately. + self._fixed.move(eb, new_x, new_y) + self._reposition_now() eb.show() self._drag_drop_success = True @@ -578,6 +600,8 @@ class DesktopWidgetWindow(WaylandWindow): return False def _rebuild_input_region(self) -> None: + if self._edit_mode: + return rects = [] for eb in self._children.values(): a = eb.get_allocation()