mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 16:26:08 +03:00
gtk: fix replacing of splits, remove dead code
This commit is contained in:

committed by
Mitchell Hashimoto

parent
ecbe910714
commit
8cf9d97ac3
@ -1,205 +0,0 @@
|
||||
const Paned = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const font = @import("../../font/main.zig");
|
||||
const input = @import("../../input.zig");
|
||||
const CoreSurface = @import("../../Surface.zig");
|
||||
|
||||
const Window = @import("Window.zig");
|
||||
const Surface = @import("Surface.zig");
|
||||
const Tab = @import("Tab.zig");
|
||||
const Position = @import("relation.zig").Position;
|
||||
const Parent = @import("relation.zig").Parent;
|
||||
const Child = @import("relation.zig").Child;
|
||||
const c = @import("c.zig");
|
||||
|
||||
const log = std.log.scoped(.gtk);
|
||||
|
||||
/// Our actual GtkPaned widget
|
||||
paned: *c.GtkPaned,
|
||||
|
||||
// We have two children, each of which can be either a Surface, another pane,
|
||||
// or empty. We're going to keep track of which each child is here.
|
||||
child1: Child,
|
||||
child2: Child,
|
||||
|
||||
// We also hold a reference to our parent widget, so that when we close we can either
|
||||
// maximize the parent pane, or close the tab.
|
||||
parent: Parent,
|
||||
|
||||
pub fn create(alloc: Allocator, sibling: *Surface, direction: input.SplitDirection) !*Paned {
|
||||
var paned = try alloc.create(Paned);
|
||||
errdefer alloc.destroy(paned);
|
||||
try paned.init(sibling, direction);
|
||||
return paned;
|
||||
}
|
||||
|
||||
pub fn init(self: *Paned, sibling: *Surface, direction: input.SplitDirection) !void {
|
||||
self.* = .{
|
||||
.paned = undefined,
|
||||
.child1 = .none,
|
||||
.child2 = .none,
|
||||
.parent = undefined,
|
||||
};
|
||||
errdefer self.* = undefined;
|
||||
|
||||
const orientation: c_uint = switch (direction) {
|
||||
.right => c.GTK_ORIENTATION_HORIZONTAL,
|
||||
.down => c.GTK_ORIENTATION_VERTICAL,
|
||||
};
|
||||
|
||||
const paned = c.gtk_paned_new(orientation);
|
||||
errdefer c.g_object_unref(paned);
|
||||
|
||||
const gtk_paned: *c.GtkPaned = @ptrCast(paned);
|
||||
self.paned = gtk_paned;
|
||||
|
||||
const alloc = sibling.app.core_app.alloc;
|
||||
var surface = try Surface.create(alloc, sibling.app, .{
|
||||
.parent2 = &sibling.core_surface,
|
||||
.parent = .{ .paned = .{ self, .end } },
|
||||
});
|
||||
errdefer surface.destroy(alloc);
|
||||
surface.container = sibling.container; // TODO
|
||||
|
||||
self.addChild1(.{ .surface = sibling });
|
||||
self.addChild2(.{ .surface = surface });
|
||||
}
|
||||
|
||||
/// Set the parent of Paned.
|
||||
pub fn setParent(self: *Paned, parent: Parent) void {
|
||||
self.parent = parent;
|
||||
}
|
||||
|
||||
/// Focus on first Surface that can be found in given position. If there's a
|
||||
/// Paned in the position, it will focus on the first surface in that position.
|
||||
pub fn focusFirstSurfaceInPosition(self: *Paned, position: Position) void {
|
||||
const child = self.childInPosition(position);
|
||||
switch (child) {
|
||||
.surface => |s| s.grabFocus(),
|
||||
.paned => |p| p.focusFirstSurfaceInPosition(position),
|
||||
.none => {
|
||||
log.warn("attempted to focus on first surface, found none", .{});
|
||||
return;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// 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;
|
||||
|
||||
// Keep explicit reference to surface gl_area before we remove it.
|
||||
const object: *c.GObject = @ptrCast(surface.gl_area);
|
||||
_ = c.g_object_ref(object);
|
||||
defer c.g_object_unref(object);
|
||||
|
||||
// Keep position of divider
|
||||
const parent_paned_position_before = c.gtk_paned_get_position(self.paned);
|
||||
// Now remove it
|
||||
self.removeChildInPosition(position);
|
||||
|
||||
// Create new Paned
|
||||
// NOTE: We cannot use `replaceChildInPosition` here because we need to
|
||||
// first remove the surface before we create a new pane.
|
||||
const paned = try Paned.create(surface.app.core_app.alloc, surface, direction);
|
||||
switch (position) {
|
||||
.start => self.addChild1(.{ .paned = paned }),
|
||||
.end => self.addChild2(.{ .paned = paned }),
|
||||
}
|
||||
// Restore position
|
||||
c.gtk_paned_set_position(self.paned, parent_paned_position_before);
|
||||
|
||||
// Focus on new surface
|
||||
paned.focusFirstSurfaceInPosition(.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);
|
||||
|
||||
// Focus on the sibling, otherwise we'll get a GTK warning
|
||||
self.focusFirstSurfaceInPosition(if (position == .start) .end else .start);
|
||||
|
||||
// Now we can remove the other one
|
||||
self.removeChildInPosition(position);
|
||||
|
||||
switch (position) {
|
||||
.start => self.addChild1(child),
|
||||
.end => self.addChild2(child),
|
||||
}
|
||||
|
||||
// Restore position
|
||||
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 => {
|
||||
assert(self.child1 != .none);
|
||||
self.child1 = .none;
|
||||
c.gtk_paned_set_start_child(@ptrCast(self.paned), null);
|
||||
},
|
||||
.end => {
|
||||
assert(self.child2 != .none);
|
||||
self.child2 = .none;
|
||||
c.gtk_paned_set_end_child(@ptrCast(self.paned), null);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn addChild1(self: *Paned, child: Child) void {
|
||||
assert(self.child1 == .none);
|
||||
|
||||
const widget = child.widget() orelse return;
|
||||
c.gtk_paned_set_start_child(@ptrCast(self.paned), widget);
|
||||
|
||||
self.child1 = child;
|
||||
child.setParent(.{ .paned = .{ self, .start } });
|
||||
}
|
||||
|
||||
fn addChild2(self: *Paned, child: Child) void {
|
||||
assert(self.child2 == .none);
|
||||
|
||||
const widget = child.widget() orelse return;
|
||||
c.gtk_paned_set_end_child(@ptrCast(self.paned), widget);
|
||||
|
||||
self.child2 = child;
|
||||
child.setParent(.{ .paned = .{ self, .end } });
|
||||
}
|
||||
|
||||
fn childInPosition(self: *Paned, position: Position) Child {
|
||||
return switch (position) {
|
||||
.start => self.child1,
|
||||
.end => self.child2,
|
||||
};
|
||||
}
|
||||
|
||||
fn surfaceInPosition(self: *Paned, position: Position) ?*Surface {
|
||||
return switch (self.childInPosition(position)) {
|
||||
.surface => |surface| surface,
|
||||
else => null,
|
||||
};
|
||||
}
|
@ -11,8 +11,6 @@ const CoreSurface = @import("../../Surface.zig");
|
||||
|
||||
const Surface = @import("Surface.zig");
|
||||
const Tab = @import("Tab.zig");
|
||||
const Position = @import("relation.zig").Position;
|
||||
const Child = @import("relation.zig").Child;
|
||||
const c = @import("c.zig");
|
||||
|
||||
const log = std.log.scoped(.gtk);
|
||||
@ -92,113 +90,38 @@ pub fn init(
|
||||
surface.grabFocus();
|
||||
}
|
||||
|
||||
/// Focus on first Surface that can be found in given position. If there's a
|
||||
/// Split in the position, it will focus on the first surface in that position.
|
||||
pub fn focusFirstSurfaceInPosition(self: *Split, position: Position) void {
|
||||
const child = self.childInPosition(position);
|
||||
switch (child) {
|
||||
.surface => |s| s.grabFocus(),
|
||||
.paned => |p| p.focusFirstSurfaceInPosition(position),
|
||||
.none => {
|
||||
log.warn("attempted to focus on first surface, found none", .{});
|
||||
return;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Split the Surface in the given position into a Split with two surfaces.
|
||||
pub fn splitSurfaceInPosition(self: *Split, position: Position, direction: input.SplitDirection) !void {
|
||||
const surface: *Surface = self.surfaceInPosition(position) orelse return;
|
||||
|
||||
// Keep explicit reference to surface gl_area before we remove it.
|
||||
const object: *c.GObject = @ptrCast(surface.gl_area);
|
||||
_ = c.g_object_ref(object);
|
||||
defer c.g_object_unref(object);
|
||||
|
||||
// Keep position of divider
|
||||
const parent_paned_position_before = c.gtk_paned_get_position(self.paned);
|
||||
// Now remove it
|
||||
self.removeChildInPosition(position);
|
||||
|
||||
// Create new Split
|
||||
// NOTE: We cannot use `replaceChildInPosition` here because we need to
|
||||
// first remove the surface before we create a new pane.
|
||||
const paned = try Split.create(surface.app.core_app.alloc, surface, direction);
|
||||
switch (position) {
|
||||
.start => self.addChild1(.{ .paned = paned }),
|
||||
.end => self.addChild2(.{ .paned = paned }),
|
||||
}
|
||||
// Restore position
|
||||
c.gtk_paned_set_position(self.paned, parent_paned_position_before);
|
||||
|
||||
// Focus on new surface
|
||||
paned.focusFirstSurfaceInPosition(.end);
|
||||
}
|
||||
|
||||
/// Replace the existing .start or .end Child with the given new Child.
|
||||
pub fn replaceChildInPosition(self: *Split, child: Child, position: Position) void {
|
||||
// Keep position of divider
|
||||
const parent_paned_position_before = c.gtk_paned_get_position(self.paned);
|
||||
|
||||
// Focus on the sibling, otherwise we'll get a GTK warning
|
||||
self.focusFirstSurfaceInPosition(if (position == .start) .end else .start);
|
||||
|
||||
// Now we can remove the other one
|
||||
self.removeChildInPosition(position);
|
||||
|
||||
switch (position) {
|
||||
.start => self.addChild1(child),
|
||||
.end => self.addChild2(child),
|
||||
}
|
||||
|
||||
// Restore position
|
||||
c.gtk_paned_set_position(self.paned, parent_paned_position_before);
|
||||
}
|
||||
|
||||
/// Remove both children, setting *c.GtkSplit start/end children to null.
|
||||
// pub fn removeChildren(self: *Split) void {
|
||||
// self.removeChildInPosition(.start);
|
||||
// self.removeChildInPosition(.end);
|
||||
//}
|
||||
|
||||
/// Deinit the Split by deiniting its child Split, if they exist.
|
||||
pub fn deinit(self: *Split, 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: *Split, position: Position) void {
|
||||
switch (position) {
|
||||
.start => {
|
||||
assert(self.child1 != .none);
|
||||
self.child1 = .none;
|
||||
c.gtk_paned_set_start_child(@ptrCast(self.paned), null);
|
||||
},
|
||||
.end => {
|
||||
assert(self.child2 != .none);
|
||||
self.child2 = .none;
|
||||
c.gtk_paned_set_end_child(@ptrCast(self.paned), null);
|
||||
},
|
||||
}
|
||||
/// Remove the top left child.
|
||||
pub fn removeTopLeft(self: *Split) void {
|
||||
self.removeChild(self.top_left, self.bottom_right);
|
||||
}
|
||||
|
||||
/// Remove the top left child.
|
||||
pub fn removeTopLeft(self: *Split) void {
|
||||
pub fn removeBottomRight(self: *Split) void {
|
||||
self.removeChild(self.bottom_right, self.top_left);
|
||||
}
|
||||
|
||||
// TODO: Is this Zig-y?
|
||||
inline fn removeChild(self: *Split, remove: Surface.Container.Elem, keep: Surface.Container.Elem) void {
|
||||
const window = self.container.window() orelse return;
|
||||
|
||||
// TODO: Grab focus
|
||||
|
||||
// Keep a reference to the side that we want to keep, so it doesn't get
|
||||
// destroyed when it's removed from our underlying GtkPaned.
|
||||
const keep_object: *c.GObject = @ptrCast(keep.widget());
|
||||
_ = c.g_object_ref(keep_object);
|
||||
defer c.g_object_unref(keep_object);
|
||||
|
||||
// Remove our children since we are going to no longer be
|
||||
// a split anyways. This prevents widgets with multiple parents.
|
||||
self.removeChildren();
|
||||
|
||||
// Our container must become whatever our bottom right is
|
||||
self.container.replace(self.bottom_right);
|
||||
// Our container must become whatever our top left is
|
||||
self.container.replace(keep);
|
||||
|
||||
// TODO: memory management of top left
|
||||
// TODO: is this correct?
|
||||
remove.shutdown();
|
||||
window.app.core_app.alloc.destroy(self);
|
||||
}
|
||||
|
||||
// TODO: ehhhhhh
|
||||
@ -242,37 +165,3 @@ fn removeChildren(self: *const Split) void {
|
||||
c.gtk_paned_set_start_child(@ptrCast(self.paned), null);
|
||||
c.gtk_paned_set_end_child(@ptrCast(self.paned), null);
|
||||
}
|
||||
|
||||
fn addChild1(self: *Split, child: Child) void {
|
||||
assert(self.child1 == .none);
|
||||
|
||||
const widget = child.widget() orelse return;
|
||||
c.gtk_paned_set_start_child(@ptrCast(self.paned), widget);
|
||||
|
||||
self.child1 = child;
|
||||
child.setParent(.{ .paned = .{ self, .start } });
|
||||
}
|
||||
|
||||
fn addChild2(self: *Split, child: Child) void {
|
||||
assert(self.child2 == .none);
|
||||
|
||||
const widget = child.widget() orelse return;
|
||||
c.gtk_paned_set_end_child(@ptrCast(self.paned), widget);
|
||||
|
||||
self.child2 = child;
|
||||
child.setParent(.{ .paned = .{ self, .end } });
|
||||
}
|
||||
|
||||
fn childInPosition(self: *Split, position: Position) Child {
|
||||
return switch (position) {
|
||||
.start => self.child1,
|
||||
.end => self.child2,
|
||||
};
|
||||
}
|
||||
|
||||
fn surfaceInPosition(self: *Split, position: Position) ?*Surface {
|
||||
return switch (self.childInPosition(position)) {
|
||||
.surface => |surface| surface,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ const Split = @import("Split.zig");
|
||||
const Tab = @import("Tab.zig");
|
||||
const Window = @import("Window.zig");
|
||||
const ClipboardConfirmationWindow = @import("ClipboardConfirmationWindow.zig");
|
||||
const Parent = @import("relation.zig").Parent;
|
||||
const inspector = @import("inspector.zig");
|
||||
const gtk_key = @import("key.zig");
|
||||
const c = @import("c.zig");
|
||||
@ -79,6 +78,22 @@ pub const Container = union(enum) {
|
||||
.split => |s| &s.container,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn shutdown(self: Elem) void {
|
||||
switch (self) {
|
||||
.surface => |s| s.shutdown(),
|
||||
.split => {
|
||||
@panic("TODO: shutdownsplit");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn debugName(self: Elem) []const u8 {
|
||||
return switch (self) {
|
||||
.surface => "surface",
|
||||
.split => "split",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Returns the window that this surface is attached to.
|
||||
@ -119,10 +134,14 @@ pub const Container = union(enum) {
|
||||
/// from a surface to a split or a split back to a surface or
|
||||
/// a split to a nested split and so on.
|
||||
pub fn replace(self: Container, elem: Elem) void {
|
||||
log.debug("Container.replace. self={s}, elem={s}", .{ self.debugName(), elem.debugName() });
|
||||
|
||||
// Move the element into the container
|
||||
switch (self) {
|
||||
.none => {},
|
||||
.tab_ => |t| t.replaceElem(elem),
|
||||
.tab_ => |t| {
|
||||
t.replaceElem(elem);
|
||||
},
|
||||
inline .split_tl, .split_br => |ptr| {
|
||||
const s = self.split().?;
|
||||
s.replace(ptr, elem);
|
||||
@ -137,13 +156,23 @@ pub const Container = union(enum) {
|
||||
/// children to effectively notify they're containing that
|
||||
/// all children at this level are exiting.
|
||||
pub fn remove(self: Container) void {
|
||||
log.warn("Container.remove", .{});
|
||||
switch (self) {
|
||||
.none => {},
|
||||
.tab_ => |t| t.closeElem(),
|
||||
.split_tl => self.split().?.removeTopLeft(),
|
||||
else => @panic("TOOD"),
|
||||
.split_br => self.split().?.removeBottomRight(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn debugName(self: Container) []const u8 {
|
||||
return switch (self) {
|
||||
.none => "none",
|
||||
.tab_ => "tab",
|
||||
.split_tl => "split_tl",
|
||||
.split_br => "split_br",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Whether the surface has been realized or not yet. When a surface is
|
||||
@ -664,10 +693,6 @@ pub fn setTitle(self: *Surface, slice: [:0]const u8) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setParent(self: *Surface, parent: Parent) void {
|
||||
self.parent = parent;
|
||||
}
|
||||
|
||||
pub fn setMouseShape(
|
||||
self: *Surface,
|
||||
shape: terminal.MouseShape,
|
||||
|
@ -10,9 +10,6 @@ const font = @import("../../font/main.zig");
|
||||
const input = @import("../../input.zig");
|
||||
const CoreSurface = @import("../../Surface.zig");
|
||||
|
||||
const Paned = @import("Paned.zig");
|
||||
const Parent = @import("relation.zig").Parent;
|
||||
const Child = @import("relation.zig").Child;
|
||||
const Surface = @import("Surface.zig");
|
||||
const Window = @import("Window.zig");
|
||||
const c = @import("c.zig");
|
||||
@ -34,9 +31,6 @@ box: *c.GtkBox,
|
||||
/// The element of this tab so that we can handle splits and so on.
|
||||
elem: Surface.Container.Elem,
|
||||
|
||||
// The child can be either a Surface if the tab is not split or a Paned
|
||||
child: Child,
|
||||
|
||||
// We'll update this every time a Surface gains focus, so that we have it
|
||||
// when we switch to another Tab. Then when we switch back to this tab, we
|
||||
// can easily re-focus that terminal.
|
||||
@ -57,7 +51,6 @@ pub fn init(self: *Tab, window: *Window, parent_: ?*CoreSurface) !void {
|
||||
.label_text = undefined,
|
||||
.box = undefined,
|
||||
.elem = undefined,
|
||||
.child = undefined,
|
||||
.focus_child = undefined,
|
||||
};
|
||||
|
||||
@ -93,7 +86,7 @@ pub fn init(self: *Tab, window: *Window, parent_: ?*CoreSurface) !void {
|
||||
c.gtk_widget_set_size_request(label_text_widget, 100, 1);
|
||||
}
|
||||
|
||||
// Create a Box in which we'll later keep either Surface or Paned
|
||||
// Create a Box in which we'll later keep either Surface or Split
|
||||
const box_widget = c.gtk_box_new(c.GTK_ORIENTATION_VERTICAL, 0);
|
||||
c.gtk_widget_set_hexpand(box_widget, 1);
|
||||
c.gtk_widget_set_vexpand(box_widget, 1);
|
||||
@ -105,7 +98,6 @@ pub fn init(self: *Tab, window: *Window, parent_: ?*CoreSurface) !void {
|
||||
});
|
||||
errdefer surface.destroy(window.app.core_app.alloc);
|
||||
surface.setContainer(.{ .tab_ = self });
|
||||
self.child = .{ .surface = surface };
|
||||
self.elem = .{ .surface = surface };
|
||||
|
||||
// Add Surface to the Tab
|
||||
@ -148,29 +140,16 @@ pub fn init(self: *Tab, window: *Window, parent_: ?*CoreSurface) !void {
|
||||
surface.grabFocus();
|
||||
}
|
||||
|
||||
/// Deinits tab by deiniting child if child is Paned.
|
||||
/// Deinits tab by deiniting child elem.
|
||||
pub fn deinit(self: *Tab) void {
|
||||
switch (self.child) {
|
||||
.none => return,
|
||||
.surface => |s| s.shutdown(),
|
||||
.paned => |paned| {
|
||||
paned.deinit(self.window.app.core_app.alloc);
|
||||
self.window.app.core_app.alloc.destroy(paned);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove the current child from the Tab. Noop if no child set.
|
||||
pub fn removeChild(self: *Tab) void {
|
||||
const widget = self.child.widget() orelse return;
|
||||
c.gtk_box_remove(self.box, widget);
|
||||
|
||||
self.child = .none;
|
||||
self.elem.shutdown();
|
||||
}
|
||||
|
||||
// TODO: move this
|
||||
/// Replace the surface element that this tab is showing.
|
||||
pub fn replaceElem(self: *Tab, elem: Surface.Container.Elem) void {
|
||||
// _ = c.g_object_ref_sink(self.elem.widget());
|
||||
|
||||
// Remove our previous widget
|
||||
c.gtk_box_remove(self.box, self.elem.widget());
|
||||
|
||||
@ -186,15 +165,6 @@ pub fn closeElem(self: *Tab) void {
|
||||
self.window.closeTab(self);
|
||||
}
|
||||
|
||||
/// Sets child to given child and sets parent on child.
|
||||
pub fn setChild(self: *Tab, child: Child) void {
|
||||
const widget = child.widget() orelse return;
|
||||
c.gtk_box_append(self.box, widget);
|
||||
|
||||
child.setParent(.{ .tab = self });
|
||||
self.child = child;
|
||||
}
|
||||
|
||||
fn gtkTabCloseClick(_: *c.GtkButton, ud: ?*anyopaque) callconv(.C) void {
|
||||
const tab: *Tab = @ptrCast(@alignCast(ud));
|
||||
const window = tab.window;
|
||||
|
@ -16,10 +16,8 @@ const input = @import("../../input.zig");
|
||||
const CoreSurface = @import("../../Surface.zig");
|
||||
|
||||
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");
|
||||
|
||||
@ -256,75 +254,6 @@ pub fn closeTab(self: *Window, tab: *Tab) void {
|
||||
if (remaining > 0) self.focusCurrentTab();
|
||||
}
|
||||
|
||||
/// Close the surface. This surface must be definitely part of this window.
|
||||
pub fn closeSurface(self: *Window, surface: *Surface) void {
|
||||
assert(surface.container.window().? == self);
|
||||
|
||||
// TODO: fixme
|
||||
// switch (surface.parent) {
|
||||
// .none => unreachable,
|
||||
// .tab => |tab| self.closeTab(tab),
|
||||
// .paned => |paned_tuple| {
|
||||
// const paned = paned_tuple[0];
|
||||
// const position = paned_tuple[1];
|
||||
//
|
||||
// self.closeSurfaceInPaned(surface, paned, position);
|
||||
// },
|
||||
// }
|
||||
}
|
||||
|
||||
fn closeSurfaceInPaned(self: *Window, surface: *Surface, paned: *Paned, position: Position) void {
|
||||
const sibling_child, const sibling_widget = switch (position) {
|
||||
.start => .{
|
||||
paned.child2,
|
||||
c.gtk_paned_get_end_child(paned.paned),
|
||||
},
|
||||
.end => .{
|
||||
paned.child1,
|
||||
c.gtk_paned_get_start_child(paned.paned),
|
||||
},
|
||||
};
|
||||
|
||||
// Keep explicit reference to sibling's widget (gl_area, or Paned), 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);
|
||||
},
|
||||
}
|
||||
|
||||
switch (sibling_child) {
|
||||
.surface => |s| s.grabFocus(),
|
||||
.paned => |p| {
|
||||
// Focus on first surface in sibling Paned
|
||||
p.focusFirstSurfaceInPosition(position);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
/// 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;
|
||||
|
@ -1,40 +0,0 @@
|
||||
const Surface = @import("Surface.zig");
|
||||
const Paned = @import("Paned.zig");
|
||||
const Tab = @import("Tab.zig");
|
||||
const c = @import("c.zig");
|
||||
|
||||
pub const Position = enum {
|
||||
start,
|
||||
end,
|
||||
};
|
||||
|
||||
pub const Parent = union(enum) {
|
||||
none,
|
||||
tab: *Tab,
|
||||
paned: struct {
|
||||
*Paned,
|
||||
Position,
|
||||
},
|
||||
};
|
||||
|
||||
pub const Child = union(enum) {
|
||||
none,
|
||||
surface: *Surface,
|
||||
paned: *Paned,
|
||||
|
||||
pub fn setParent(self: Child, parent: Parent) void {
|
||||
switch (self) {
|
||||
.none => return,
|
||||
.surface => |surface| surface.setParent(parent),
|
||||
.paned => |paned| paned.setParent(parent),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn widget(self: Child) ?*c.GtkWidget {
|
||||
return switch (self) {
|
||||
.none => null,
|
||||
.paned => |paned| @ptrCast(@alignCast(paned.paned)),
|
||||
.surface => |surface| @ptrCast(surface.gl_area),
|
||||
};
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user