mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
gtk: close tab button
This commit is contained in:
@ -158,9 +158,10 @@ pub const App = struct {
|
|||||||
try window.init(self);
|
try window.init(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtkTabAddClick(_: *c.GtkButton, ud: ?*anyopaque) callconv(.C) void {
|
pub fn newTab(self: *App, parent_: ?*CoreSurface) !void {
|
||||||
_ = ud;
|
// TODO
|
||||||
log.warn("CLICK", .{});
|
_ = self;
|
||||||
|
_ = parent_;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate(app: *c.GtkApplication, ud: ?*anyopaque) callconv(.C) void {
|
fn activate(app: *c.GtkApplication, ud: ?*anyopaque) callconv(.C) void {
|
||||||
@ -177,8 +178,13 @@ pub const App = struct {
|
|||||||
|
|
||||||
/// The state for a single, real GTK window.
|
/// The state for a single, real GTK window.
|
||||||
const Window = struct {
|
const Window = struct {
|
||||||
|
const TAB_CLOSE_PAGE = "tab_close_page";
|
||||||
|
|
||||||
app: *App,
|
app: *App,
|
||||||
|
|
||||||
|
/// Our window
|
||||||
|
window: *c.GtkWindow,
|
||||||
|
|
||||||
/// The notebook (tab grouping) for this window.
|
/// The notebook (tab grouping) for this window.
|
||||||
notebook: *c.GtkNotebook,
|
notebook: *c.GtkNotebook,
|
||||||
|
|
||||||
@ -186,6 +192,7 @@ const Window = struct {
|
|||||||
// Set up our own state
|
// Set up our own state
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.app = app,
|
.app = app,
|
||||||
|
.window = undefined,
|
||||||
.notebook = undefined,
|
.notebook = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -193,6 +200,7 @@ const Window = struct {
|
|||||||
const window = c.gtk_application_window_new(app.app);
|
const window = c.gtk_application_window_new(app.app);
|
||||||
const gtk_window = @ptrCast(*c.GtkWindow, window);
|
const gtk_window = @ptrCast(*c.GtkWindow, window);
|
||||||
errdefer c.gtk_window_destroy(gtk_window);
|
errdefer c.gtk_window_destroy(gtk_window);
|
||||||
|
self.window = gtk_window;
|
||||||
c.gtk_window_set_title(gtk_window, "Ghostty");
|
c.gtk_window_set_title(gtk_window, "Ghostty");
|
||||||
c.gtk_window_set_default_size(gtk_window, 200, 200);
|
c.gtk_window_set_default_size(gtk_window, 200, 200);
|
||||||
c.gtk_widget_show(window);
|
c.gtk_widget_show(window);
|
||||||
@ -228,25 +236,41 @@ const Window = struct {
|
|||||||
var surface = try self.app.core_app.alloc.create(Surface);
|
var surface = try self.app.core_app.alloc.create(Surface);
|
||||||
errdefer self.app.core_app.alloc.destroy(surface);
|
errdefer self.app.core_app.alloc.destroy(surface);
|
||||||
|
|
||||||
|
// Build our tab label
|
||||||
|
const label_box_widget = c.gtk_box_new(c.GTK_ORIENTATION_HORIZONTAL, 0);
|
||||||
|
const label_box = @ptrCast(*c.GtkBox, label_box_widget);
|
||||||
|
const label_text = c.gtk_label_new("Ghostty");
|
||||||
|
c.gtk_box_append(label_box, label_text);
|
||||||
|
|
||||||
|
const label_close_widget = c.gtk_button_new_from_icon_name("window-close");
|
||||||
|
const label_close = @ptrCast(*c.GtkButton, label_close_widget);
|
||||||
|
c.gtk_button_set_has_frame(label_close, 0);
|
||||||
|
c.gtk_box_append(label_box, label_close_widget);
|
||||||
|
_ = c.g_signal_connect_data(label_close, "clicked", c.G_CALLBACK(>kTabCloseClick), self, null, c.G_CONNECT_DEFAULT);
|
||||||
|
|
||||||
// Initialize the GtkGLArea and attach it to our surface.
|
// Initialize the GtkGLArea and attach it to our surface.
|
||||||
// The surface starts in the "unrealized" state because we have to
|
// The surface starts in the "unrealized" state because we have to
|
||||||
// wait for the "realize" callback from GTK to know that the OpenGL
|
// wait for the "realize" callback from GTK to know that the OpenGL
|
||||||
// context is ready. See Surface docs for more info.
|
// context is ready. See Surface docs for more info.
|
||||||
const gl_area = c.gtk_gl_area_new();
|
const gl_area = c.gtk_gl_area_new();
|
||||||
const label = c.gtk_label_new("Ghostty");
|
|
||||||
try surface.init(self.app, .{
|
try surface.init(self.app, .{
|
||||||
.gl_area = @ptrCast(*c.GtkGLArea, gl_area),
|
.gl_area = @ptrCast(*c.GtkGLArea, gl_area),
|
||||||
.title_label = @ptrCast(*c.GtkLabel, label),
|
.title_label = @ptrCast(*c.GtkLabel, label_text),
|
||||||
});
|
});
|
||||||
errdefer surface.deinit();
|
errdefer surface.deinit();
|
||||||
const page = c.gtk_notebook_append_page(self.notebook, gl_area, label);
|
const page_idx = c.gtk_notebook_append_page(self.notebook, gl_area, label_box_widget);
|
||||||
if (page < 0) {
|
if (page_idx < 0) {
|
||||||
log.warn("failed to add surface to notebook", .{});
|
log.warn("failed to add surface to notebook", .{});
|
||||||
return error.GtkAppendPageFailed;
|
return error.GtkAppendPageFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the userdata of the close button so it points to this page.
|
||||||
|
const page = c.gtk_notebook_get_page(self.notebook, gl_area) orelse
|
||||||
|
return error.GtkNotebookPageNotFound;
|
||||||
|
c.g_object_set_data(@ptrCast(*c.GObject, label_close), TAB_CLOSE_PAGE, page);
|
||||||
|
|
||||||
// Switch to the new tab
|
// Switch to the new tab
|
||||||
c.gtk_notebook_set_current_page(self.notebook, page);
|
c.gtk_notebook_set_current_page(self.notebook, page_idx);
|
||||||
|
|
||||||
// We need to grab focus after it is added to the window. When
|
// We need to grab focus after it is added to the window. When
|
||||||
// creating a window we want to always focus on the widget.
|
// creating a window we want to always focus on the widget.
|
||||||
@ -262,6 +286,34 @@ const Window = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gtkTabCloseClick(btn: *c.GtkButton, ud: ?*anyopaque) callconv(.C) void {
|
||||||
|
// Get the notebook page
|
||||||
|
const page = @ptrCast(*c.GtkNotebookPage, @alignCast(
|
||||||
|
@alignOf(c.GtkNotebookPage),
|
||||||
|
c.g_object_get_data(@ptrCast(*c.GObject, btn), TAB_CLOSE_PAGE),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Get the page index
|
||||||
|
var value: c.GValue = std.mem.zeroes(c.GValue);
|
||||||
|
defer c.g_value_unset(&value);
|
||||||
|
_ = c.g_value_init(&value, c.G_TYPE_INT);
|
||||||
|
c.g_object_get_property(
|
||||||
|
@ptrCast(*c.GObject, @alignCast(@alignOf(c.GObject), page)),
|
||||||
|
"position",
|
||||||
|
&value,
|
||||||
|
);
|
||||||
|
|
||||||
|
const page_idx = c.g_value_get_int(&value);
|
||||||
|
const self = userdataSelf(ud.?);
|
||||||
|
c.gtk_notebook_remove_page(self.notebook, page_idx);
|
||||||
|
|
||||||
|
// If we have no more tabs left we close the window
|
||||||
|
const remaining = c.gtk_notebook_get_n_pages(self.notebook);
|
||||||
|
if (remaining == 0) {
|
||||||
|
c.gtk_window_destroy(self.window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// "destroy" signal for the window
|
/// "destroy" signal for the window
|
||||||
fn gtkDestroy(v: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void {
|
fn gtkDestroy(v: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void {
|
||||||
_ = v;
|
_ = v;
|
||||||
|
@ -273,12 +273,12 @@ pub const Config = struct {
|
|||||||
.{ .key = .w, .mods = .{ .super = true } },
|
.{ .key = .w, .mods = .{ .super = true } },
|
||||||
.{ .close_window = {} },
|
.{ .close_window = {} },
|
||||||
);
|
);
|
||||||
if (comptime builtin.target.isDarwin()) {
|
|
||||||
try result.keybind.set.put(
|
try result.keybind.set.put(
|
||||||
alloc,
|
alloc,
|
||||||
.{ .key = .t, .mods = .{ .super = true } },
|
.{ .key = .t, .mods = .{ .super = true } },
|
||||||
.{ .new_tab = {} },
|
.{ .new_tab = {} },
|
||||||
);
|
);
|
||||||
|
if (comptime builtin.target.isDarwin()) {
|
||||||
try result.keybind.set.put(
|
try result.keybind.set.put(
|
||||||
alloc,
|
alloc,
|
||||||
.{ .key = .q, .mods = .{ .super = true } },
|
.{ .key = .q, .mods = .{ .super = true } },
|
||||||
|
Reference in New Issue
Block a user