mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-08-25 00:21:46 +00:00
gtk: support cross-tree surface drag and drop
This commit is contained in:
@@ -387,11 +387,6 @@ pub const SplitTree = extern struct {
|
||||
return true;
|
||||
}
|
||||
|
||||
pub const MoveSplitError = Allocator.Error || error{
|
||||
SourceNotFound,
|
||||
TargetNotFound,
|
||||
};
|
||||
|
||||
/// Move the source split onto the target split in a given direction.
|
||||
/// The target split must be located within this tree.
|
||||
pub fn moveSplit(
|
||||
@@ -399,21 +394,27 @@ pub const SplitTree = extern struct {
|
||||
source: *Surface,
|
||||
target: *Surface,
|
||||
dir: Surface.Tree.Split.Direction,
|
||||
) MoveSplitError!void {
|
||||
) Allocator.Error!void {
|
||||
const alloc = Application.default().allocator();
|
||||
const tree = self.getTree() orelse return;
|
||||
|
||||
const source_handle = tree.locate(source) orelse return error.SourceNotFound;
|
||||
const target_tree = self.getTree() orelse return;
|
||||
|
||||
// This really shouldn't fail, but just in case
|
||||
const target_handle = tree.locate(target) orelse return error.TargetNotFound;
|
||||
const target_handle = target_tree.locate(target) orelse {
|
||||
log.warn("target is not placed in a split tree", .{});
|
||||
return;
|
||||
};
|
||||
|
||||
// TODO: is it perhaps possible to condense all of this
|
||||
// into one atomic operation?
|
||||
// Try to find the source within the current tree.
|
||||
// If it exists, then it's a local move; otherwise the logic gets more
|
||||
// complicated
|
||||
const source_handle = target_tree.locate(source);
|
||||
|
||||
// First add the source into this tree.
|
||||
// We have to do this no matter what
|
||||
var branch = try Surface.Tree.init(alloc, source);
|
||||
defer branch.deinit();
|
||||
|
||||
var after_split = try tree.split(
|
||||
var after_split = try target_tree.split(
|
||||
alloc,
|
||||
target_handle,
|
||||
dir,
|
||||
@@ -422,10 +423,36 @@ pub const SplitTree = extern struct {
|
||||
);
|
||||
defer after_split.deinit();
|
||||
|
||||
var after_remove = try after_split.remove(alloc, source_handle);
|
||||
defer after_remove.deinit();
|
||||
if (source_handle) |handle| {
|
||||
// Happy path: source and target are located within the same tree.
|
||||
// In that case, we just remove the existing source from this tree
|
||||
|
||||
self.setTree(&after_remove);
|
||||
var after_remove = try after_split.remove(alloc, handle);
|
||||
defer after_remove.deinit();
|
||||
|
||||
self.setTree(&after_remove);
|
||||
} else {
|
||||
// :( Cross-tree moves are a bit more complicated.
|
||||
|
||||
// TODO: Find a better way to access the split tree from here
|
||||
const source_tree_widget = ext.getAncestor(
|
||||
SplitTree,
|
||||
source.as(gtk.Widget),
|
||||
) orelse {
|
||||
log.warn("source is not placed in a split tree", .{});
|
||||
return;
|
||||
};
|
||||
const source_tree = source_tree_widget.getTree() orelse return;
|
||||
|
||||
// Remove the source from its own tree
|
||||
const handle = source_tree.locate(source) orelse return;
|
||||
var new_source_tree = try source_tree.remove(alloc, handle);
|
||||
defer new_source_tree.deinit();
|
||||
|
||||
// Finally, set the final tree structures for both tree widgets
|
||||
source_tree_widget.setTree(&new_source_tree);
|
||||
self.setTree(&after_split);
|
||||
}
|
||||
}
|
||||
|
||||
fn disconnectSurfaceHandlers(self: *Self) void {
|
||||
|
||||
@@ -3773,21 +3773,9 @@ pub const Surface = extern struct {
|
||||
|
||||
const dir = self.calcDropDirection(x, y);
|
||||
|
||||
st.moveSplit(from, self, dir) catch |err| {
|
||||
switch (err) {
|
||||
error.OutOfMemory => log.warn("out of memory", .{}),
|
||||
// FIXME: implement this!
|
||||
error.SourceNotFound => log.debug(
|
||||
"cross-tree drag-and-drop not yet supported",
|
||||
.{},
|
||||
),
|
||||
error.TargetNotFound => log.warn(
|
||||
"can't seem to find surface in tree - this shouldn't happen!",
|
||||
.{},
|
||||
),
|
||||
}
|
||||
return;
|
||||
};
|
||||
// The only error that could happen here is an OOM,
|
||||
// and in that case we're already milliseconds away from crashing, so...
|
||||
st.moveSplit(from, self, dir) catch return;
|
||||
|
||||
// Clean up overlay state
|
||||
self.setDropOverlayDirection(null);
|
||||
|
||||
Reference in New Issue
Block a user