diff --git a/src/apprt/gtk/class/split_tree.zig b/src/apprt/gtk/class/split_tree.zig index 473ae3daf..660c7c61c 100644 --- a/src/apprt/gtk/class/split_tree.zig +++ b/src/apprt/gtk/class/split_tree.zig @@ -239,12 +239,7 @@ pub const SplitTree = extern struct { } // Bind is-split property for new surface - _ = self.as(gobject.Object).bindProperty( - "is-split", - surface.as(gobject.Object), - "is-split", - .{ .sync_create = true }, - ); + surface.bindIsSplit(self); // Create our tree var single_tree = try Surface.Tree.init(alloc, surface); @@ -452,6 +447,9 @@ pub const SplitTree = extern struct { // Finally, set the final tree structures for both tree widgets source_tree_widget.setTree(&new_source_tree); self.setTree(&after_split); + + // Re-bind vital properties like `is-split` + source.bindIsSplit(self); } } diff --git a/src/apprt/gtk/class/surface.zig b/src/apprt/gtk/class/surface.zig index e9aea6d51..cc7726617 100644 --- a/src/apprt/gtk/class/surface.zig +++ b/src/apprt/gtk/class/surface.zig @@ -691,6 +691,7 @@ pub const Surface = extern struct { // True if the current surface is a split, this is used to apply // unfocused-split-* options is_split: bool = false, + is_split_binding: ?*gobject.Binding = null, action_group: ?*gio.SimpleActionGroup = null, @@ -847,6 +848,18 @@ pub const Surface = extern struct { return @intFromBool(config.@"bell-features".border); } + pub fn bindIsSplit(self: *Self, tree: *SplitTree) void { + const priv = self.private(); + if (priv.is_split_binding) |bind| bind.unbind(); + + priv.is_split_binding = tree.as(gobject.Object).bindProperty( + "is-split", + self.as(gobject.Object), + "is-split", + .{ .sync_create = true }, + ); + } + /// Callback used to determine whether unfocused-split-fill / unfocused-split-opacity /// should be applied to the surface fn closureShouldUnfocusedSplitBeShown( @@ -3650,6 +3663,21 @@ pub const Surface = extern struct { }; } + fn closureShouldDragHandleBeShown( + _: *Self, + config_: ?*Config, + is_split: c_int, + ) callconv(.c) c_int { + const config = config_ orelse return @intFromBool(false); + + const shown = switch (config.get().@"drag-handle") { + .always => true, + .auto => is_split != 0, + .never => false, + }; + return @intFromBool(shown); + } + fn surfaceDragPrepare( src: *gtk.DragSource, x: f64, @@ -3722,7 +3750,6 @@ pub const Surface = extern struct { const dropped = self.core().?.app.findSurfaceByID(dropped_id) orelse return; const from = dropped.rt_surface.gobj(); - // TODO: Find a better way to access the split tree from here const st = ext.getAncestor( SplitTree, self.as(gtk.Widget), @@ -3892,6 +3919,7 @@ pub const Surface = extern struct { class.bindTemplateCallback("search_changed", &searchChanged); class.bindTemplateCallback("search_next_match", &searchNextMatch); class.bindTemplateCallback("search_previous_match", &searchPreviousMatch); + class.bindTemplateCallback("should_drag_handle_be_shown", &closureShouldDragHandleBeShown); class.bindTemplateCallback("surface_drag_prepare", &surfaceDragPrepare); class.bindTemplateCallback("surface_drag_begin", &surfaceDragBegin); class.bindTemplateCallback("surface_drop", &surfaceDrop); diff --git a/src/apprt/gtk/ui/1.2/surface.blp b/src/apprt/gtk/ui/1.2/surface.blp index b7d07cb3e..fc14fd3b5 100644 --- a/src/apprt/gtk/ui/1.2/surface.blp +++ b/src/apprt/gtk/ui/1.2/surface.blp @@ -232,6 +232,7 @@ Overlay terminal_page { CenterBox drag_handle { halign: fill; valign: start; + visible: bind $should_drag_handle_be_shown(template.config, template.is-split) as ; styles [ "drag-handle", diff --git a/src/config/Config.zig b/src/config/Config.zig index 7fa282437..b96300d14 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -2345,6 +2345,30 @@ keybind: Keybinds = .{}, /// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color. @"window-titlebar-foreground": ?Color = null, +/// Controls when drag handles are shown over splits, +/// allowing splits to be rearranged with mouse controls. +/// +/// Valid values: +/// +/// - `always` +/// +/// Always display the drag handle, even when there's only one split. +/// +/// - `auto` *(default)* +/// +/// Automatically show and hide the drag handle. The handle is only +/// shown when there are two or more splits present. +/// +/// - `never` +/// +/// Never show the drag handle. Splits then cannot be rearranged with +/// mouse controls. +/// +/// Available since: 1.4.0. +/// +/// Currently only supported on Linux (GTK). +@"drag-handle": DragHandle = .auto, + /// This controls when resize overlays are shown. Resize overlays are a /// transient popup that shows the size of the terminal while the surfaces are /// being resized. The possible options are: @@ -9297,6 +9321,13 @@ pub const WindowShowTabBar = enum { never, }; +/// See drag-handle +pub const DragHandle = enum { + always, + auto, + never, +}; + /// See resize-overlay pub const ResizeOverlay = enum { always,