diff --git a/src/apprt/gtk/Paned.zig b/src/apprt/gtk/Paned.zig index e94a494fc..977ffc3dd 100644 --- a/src/apprt/gtk/Paned.zig +++ b/src/apprt/gtk/Paned.zig @@ -75,7 +75,7 @@ pub fn init(self: *Paned, window: *Window, sibling: *Surface, direction: input.S self.addChild2(.{ .surface = surface }); } -pub fn newSurface(self: *Paned, tab: *Tab, parent_: ?*CoreSurface) !*Surface { +fn newSurface(self: *Paned, tab: *Tab, parent_: ?*CoreSurface) !*Surface { // Grab a surface allocation we'll need it later. var surface = try self.window.app.core_app.alloc.create(Surface); errdefer self.window.app.core_app.alloc.destroy(surface); @@ -110,16 +110,19 @@ pub fn newSurface(self: *Paned, tab: *Tab, parent_: ?*CoreSurface) !*Surface { return surface; } +/// Set the parent of Paned. pub fn setParent(self: *Paned, parent: Parent) void { self.parent = parent; } +/// Focus on the Surface's gl_area in the given position. pub fn focusSurfaceInPosition(self: *Paned, position: Position) void { const surface: *Surface = self.surfaceInPosition(position) orelse return; const widget = @as(*c.GtkWidget, @ptrCast(surface.gl_area)); _ = c.gtk_widget_grab_focus(widget); } +/// Split the Surface in the given position into a Paned with two surfaces. pub fn splitSurfaceInPosition(self: *Paned, position: Position, direction: input.SplitDirection) !void { const surface: *Surface = self.surfaceInPosition(position) orelse return; @@ -148,6 +151,7 @@ pub fn splitSurfaceInPosition(self: *Paned, position: Position, direction: input paned.focusSurfaceInPosition(.end); } +/// Replace the existing .start or .end Child with the given new Child. pub fn replaceChildInPosition(self: *Paned, child: Child, position: Position) void { // Keep position of divider const parent_paned_position_before = c.gtk_paned_get_position(self.paned); @@ -167,11 +171,25 @@ pub fn replaceChildInPosition(self: *Paned, child: Child, position: Position) vo c.gtk_paned_set_position(self.paned, parent_paned_position_before); } +/// Remove both children, setting *c.GtkPaned start/end children to null. pub fn removeChildren(self: *Paned) void { self.removeChildInPosition(.start); self.removeChildInPosition(.end); } +/// Deinit the Paned by deiniting its child Paneds, if they exist. +pub fn deinit(self: *Paned, alloc: Allocator) void { + for ([_]Child{ self.child1, self.child2 }) |child| { + switch (child) { + .none, .surface => continue, + .paned => |paned| { + paned.deinit(alloc); + alloc.destroy(paned); + }, + } + } +} + fn removeChildInPosition(self: *Paned, position: Position) void { switch (position) { .start => { @@ -218,15 +236,3 @@ fn surfaceInPosition(self: *Paned, position: Position) ?*Surface { else => null, }; } - -pub fn deinit(self: *Paned, alloc: Allocator) void { - for ([_]Child{ self.child1, self.child2 }) |child| { - switch (child) { - .none, .surface => continue, - .paned => |paned| { - paned.deinit(alloc); - alloc.destroy(paned); - }, - } - } -} diff --git a/src/apprt/gtk/Tab.zig b/src/apprt/gtk/Tab.zig index cf604c792..cdd5e2b45 100644 --- a/src/apprt/gtk/Tab.zig +++ b/src/apprt/gtk/Tab.zig @@ -158,12 +158,6 @@ pub fn setChild(self: *Tab, child: Child) void { self.child = child; } -fn gtkTabCloseClick(_: *c.GtkButton, ud: ?*anyopaque) callconv(.C) void { - const tab: *Tab = @ptrCast(@alignCast(ud)); - const window = tab.window; - window.closeTab(tab); -} - pub fn deinit(self: *Tab) void { switch (self.child) { .none, .surface => return, @@ -173,3 +167,9 @@ pub fn deinit(self: *Tab) void { }, } } + +fn gtkTabCloseClick(_: *c.GtkButton, ud: ?*anyopaque) callconv(.C) void { + const tab: *Tab = @ptrCast(@alignCast(ud)); + const window = tab.window; + window.closeTab(tab); +} diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index 9e3a28937..ae5efda43 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -15,6 +15,7 @@ const App = @import("App.zig"); const Paned = @import("Paned.zig"); const Surface = @import("Surface.zig"); const Tab = @import("Tab.zig"); +const Position = @import("relation.zig").Position; const icon = @import("icon.zig"); const c = @import("c.zig"); @@ -213,7 +214,6 @@ pub fn removeTab(self: *Window, tab: *Tab) !void { if (t == tab) break i; } else null; - // TODO: Shrink capacity? if (tab_idx) |idx| _ = self.tabs.orderedRemove(idx) else return error.TabNotFound; // Deallocate the tab @@ -256,8 +256,6 @@ pub fn closeTab(self: *Window, tab: *Tab) void { pub fn closeSurface(self: *Window, surface: *Surface) void { assert(surface.window == self); - const alloc = self.app.core_app.alloc; - switch (surface.parent) { .none => unreachable, .tab => |tab| self.closeTab(tab), @@ -265,56 +263,60 @@ pub fn closeSurface(self: *Window, surface: *Surface) void { const paned = paned_tuple[0]; const position = paned_tuple[1]; - const sibling = switch (position) { - .start => .{ - paned.child2, - c.gtk_paned_get_end_child(paned.paned), - }, - .end => .{ - paned.child1, - c.gtk_paned_get_start_child(paned.paned), - }, - }; - // TODO: Use destructuring syntax once it doesn't break ZLS - const sibling_child = sibling[0]; - const sibling_widget = sibling[1]; - - // Keep explicit reference to sibling's gl_area, so it's not - // destroyed when we remove it from GtkPaned. - const sibling_object: *c.GObject = @ptrCast(sibling_widget); - _ = c.g_object_ref(sibling_object); - defer c.g_object_unref(sibling_object); - - // Remove reference on the surface we're closing - surface.setParent(.none); - - // Remove children. - paned.removeChildren(); - // Don't need to call paned.deinit, because we already removed children. - defer alloc.destroy(paned); - - switch (paned.parent) { - .none => unreachable, - .tab => |tab| { - // If parent of Paned we belong to is a tab, we can - // replace the child with the other surface - tab.removeChild(); - tab.setChild(sibling_child); - }, - .paned => |parent_paned_tuple| { - const parent_paned = parent_paned_tuple[0]; - const parent_paned_position = parent_paned_tuple[1]; - - parent_paned.replaceChildInPosition(sibling_child, parent_paned_position); - }, - } - - const widget = @as(*c.GtkWidget, @ptrCast(sibling_widget)); - _ = c.gtk_widget_grab_focus(widget); + self.closeSurfaceInPaned(surface, paned, position); }, } } +fn closeSurfaceInPaned(self: *Window, surface: *Surface, paned: *Paned, position: Position) void { + const sibling = switch (position) { + .start => .{ + paned.child2, + c.gtk_paned_get_end_child(paned.paned), + }, + .end => .{ + paned.child1, + c.gtk_paned_get_start_child(paned.paned), + }, + }; + // TODO: Use destructuring syntax once it doesn't break ZLS + const sibling_child = sibling[0]; + const sibling_widget = sibling[1]; + + // Keep explicit reference to sibling's gl_area, so it's not + // destroyed when we remove it from GtkPaned. + const sibling_object: *c.GObject = @ptrCast(sibling_widget); + _ = c.g_object_ref(sibling_object); + defer c.g_object_unref(sibling_object); + + // Remove reference on the surface we're closing + surface.setParent(.none); + + // Remove children. + paned.removeChildren(); + // Don't need to call paned.deinit, because we already removed children. + defer self.app.core_app.alloc.destroy(paned); + + switch (paned.parent) { + .none => unreachable, + .tab => |tab| { + // If parent of Paned we belong to is a tab, we can + // replace the child with the other surface + tab.removeChild(); + tab.setChild(sibling_child); + }, + .paned => |parent_paned_tuple| { + const parent_paned = parent_paned_tuple[0]; + const parent_paned_position = parent_paned_tuple[1]; + + parent_paned.replaceChildInPosition(sibling_child, parent_paned_position); + }, + } + + const widget = @as(*c.GtkWidget, @ptrCast(sibling_widget)); + _ = c.gtk_widget_grab_focus(widget); +} + /// Returns true if this window has any tabs. pub fn hasTabs(self: *const Window) bool { return c.gtk_notebook_get_n_pages(self.notebook) > 1;