mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-23 04:06:13 +03:00
apprt/gkt: a lot of things are broken
This commit is contained in:
@ -12,7 +12,6 @@ const CoreSurface = @import("../../Surface.zig");
|
|||||||
const Surface = @import("Surface.zig");
|
const Surface = @import("Surface.zig");
|
||||||
const Tab = @import("Tab.zig");
|
const Tab = @import("Tab.zig");
|
||||||
const Position = @import("relation.zig").Position;
|
const Position = @import("relation.zig").Position;
|
||||||
const Parent = @import("relation.zig").Parent;
|
|
||||||
const Child = @import("relation.zig").Child;
|
const Child = @import("relation.zig").Child;
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig");
|
||||||
|
|
||||||
@ -25,27 +24,8 @@ paned: *c.GtkPaned,
|
|||||||
container: Surface.Container,
|
container: Surface.Container,
|
||||||
|
|
||||||
/// The elements of this split panel.
|
/// The elements of this split panel.
|
||||||
top_left: Elem,
|
top_left: Surface.Container.Elem,
|
||||||
bottom_right: Elem,
|
bottom_right: Surface.Container.Elem,
|
||||||
|
|
||||||
/// Elem is the possible element of the split.
|
|
||||||
pub const Elem = union(enum) {
|
|
||||||
/// A surface is a leaf element of the split -- a terminal surface.
|
|
||||||
surface: *Surface,
|
|
||||||
|
|
||||||
/// A split is a nested split within a split. This lets you for example
|
|
||||||
/// have a horizontal split with a vertical split on the left side
|
|
||||||
/// (amongst all other possible combinations).
|
|
||||||
split: *Split,
|
|
||||||
|
|
||||||
/// Returns the GTK widget to add to the paned for the given element
|
|
||||||
pub fn widget(self: Child) *c.GtkWidget {
|
|
||||||
return switch (self) {
|
|
||||||
.surface => |surface| @ptrCast(surface.gl_area),
|
|
||||||
.split => |split| @ptrCast(@alignCast(split.paned)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Create a new split panel with the given sibling surface in the given
|
/// Create a new split panel with the given sibling surface in the given
|
||||||
/// direction. The direction is where the new surface will be initialized.
|
/// direction. The direction is where the new surface will be initialized.
|
||||||
@ -73,7 +53,6 @@ pub fn init(
|
|||||||
const alloc = sibling.app.core_app.alloc;
|
const alloc = sibling.app.core_app.alloc;
|
||||||
var surface = try Surface.create(alloc, sibling.app, .{
|
var surface = try Surface.create(alloc, sibling.app, .{
|
||||||
.parent2 = &sibling.core_surface,
|
.parent2 = &sibling.core_surface,
|
||||||
.parent = .{ .paned = .{ self, .end } },
|
|
||||||
});
|
});
|
||||||
errdefer surface.destroy(alloc);
|
errdefer surface.destroy(alloc);
|
||||||
|
|
||||||
@ -93,25 +72,21 @@ pub fn init(
|
|||||||
sibling.container = .{ .split_tl = &self.top_left };
|
sibling.container = .{ .split_tl = &self.top_left };
|
||||||
surface.container = .{ .split_br = &self.bottom_right };
|
surface.container = .{ .split_br = &self.bottom_right };
|
||||||
|
|
||||||
// If the sibling is already in a split, then we need to
|
|
||||||
// nest them properly. This gets the pointer to the split element
|
|
||||||
// that the original split was in, then updates it to point to this
|
|
||||||
// split. This split then contains the surface as an element.
|
|
||||||
if (container.splitElem()) |parent_elem| {
|
|
||||||
parent_elem.* = .{ .split = self };
|
|
||||||
}
|
|
||||||
|
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.paned = @ptrCast(paned),
|
.paned = @ptrCast(paned),
|
||||||
.container = container,
|
.container = container,
|
||||||
.top_left = .{ .surface = sibling },
|
.top_left = .{ .surface = sibling },
|
||||||
.bottom_right = .{ .surface = surface },
|
.bottom_right = .{ .surface = surface },
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the parent of Split.
|
// Replace the previous containers element with our split.
|
||||||
pub fn setParent(self: *Split, parent: Parent) void {
|
// This allows a non-split to become a split, a split to
|
||||||
self.parent = parent;
|
// become a nested split, etc.
|
||||||
|
container.replace(.{ .split = self });
|
||||||
|
|
||||||
|
// Update our children so that our GL area is properly
|
||||||
|
// added to the paned.
|
||||||
|
self.updateChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Focus on first Surface that can be found in given position. If there's a
|
/// Focus on first Surface that can be found in given position. If there's a
|
||||||
@ -211,6 +186,23 @@ fn removeChildInPosition(self: *Split, position: Position) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: ehhhhhh
|
||||||
|
pub fn replace(
|
||||||
|
self: *Split,
|
||||||
|
ptr: *Surface.Container.Elem,
|
||||||
|
new: Surface.Container.Elem,
|
||||||
|
) void {
|
||||||
|
// We can write our element directly. There's nothing special.
|
||||||
|
assert(&self.top_left == ptr or &self.bottom_right == ptr);
|
||||||
|
ptr.* = new;
|
||||||
|
|
||||||
|
// Update our paned children. This will reset the divider
|
||||||
|
// position but we want to keep it in place so save and restore it.
|
||||||
|
const pos = c.gtk_paned_get_position(self.paned);
|
||||||
|
self.updateChildren();
|
||||||
|
c.gtk_paned_set_position(self.paned, pos);
|
||||||
|
}
|
||||||
|
|
||||||
/// Update the paned children to represent the current state.
|
/// Update the paned children to represent the current state.
|
||||||
/// This should be called anytime the top/left or bottom/right
|
/// This should be called anytime the top/left or bottom/right
|
||||||
/// element is changed.
|
/// element is changed.
|
||||||
|
@ -32,9 +32,6 @@ pub const Options = struct {
|
|||||||
/// The parent surface to inherit settings such as font size, working
|
/// The parent surface to inherit settings such as font size, working
|
||||||
/// directory, etc. from.
|
/// directory, etc. from.
|
||||||
parent2: ?*CoreSurface = null,
|
parent2: ?*CoreSurface = null,
|
||||||
|
|
||||||
/// The parent this surface is created under.
|
|
||||||
parent: Parent,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The container that this surface is directly attached to.
|
/// The container that this surface is directly attached to.
|
||||||
@ -49,8 +46,33 @@ pub const Container = union(enum) {
|
|||||||
|
|
||||||
/// A split within a split hierarchy. The key determines the
|
/// A split within a split hierarchy. The key determines the
|
||||||
/// position of the split within the parent split.
|
/// position of the split within the parent split.
|
||||||
split_tl: *Split.Elem,
|
split_tl: *Elem,
|
||||||
split_br: *Split.Elem,
|
split_br: *Elem,
|
||||||
|
|
||||||
|
/// Elem is the possible element of any container. A container can
|
||||||
|
/// hold both a surface and a split. Any valid container should
|
||||||
|
/// have an Elem value so that it can be properly used with
|
||||||
|
/// splits.
|
||||||
|
pub const Elem = union(enum) {
|
||||||
|
/// A surface is a leaf element of the split -- a terminal
|
||||||
|
/// surface.
|
||||||
|
surface: *Surface,
|
||||||
|
|
||||||
|
/// A split is a nested split within a split. This lets you
|
||||||
|
/// for example have a horizontal split with a vertical split
|
||||||
|
/// on the left side (amongst all other possible
|
||||||
|
/// combinations).
|
||||||
|
split: *Split,
|
||||||
|
|
||||||
|
/// Returns the GTK widget to add to the paned for the given
|
||||||
|
/// element
|
||||||
|
pub fn widget(self: Elem) *c.GtkWidget {
|
||||||
|
return switch (self) {
|
||||||
|
.surface => |s| @ptrCast(s.gl_area),
|
||||||
|
.split => |s| @ptrCast(@alignCast(s.paned)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Returns the window that this surface is attached to.
|
/// Returns the window that this surface is attached to.
|
||||||
pub fn window(self: Container) ?*Window {
|
pub fn window(self: Container) ?*Window {
|
||||||
@ -85,14 +107,19 @@ pub const Container = union(enum) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the element of the split that this container
|
/// Replace the container's element with this element. This is
|
||||||
/// is attached to.
|
/// used by children to modify their parents to for example change
|
||||||
pub fn splitElem(self: Container) ?*Split.Elem {
|
/// from a surface to a split or a split back to a surface or
|
||||||
return switch (self) {
|
/// a split to a nested split and so on.
|
||||||
.none, .tab_ => null,
|
pub fn replace(self: Container, elem: Elem) void {
|
||||||
.split_tl => |ptr| ptr,
|
switch (self) {
|
||||||
.split_br => |ptr| ptr,
|
.none => {},
|
||||||
};
|
.tab_ => |t| t.replaceElem(elem),
|
||||||
|
inline .split_tl, .split_br => |ptr| {
|
||||||
|
const s = self.split().?;
|
||||||
|
s.replace(ptr, elem);
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -111,9 +138,6 @@ container: Container = .{ .none = {} },
|
|||||||
/// The app we're part of
|
/// The app we're part of
|
||||||
app: *App,
|
app: *App,
|
||||||
|
|
||||||
/// The parent we belong to
|
|
||||||
parent: Parent,
|
|
||||||
|
|
||||||
/// Our GTK area
|
/// Our GTK area
|
||||||
gl_area: *c.GtkGLArea,
|
gl_area: *c.GtkGLArea,
|
||||||
|
|
||||||
@ -158,9 +182,20 @@ pub fn create(alloc: Allocator, app: *App, opts: Options) !*Surface {
|
|||||||
pub fn init(self: *Surface, app: *App, opts: Options) !void {
|
pub fn init(self: *Surface, app: *App, opts: Options) !void {
|
||||||
const widget: *c.GtkWidget = c.gtk_gl_area_new();
|
const widget: *c.GtkWidget = c.gtk_gl_area_new();
|
||||||
const gl_area: *c.GtkGLArea = @ptrCast(widget);
|
const gl_area: *c.GtkGLArea = @ptrCast(widget);
|
||||||
|
|
||||||
|
// We grab the floating reference to GL area. This lets the
|
||||||
|
// GL area be moved around i.e. between a split, a tab, etc.
|
||||||
|
// without having to be really careful about ordering to
|
||||||
|
// prevent a destroy.
|
||||||
|
// TODO: unref in deinit
|
||||||
|
_ = c.g_object_ref_sink(@ptrCast(gl_area));
|
||||||
|
errdefer c.g_object_unref(@ptrCast(gl_area));
|
||||||
|
|
||||||
|
// We want the gl area to expand to fill the parent container.
|
||||||
c.gtk_widget_set_hexpand(widget, 1);
|
c.gtk_widget_set_hexpand(widget, 1);
|
||||||
c.gtk_widget_set_vexpand(widget, 1);
|
c.gtk_widget_set_vexpand(widget, 1);
|
||||||
|
|
||||||
|
// Various other GL properties
|
||||||
c.gtk_widget_set_cursor_from_name(@ptrCast(gl_area), "text");
|
c.gtk_widget_set_cursor_from_name(@ptrCast(gl_area), "text");
|
||||||
c.gtk_gl_area_set_required_version(gl_area, 3, 3);
|
c.gtk_gl_area_set_required_version(gl_area, 3, 3);
|
||||||
c.gtk_gl_area_set_has_stencil_buffer(gl_area, 0);
|
c.gtk_gl_area_set_has_stencil_buffer(gl_area, 0);
|
||||||
@ -226,7 +261,6 @@ pub fn init(self: *Surface, app: *App, opts: Options) !void {
|
|||||||
self.* = .{
|
self.* = .{
|
||||||
.app = app,
|
.app = app,
|
||||||
.container = .{ .none = {} },
|
.container = .{ .none = {} },
|
||||||
.parent = opts.parent,
|
|
||||||
.gl_area = gl_area,
|
.gl_area = gl_area,
|
||||||
.title_text_buf = undefined,
|
.title_text_buf = undefined,
|
||||||
.title_text_buf_len = 0,
|
.title_text_buf_len = 0,
|
||||||
@ -450,19 +484,21 @@ pub fn getTitleLabel(self: *Surface) ?*c.GtkWidget {
|
|||||||
|
|
||||||
pub fn newSplit(self: *Surface, direction: input.SplitDirection) !void {
|
pub fn newSplit(self: *Surface, direction: input.SplitDirection) !void {
|
||||||
log.debug("splitting direction={}", .{direction});
|
log.debug("splitting direction={}", .{direction});
|
||||||
|
const alloc = self.app.core_app.alloc;
|
||||||
|
_ = try Split.create(alloc, self, direction);
|
||||||
|
|
||||||
switch (self.parent) {
|
// switch (self.parent) {
|
||||||
.none => return,
|
// .none => return,
|
||||||
.paned => |parent_paned_tuple| {
|
// .paned => |parent_paned_tuple| {
|
||||||
const paned = parent_paned_tuple[0];
|
// const paned = parent_paned_tuple[0];
|
||||||
const position = parent_paned_tuple[1];
|
// const position = parent_paned_tuple[1];
|
||||||
|
//
|
||||||
try paned.splitSurfaceInPosition(position, direction);
|
// try paned.splitSurfaceInPosition(position, direction);
|
||||||
},
|
// },
|
||||||
.tab => |tab| {
|
// .tab => |tab| {
|
||||||
try tab.splitSurface(direction);
|
// try tab.splitSurface(direction);
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newTab(self: *Surface) !void {
|
pub fn newTab(self: *Surface) !void {
|
||||||
@ -852,6 +888,7 @@ fn gtkRealize(area: *c.GtkGLArea, ud: ?*anyopaque) callconv(.C) void {
|
|||||||
fn gtkUnrealize(area: *c.GtkGLArea, ud: ?*anyopaque) callconv(.C) void {
|
fn gtkUnrealize(area: *c.GtkGLArea, ud: ?*anyopaque) callconv(.C) void {
|
||||||
_ = area;
|
_ = area;
|
||||||
|
|
||||||
|
log.debug("gl surface unrealized", .{});
|
||||||
const self = userdataSelf(ud.?);
|
const self = userdataSelf(ud.?);
|
||||||
self.core_surface.renderer.displayUnrealized();
|
self.core_surface.renderer.displayUnrealized();
|
||||||
|
|
||||||
@ -973,7 +1010,8 @@ fn gtkMouseDown(
|
|||||||
|
|
||||||
// If we have siblings, we also update the title, since it means
|
// If we have siblings, we also update the title, since it means
|
||||||
// another sibling might have updated the title.
|
// another sibling might have updated the title.
|
||||||
if (self.parent != Parent.tab) self.updateTitleLabels();
|
// TODO: fixme
|
||||||
|
//if (self.parent != Parent.tab) self.updateTitleLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.core_surface.mouseButtonCallback(.press, button, mods) catch |err| {
|
self.core_surface.mouseButtonCallback(.press, button, mods) catch |err| {
|
||||||
|
@ -22,12 +22,21 @@ const log = std.log.scoped(.gtk);
|
|||||||
pub const GHOSTTY_TAB = "ghostty_tab";
|
pub const GHOSTTY_TAB = "ghostty_tab";
|
||||||
|
|
||||||
window: *Window,
|
window: *Window,
|
||||||
|
|
||||||
|
/// The tab label.
|
||||||
label_text: *c.GtkLabel,
|
label_text: *c.GtkLabel,
|
||||||
// We'll put our children into this box instead of packing them directly, so
|
|
||||||
// that we can send the box into `c.g_signal_connect_data` for the close button
|
/// We'll put our children into this box instead of packing them
|
||||||
|
/// directly, so that we can send the box into `c.g_signal_connect_data`
|
||||||
|
/// for the close button
|
||||||
box: *c.GtkBox,
|
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
|
// The child can be either a Surface if the tab is not split or a Paned
|
||||||
child: Child,
|
child: Child,
|
||||||
|
|
||||||
// We'll update this every time a Surface gains focus, so that we have it
|
// 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
|
// when we switch to another Tab. Then when we switch back to this tab, we
|
||||||
// can easily re-focus that terminal.
|
// can easily re-focus that terminal.
|
||||||
@ -47,6 +56,7 @@ pub fn init(self: *Tab, window: *Window, parent_: ?*CoreSurface) !void {
|
|||||||
.window = window,
|
.window = window,
|
||||||
.label_text = undefined,
|
.label_text = undefined,
|
||||||
.box = undefined,
|
.box = undefined,
|
||||||
|
.elem = undefined,
|
||||||
.child = undefined,
|
.child = undefined,
|
||||||
.focus_child = undefined,
|
.focus_child = undefined,
|
||||||
};
|
};
|
||||||
@ -92,11 +102,11 @@ pub fn init(self: *Tab, window: *Window, parent_: ?*CoreSurface) !void {
|
|||||||
// Create the initial surface since all tabs start as a single non-split
|
// Create the initial surface since all tabs start as a single non-split
|
||||||
var surface = try Surface.create(window.app.core_app.alloc, window.app, .{
|
var surface = try Surface.create(window.app.core_app.alloc, window.app, .{
|
||||||
.parent2 = parent_,
|
.parent2 = parent_,
|
||||||
.parent = .{ .tab = self },
|
|
||||||
});
|
});
|
||||||
errdefer surface.destroy(window.app.core_app.alloc);
|
errdefer surface.destroy(window.app.core_app.alloc);
|
||||||
surface.setContainer(.{ .tab_ = self });
|
surface.setContainer(.{ .tab_ = self });
|
||||||
self.child = .{ .surface = surface };
|
self.child = .{ .surface = surface };
|
||||||
|
self.elem = .{ .surface = surface };
|
||||||
|
|
||||||
// Add Surface to the Tab
|
// Add Surface to the Tab
|
||||||
const gl_area_widget = @as(*c.GtkWidget, @ptrCast(surface.gl_area));
|
const gl_area_widget = @as(*c.GtkWidget, @ptrCast(surface.gl_area));
|
||||||
@ -178,6 +188,17 @@ pub fn removeChild(self: *Tab) void {
|
|||||||
self.child = .none;
|
self.child = .none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move this
|
||||||
|
/// Replace the surface element that this tab is showing.
|
||||||
|
pub fn replaceElem(self: *Tab, elem: Surface.Container.Elem) void {
|
||||||
|
// Remove our previous widget
|
||||||
|
c.gtk_box_remove(self.box, self.elem.widget());
|
||||||
|
|
||||||
|
// Add our new one
|
||||||
|
c.gtk_box_append(self.box, elem.widget());
|
||||||
|
self.elem = elem;
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets child to given child and sets parent on child.
|
/// Sets child to given child and sets parent on child.
|
||||||
pub fn setChild(self: *Tab, child: Child) void {
|
pub fn setChild(self: *Tab, child: Child) void {
|
||||||
const widget = child.widget() orelse return;
|
const widget = child.widget() orelse return;
|
||||||
|
@ -260,16 +260,17 @@ pub fn closeTab(self: *Window, tab: *Tab) void {
|
|||||||
pub fn closeSurface(self: *Window, surface: *Surface) void {
|
pub fn closeSurface(self: *Window, surface: *Surface) void {
|
||||||
assert(surface.container.window().? == self);
|
assert(surface.container.window().? == self);
|
||||||
|
|
||||||
switch (surface.parent) {
|
// TODO: fixme
|
||||||
.none => unreachable,
|
// switch (surface.parent) {
|
||||||
.tab => |tab| self.closeTab(tab),
|
// .none => unreachable,
|
||||||
.paned => |paned_tuple| {
|
// .tab => |tab| self.closeTab(tab),
|
||||||
const paned = paned_tuple[0];
|
// .paned => |paned_tuple| {
|
||||||
const position = paned_tuple[1];
|
// const paned = paned_tuple[0];
|
||||||
|
// const position = paned_tuple[1];
|
||||||
self.closeSurfaceInPaned(surface, paned, position);
|
//
|
||||||
},
|
// self.closeSurfaceInPaned(surface, paned, position);
|
||||||
}
|
// },
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn closeSurfaceInPaned(self: *Window, surface: *Surface, paned: *Paned, position: Position) void {
|
fn closeSurfaceInPaned(self: *Window, surface: *Surface, paned: *Paned, position: Position) void {
|
||||||
|
Reference in New Issue
Block a user