diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index 99d0fb9de..6d2b93aef 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -894,7 +894,7 @@ fn updateTitleLabels(self: *Surface) void { // If we have a tab and are the focused child, then we have to update the tab if (self.container.tab()) |tab| { - if (tab.focus_child == self) c.gtk_label_set_text(tab.label_text, title.ptr); + if (tab.focus_child == self) tab.setLabelText(title); // c.gtk_label_set_text(tab.label_text, title.ptr); } // If we have a window and are focused, then we have to update the window title. diff --git a/src/apprt/gtk/Tab.zig b/src/apprt/gtk/Tab.zig index 42a18711b..8a2f05513 100644 --- a/src/apprt/gtk/Tab.zig +++ b/src/apprt/gtk/Tab.zig @@ -55,37 +55,23 @@ pub fn init(self: *Tab, window: *Window, parent_: ?*CoreSurface) !void { .focus_child = undefined, }; - // Build the tab label - const label_box_widget = c.gtk_box_new(c.GTK_ORIENTATION_HORIZONTAL, 0); - const label_box = @as(*c.GtkBox, @ptrCast(label_box_widget)); - const label_text_widget = c.gtk_label_new("Ghostty"); - const label_text: *c.GtkLabel = @ptrCast(label_text_widget); - c.gtk_box_append(label_box, label_text_widget); - self.label_text = label_text; + // // Wide style GTK tabs + // if (window.app.config.@"gtk-wide-tabs") { + // c.gtk_widget_set_hexpand(label_box_widget, 1); + // c.gtk_widget_set_halign(label_box_widget, c.GTK_ALIGN_FILL); + // c.gtk_widget_set_hexpand(label_text_widget, 1); + // c.gtk_widget_set_halign(label_text_widget, c.GTK_ALIGN_FILL); - // Build the close button for the tab - const label_close_widget = c.gtk_button_new_from_icon_name("window-close-symbolic"); - const label_close: *c.GtkButton = @ptrCast(label_close_widget); - c.gtk_button_set_has_frame(label_close, 0); - c.gtk_box_append(label_box, label_close_widget); + // // This ensures that tabs are always equal width. If they're too + // // long, they'll be truncated with an ellipsis. + // c.gtk_label_set_max_width_chars(label_text, 1); + // c.gtk_label_set_ellipsize(label_text, c.PANGO_ELLIPSIZE_END); - // Wide style GTK tabs - if (window.app.config.@"gtk-wide-tabs") { - c.gtk_widget_set_hexpand(label_box_widget, 1); - c.gtk_widget_set_halign(label_box_widget, c.GTK_ALIGN_FILL); - c.gtk_widget_set_hexpand(label_text_widget, 1); - c.gtk_widget_set_halign(label_text_widget, c.GTK_ALIGN_FILL); - - // This ensures that tabs are always equal width. If they're too - // long, they'll be truncated with an ellipsis. - c.gtk_label_set_max_width_chars(label_text, 1); - c.gtk_label_set_ellipsize(label_text, c.PANGO_ELLIPSIZE_END); - - // We need to set a minimum width so that at a certain point - // the notebook will have an arrow button rather than shrinking tabs - // to an unreadably small size. - c.gtk_widget_set_size_request(label_text_widget, 100, 1); - } + // // We need to set a minimum width so that at a certain point + // // the notebook will have an arrow button rather than shrinking tabs + // // to an unreadably small size. + // c.gtk_widget_set_size_request(label_text_widget, 100, 1); + // } // Create a Box in which we'll later keep either Surface or Split. // Using a box makes it easier to maintain the tab contents because @@ -106,47 +92,51 @@ pub fn init(self: *Tab, window: *Window, parent_: ?*CoreSurface) !void { // Add Surface to the Tab c.gtk_box_append(self.box, surface.primaryWidget()); - // Add the notebook page (create tab). - const parent_page_idx = switch (window.app.config.@"window-new-tab-position") { - .current => c.gtk_notebook_get_current_page(window.notebook) + 1, - .end => c.gtk_notebook_get_n_pages(window.notebook), - }; + try window.notebook.addTab(box_widget, "Ghostty"); - const page_idx = c.gtk_notebook_insert_page( - window.notebook, - box_widget, - label_box_widget, - parent_page_idx, - ); - if (page_idx < 0) { - log.warn("failed to add page to notebook", .{}); - return error.GtkAppendPageFailed; - } + // const notebook: *c.GtkNotebook = window.notebook.as_notebook(); - // Tab settings - c.gtk_notebook_set_tab_reorderable(window.notebook, box_widget, 1); - c.gtk_notebook_set_tab_detachable(window.notebook, box_widget, 1); + // // Add the notebook page (create tab). + // const parent_page_idx = switch (window.app.config.@"window-new-tab-position") { + // .current => c.gtk_notebook_get_current_page(notebook) + 1, + // .end => c.gtk_notebook_get_n_pages(notebook), + // }; - // If we have multiple tabs, show the tab bar. - if (c.gtk_notebook_get_n_pages(window.notebook) > 1) { - c.gtk_notebook_set_show_tabs(window.notebook, 1); - } + // const page_idx = c.gtk_notebook_insert_page( + // notebook, + // box_widget, + // label_box_widget, + // parent_page_idx, + // ); + // if (page_idx < 0) { + // log.warn("failed to add page to notebook", .{}); + // return error.GtkAppendPageFailed; + // } + + // // Tab settings + // c.gtk_notebook_set_tab_reorderable(notebook, box_widget, 1); + // c.gtk_notebook_set_tab_detachable(notebook, box_widget, 1); + + // // If we have multiple tabs, show the tab bar. + // if (c.gtk_notebook_get_n_pages(notebook) > 1) { + // c.gtk_notebook_set_show_tabs(notebook, 1); + // } // Set the userdata of the box to point to this tab. c.g_object_set_data(@ptrCast(box_widget), GHOSTTY_TAB, self); - // Clicks - const gesture_tab_click = c.gtk_gesture_click_new(); - c.gtk_gesture_single_set_button(@ptrCast(gesture_tab_click), 0); - c.gtk_widget_add_controller(label_box_widget, @ptrCast(gesture_tab_click)); + // // Clicks + // const gesture_tab_click = c.gtk_gesture_click_new(); + // c.gtk_gesture_single_set_button(@ptrCast(gesture_tab_click), 0); + // c.gtk_widget_add_controller(label_box_widget, @ptrCast(gesture_tab_click)); - // Attach all events - _ = c.g_signal_connect_data(label_close, "clicked", c.G_CALLBACK(>kTabCloseClick), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(box_widget, "destroy", c.G_CALLBACK(>kDestroy), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(gesture_tab_click, "pressed", c.G_CALLBACK(>kTabClick), self, null, c.G_CONNECT_DEFAULT); + // // Attach all events + // _ = c.g_signal_connect_data(label_close, "clicked", c.G_CALLBACK(>kTabCloseClick), self, null, c.G_CONNECT_DEFAULT); + // _ = c.g_signal_connect_data(box_widget, "destroy", c.G_CALLBACK(>kDestroy), self, null, c.G_CONNECT_DEFAULT); + // _ = c.g_signal_connect_data(gesture_tab_click, "pressed", c.G_CALLBACK(>kTabClick), self, null, c.G_CONNECT_DEFAULT); - // Switch to the new tab - c.gtk_notebook_set_current_page(window.notebook, page_idx); + // // Switch to the new tab + // c.gtk_notebook_set_current_page(notebook, page_idx); // We need to grab focus after Surface and Tab is added to the window. When // creating a Tab we want to always focus on the widget. @@ -175,6 +165,18 @@ pub fn replaceElem(self: *Tab, elem: Surface.Container.Elem) void { self.elem = elem; } +pub fn setLabelText(self: *Tab, title: [:0]const u8) void { + switch (self.window.notebook) { + .adw_tab_view => |tab_view| { + const page = c.adw_tab_view_get_page(tab_view, @ptrCast(self.box)); + c.adw_tab_page_set_title(page, title.ptr); + }, + .gtk_notebook => { + c.gtk_label_set_text(self.label_text, title.ptr); + } + } +} + /// Remove this tab from the window. pub fn remove(self: *Tab) void { self.window.closeTab(self); diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index 3446aa304..7bfe62efb 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -8,6 +8,7 @@ const Window = @This(); const std = @import("std"); const builtin = @import("builtin"); const build_config = @import("../../build_config.zig"); +const build_options = @import("build_options"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; const configpkg = @import("../../config.zig"); @@ -23,13 +24,139 @@ const c = @import("c.zig").c; const log = std.log.scoped(.gtk); +pub const Notebook = union(enum) { + adw_tab_view: *c.AdwTabView, + gtk_notebook: *c.GtkNotebook, + + pub fn create(window: *Window) @This() { + const app = window.app; + + // Create a notebook to hold our tabs. + const notebook_widget = c.gtk_notebook_new(); + const notebook: *c.GtkNotebook = @ptrCast(notebook_widget); + const notebook_tab_pos: c_uint = switch (app.config.@"gtk-tabs-location") { + .top => c.GTK_POS_TOP, + .bottom => c.GTK_POS_BOTTOM, + .left => c.GTK_POS_LEFT, + .right => c.GTK_POS_RIGHT, + }; + c.gtk_notebook_set_tab_pos(notebook, notebook_tab_pos); + c.gtk_notebook_set_scrollable(notebook, 1); + c.gtk_notebook_set_show_tabs(notebook, 0); + c.gtk_notebook_set_show_border(notebook, 0); + + // This enables all Ghostty terminal tabs to be exchanged across windows. + c.gtk_notebook_set_group_name(notebook, "ghostty-terminal-tabs"); + + // This is important so the notebook expands to fit available space. + // Otherwise, it will be zero/zero in the box below. + c.gtk_widget_set_vexpand(notebook_widget, 1); + c.gtk_widget_set_hexpand(notebook_widget, 1); + + // If we are in fullscreen mode, new windows start fullscreen. + if (app.config.fullscreen) c.gtk_window_fullscreen(window.window); + + // All of our events + _ = c.g_signal_connect_data(window, "close-request", c.G_CALLBACK(>kCloseRequest), window, null, c.G_CONNECT_DEFAULT); + _ = c.g_signal_connect_data(window, "destroy", c.G_CALLBACK(>kDestroy), window, null, c.G_CONNECT_DEFAULT); + _ = c.g_signal_connect_data(notebook, "page-added", c.G_CALLBACK(>kPageAdded), window, null, c.G_CONNECT_DEFAULT); + _ = c.g_signal_connect_data(notebook, "page-removed", c.G_CALLBACK(>kPageRemoved), window, null, c.G_CONNECT_DEFAULT); + _ = c.g_signal_connect_data(notebook, "switch-page", c.G_CALLBACK(>kSwitchPage), window, null, c.G_CONNECT_DEFAULT); + _ = c.g_signal_connect_data(notebook, "create-window", c.G_CALLBACK(>kNotebookCreateWindow), window, null, c.G_CONNECT_DEFAULT); + + return .{ .gtk_notebook = notebook }; + } + + pub fn as_widget(self: Notebook) *c.GtkWidget { + return switch (self) { + .adw_tab_view => |ptr| @ptrCast(@alignCast(ptr)), + .gtk_notebook => |ptr| @ptrCast(@alignCast(ptr)), + }; + } + + pub fn as_notebook(self: Notebook) *c.GtkNotebook { + return switch (self) { + .adw_tab_view => @panic("adw tab view"), + .gtk_notebook => |notebook| notebook, + }; + } + + pub fn nPages(self: Notebook) c_int { + return switch (self) { + .adw_tab_view => |tab_view| c.adw_tab_view_get_n_pages(tab_view), + .gtk_notebook => |notebook| c.gtk_notebook_get_n_pages(notebook), + }; + } + + pub fn currentPage(self: Notebook) c_int { + switch (self) { + .adw_tab_view => |tab_view| { + const page = c.adw_tab_view_get_selected_page(tab_view); + return c.adw_tab_view_get_page_position(tab_view, page); + }, + .gtk_notebook => |notebook| return c.gtk_notebook_get_current_page(notebook), + } + } + + pub fn currentTab(self: Notebook) ?*Tab { + const child = switch (self) { + .adw_tab_view => |tab_view| child: { + const page = c.adw_tab_view_get_selected_page(tab_view); + const child = c.adw_tab_page_get_child(page); + break :child child; + }, + .gtk_notebook => |notebook| child: { + const page = self.currentPage(); + break :child c.gtk_notebook_get_nth_page(notebook, page); + }, + }; + return @ptrCast(@alignCast( + c.g_object_get_data(@ptrCast(child), Tab.GHOSTTY_TAB) orelse return null, + )); + } + + pub fn addTab(self: Notebook, tab_widget: *c.GtkWidget, title: [:0]const u8) !void { + switch (self) { + .adw_tab_view => |tab_view| { + const page = c.adw_tab_view_append(tab_view, tab_widget); + c.adw_tab_page_set_title(page, title); + }, + .gtk_notebook => |notebook| { + // Build the tab label + const label_box_widget = c.gtk_box_new(c.GTK_ORIENTATION_HORIZONTAL, 0); + const label_box = @as(*c.GtkBox, @ptrCast(label_box_widget)); + const label_text_widget = c.gtk_label_new("Ghostty"); + // const label_text: *c.GtkLabel = @ptrCast(label_text_widget); + c.gtk_box_append(label_box, label_text_widget); + // self.label_text = label_text; + + // Build the close button for the tab + const label_close_widget = c.gtk_button_new_from_icon_name("window-close-symbolic"); + const label_close: *c.GtkButton = @ptrCast(label_close_widget); + c.gtk_button_set_has_frame(label_close, 0); + c.gtk_box_append(label_box, label_close_widget); + + const parent_page_idx = self.nPages(); + const page_idx = c.gtk_notebook_insert_page( + notebook, + tab_widget, + label_box_widget, + parent_page_idx, + ); + _ = page_idx; + } + } + } +}; + app: *App, /// Our window window: *c.GtkWindow, /// The notebook (tab grouping) for this window. -notebook: *c.GtkNotebook, +/// can be either c.GtkNotebook or c.AdwTabView. +notebook: Notebook, context_menu: *c.GtkWidget, @@ -107,29 +234,6 @@ pub fn init(self: *Window, app: *App) !void { c.gtk_window_set_decorated(gtk_window, 0); } - // Create a notebook to hold our tabs. - const notebook_widget = c.gtk_notebook_new(); - const notebook: *c.GtkNotebook = @ptrCast(notebook_widget); - self.notebook = notebook; - const notebook_tab_pos: c_uint = switch (app.config.@"gtk-tabs-location") { - .top => c.GTK_POS_TOP, - .bottom => c.GTK_POS_BOTTOM, - .left => c.GTK_POS_LEFT, - .right => c.GTK_POS_RIGHT, - }; - c.gtk_notebook_set_tab_pos(notebook, notebook_tab_pos); - c.gtk_notebook_set_scrollable(notebook, 1); - c.gtk_notebook_set_show_tabs(notebook, 0); - c.gtk_notebook_set_show_border(notebook, 0); - - // This enables all Ghostty terminal tabs to be exchanged across windows. - c.gtk_notebook_set_group_name(notebook, "ghostty-terminal-tabs"); - - // This is important so the notebook expands to fit available space. - // Otherwise, it will be zero/zero in the box below. - c.gtk_widget_set_vexpand(notebook_widget, 1); - c.gtk_widget_set_hexpand(notebook_widget, 1); - // Create our box which will hold our widgets. const box = c.gtk_box_new(c.GTK_ORIENTATION_VERTICAL, 0); @@ -141,7 +245,19 @@ pub fn init(self: *Window, app: *App) !void { c.gtk_widget_set_margin_bottom(warning, 10); c.gtk_box_append(@ptrCast(box), warning); } - c.gtk_box_append(@ptrCast(box), notebook_widget); + + const adwaita = build_options.libadwaita and app.config.@"gtk-adwaita"; + if (adwaita) { + log.warn("using adwaita", .{}); + const tab_view = c.adw_tab_view_new(); + const tab_bar = c.adw_tab_bar_new(); + c.gtk_box_append(@ptrCast(box), @ptrCast(@alignCast(tab_bar))); + c.adw_tab_bar_set_view(tab_bar, tab_view.?); + self.notebook = .{ .adw_tab_view = tab_view.? }; + } else { + self.notebook = Notebook.create(self); + } + c.gtk_box_append(@ptrCast(box), self.notebook.as_widget()); self.context_menu = c.gtk_popover_menu_new_from_model(@ptrCast(@alignCast(self.app.context_menu))); c.gtk_widget_set_parent(self.context_menu, window); @@ -155,10 +271,6 @@ pub fn init(self: *Window, app: *App) !void { _ = c.g_signal_connect_data(self.context_menu, "closed", c.G_CALLBACK(>kRefocusTerm), self, null, c.G_CONNECT_DEFAULT); _ = c.g_signal_connect_data(window, "close-request", c.G_CALLBACK(>kCloseRequest), self, null, c.G_CONNECT_DEFAULT); _ = c.g_signal_connect_data(window, "destroy", c.G_CALLBACK(>kDestroy), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(notebook, "page-added", c.G_CALLBACK(>kPageAdded), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(notebook, "page-removed", c.G_CALLBACK(>kPageRemoved), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(notebook, "switch-page", c.G_CALLBACK(>kSwitchPage), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(notebook, "create-window", c.G_CALLBACK(>kNotebookCreateWindow), self, null, c.G_CONNECT_DEFAULT); // Our actions for the menu initActions(self); @@ -219,22 +331,23 @@ pub fn newTab(self: *Window, parent: ?*CoreSurface) !void { /// Close the tab for the given notebook page. This will automatically /// handle closing the window if there are no more tabs. pub fn closeTab(self: *Window, tab: *Tab) void { - const page = c.gtk_notebook_get_page(self.notebook, @ptrCast(tab.box)) orelse return; + const notebook: *c.GtkNotebook = self.notebook.as_notebook(); + const page = c.gtk_notebook_get_page(notebook, @ptrCast(tab.box)) orelse return; // Find page and tab which we're closing const page_idx = getNotebookPageIndex(page); // Remove the page. This will destroy the GTK widgets in the page which // will trigger Tab cleanup. - c.gtk_notebook_remove_page(self.notebook, page_idx); + c.gtk_notebook_remove_page(notebook, page_idx); - const remaining = c.gtk_notebook_get_n_pages(self.notebook); + const remaining = c.gtk_notebook_get_n_pages(notebook); switch (remaining) { // If we have no more tabs we close the window 0 => c.gtk_window_destroy(self.window), // If we have one more tab we hide the tab bar - 1 => c.gtk_notebook_set_show_tabs(self.notebook, 0), + 1 => c.gtk_notebook_set_show_tabs(notebook, 0), else => {}, } @@ -245,7 +358,7 @@ pub fn closeTab(self: *Window, tab: *Tab) void { /// 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; + return c.gtk_notebook_get_n_pages(self.notebook.as_notebook()) > 0; } /// Go to the previous tab for a surface. @@ -255,19 +368,20 @@ pub fn gotoPreviousTab(self: *Window, surface: *Surface) void { return; }; - const page = c.gtk_notebook_get_page(self.notebook, @ptrCast(tab.box)) orelse return; + const notebook: *c.GtkNotebook = self.notebook.as_notebook(); + const page = c.gtk_notebook_get_page(notebook, @ptrCast(tab.box)) orelse return; const page_idx = getNotebookPageIndex(page); // The next index is the previous or we wrap around. const next_idx = if (page_idx > 0) page_idx - 1 else next_idx: { - const max = c.gtk_notebook_get_n_pages(self.notebook); + const max = c.gtk_notebook_get_n_pages(notebook); break :next_idx max -| 1; }; // Do nothing if we have one tab if (next_idx == page_idx) return; - c.gtk_notebook_set_current_page(self.notebook, next_idx); + c.gtk_notebook_set_current_page(notebook, next_idx); self.focusCurrentTab(); } @@ -278,13 +392,14 @@ pub fn gotoNextTab(self: *Window, surface: *Surface) void { return; }; - const page = c.gtk_notebook_get_page(self.notebook, @ptrCast(tab.box)) orelse return; + const notebook: *c.GtkNotebook = self.notebook.as_notebook(); + const page = c.gtk_notebook_get_page(notebook, @ptrCast(tab.box)) orelse return; const page_idx = getNotebookPageIndex(page); - const max = c.gtk_notebook_get_n_pages(self.notebook) -| 1; + const max = c.gtk_notebook_get_n_pages(notebook) -| 1; const next_idx = if (page_idx < max) page_idx + 1 else 0; if (next_idx == page_idx) return; - c.gtk_notebook_set_current_page(self.notebook, next_idx); + c.gtk_notebook_set_current_page(notebook, next_idx); self.focusCurrentTab(); } @@ -298,10 +413,11 @@ pub fn gotoLastTab(self: *Window) void { /// Go to the specific tab index. pub fn gotoTab(self: *Window, n: usize) void { if (n == 0) return; - const max = c.gtk_notebook_get_n_pages(self.notebook); + const notebook: *c.GtkNotebook = self.notebook.as_notebook(); + const max = c.gtk_notebook_get_n_pages(notebook); const page_idx = std.math.cast(c_int, n - 1) orelse return; if (page_idx < max) { - c.gtk_notebook_set_current_page(self.notebook, page_idx); + c.gtk_notebook_set_current_page(notebook, page_idx); self.focusCurrentTab(); } } @@ -327,11 +443,13 @@ pub fn toggleWindowDecorations(self: *Window) void { /// Grabs focus on the currently selected tab. fn focusCurrentTab(self: *Window) void { - const page_idx = c.gtk_notebook_get_current_page(self.notebook); - const page = c.gtk_notebook_get_nth_page(self.notebook, page_idx); - const tab: *Tab = @ptrCast(@alignCast( - c.g_object_get_data(@ptrCast(page), Tab.GHOSTTY_TAB) orelse return, - )); + // const notebook: *c.GtkNotebook = self.notebook.as_notebook(); + // const page_idx = c.gtk_notebook_get_current_page(notebook); + // const page = c.gtk_notebook_get_nth_page(notebook, page_idx); + // const tab: *Tab = @ptrCast(@alignCast( + // c.g_object_get_data(@ptrCast(page), Tab.GHOSTTY_TAB) orelse return, + // )); + const tab = self.notebook.currentTab() orelse return; const gl_area = @as(*c.GtkWidget, @ptrCast(tab.focus_child.gl_area)); _ = c.gtk_widget_grab_focus(gl_area); } @@ -379,16 +497,18 @@ fn gtkPageRemoved( ) callconv(.C) void { const self = userdataSelf(ud.?); + const notebook: *c.GtkNotebook = self.notebook.as_notebook(); + // Hide the tab bar if we only have one tab after removal - const remaining = c.gtk_notebook_get_n_pages(self.notebook); + const remaining = c.gtk_notebook_get_n_pages(notebook); if (remaining == 1) { - c.gtk_notebook_set_show_tabs(self.notebook, 0); + c.gtk_notebook_set_show_tabs(notebook, 0); } } fn gtkSwitchPage(_: *c.GtkNotebook, page: *c.GtkWidget, _: usize, ud: ?*anyopaque) callconv(.C) void { const self = userdataSelf(ud.?); - const gtk_label_box = @as(*c.GtkWidget, @ptrCast(c.gtk_notebook_get_tab_label(self.notebook, page))); + const gtk_label_box = @as(*c.GtkWidget, @ptrCast(c.gtk_notebook_get_tab_label(self.notebook.as_notebook(), page))); const gtk_label = @as(*c.GtkLabel, @ptrCast(c.gtk_widget_get_first_child(gtk_label_box))); const label_text = c.gtk_label_get_text(gtk_label); c.gtk_window_set_title(self.window, label_text); @@ -417,7 +537,7 @@ fn gtkNotebookCreateWindow( // And add it to the new window. tab.window = window; - return window.notebook; + return window.notebook.as_notebook(); } fn gtkRefocusTerm(v: *c.GtkWindow, ud: ?*anyopaque) callconv(.C) bool { @@ -652,11 +772,13 @@ fn gtkActionReset( /// Returns the surface to use for an action. fn actionSurface(self: *Window) ?*CoreSurface { - const page_idx = c.gtk_notebook_get_current_page(self.notebook); - const page = c.gtk_notebook_get_nth_page(self.notebook, page_idx); - const tab: *Tab = @ptrCast(@alignCast( - c.g_object_get_data(@ptrCast(page), Tab.GHOSTTY_TAB) orelse return null, - )); + const tab = self.notebook.currentTab() orelse return null; + // const notebook: *c.GtkNotebook = self.notebook.as_notebook(); + // const page_idx = c.gtk_notebook_get_current_page(notebook); + // const page = c.gtk_notebook_get_nth_page(notebook, page_idx); + // const tab: *Tab = @ptrCast(@alignCast( + // c.g_object_get_data(@ptrCast(page), Tab.GHOSTTY_TAB) orelse return null, + // )); return &tab.focus_child.core_surface; }