Fix webview dragging.

This commit is contained in:
Greyson Parrelli
2026-08-26 14:03:49 -04:00
parent 0fd0aa44c7
commit 4327c17fd7
2 changed files with 28 additions and 0 deletions
+17
View File
@@ -395,6 +395,12 @@ pub fn grabFocus(self: *Pane) void {
self.content.grabFocus();
}
/// Whether the content is allowed to be picked as the target of a pointer or a
/// drop. Off for the length of a pane drag — see `installDropTarget`.
pub fn setContentTargetable(self: *Pane, targetable: bool) void {
self.content.widget().setCanTarget(@intFromBool(targetable));
}
/// The terminal this pane holds, or null if it holds something else. Callers
/// that only make sense for a terminal — pasting a VT sequence, say — use this
/// to opt out on a web pane.
@@ -585,6 +591,17 @@ fn installDropTarget(self: *Pane) void {
_ = gtk.DropTarget.signals.motion.connect(target, *Pane, &onDropMotion, self, .{});
_ = gtk.DropTarget.signals.leave.connect(target, *Pane, &onDropLeave, self, .{});
_ = gtk.DropTarget.signals.drop.connect(target, *Pane, &onDrop, self, .{});
// On the pane rather than the header, so the whole pane is a target and
// `targetAt` has an area to pick a side from. That puts it above the
// content in the widget tree, which is fine for a terminal — it takes no
// drops — but a web view is a drop target in its own right and an
// innermost one wins. Since the preview slides the dragged pane in under
// the pointer, the drop at the end of a drag of a browser or a review pane
// would land in that pane's own page: no `drop` here, so `endDrag` would
// find the drag uncommitted and undo the whole move. `View.beginDrag`
// takes every pane's content out of the picking for the length of a drag
// so that the pane is what the drop reaches.
self.widget().addController(target.as(gtk.EventController));
}
+11
View File
@@ -786,6 +786,13 @@ pub fn beginDrag(self: *View, pane: *Pane) bool {
.origin_ratio = position.ratio,
};
pane.widget().addCssClass("dragging");
// For the length of the drag, a pane's content is not a drop target and
// the pane itself is. Without this a web view — a browser or a review
// pane — swallows the drop that lands on it, including the drop on the
// dragged pane itself, which is where the preview has just put it. See
// `Pane.installDropTarget`.
for (self.panes.items) |p| p.setContentTargetable(false);
return true;
}
@@ -808,6 +815,10 @@ pub fn commitDrag(self: *View) void {
/// End of a drag. If no drop was accepted, undo whatever the preview did.
pub fn endDrag(self: *View) void {
// Before the early return: a drag whose pane was closed under it has
// already cleared `drag`, and the content would stay unpickable for good.
for (self.panes.items) |p| p.setContentTargetable(true);
const drag = self.drag orelse return;
self.drag = null;
drag.pane.widget().removeCssClass("dragging");