apprt/gtk-ng: workaround for tab overview selection

pull/8098/head
Mitchell Hashimoto 2025-07-29 10:39:42 -07:00
parent 16bb579bab
commit 8b14ab1221
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
3 changed files with 61 additions and 0 deletions

View File

@ -1050,6 +1050,13 @@ pub const Surface = extern struct {
);
}
/// Focus this surface. This properly focuses the input part of
/// our surface.
pub fn grabFocus(self: *Self) void {
const priv = self.private();
_ = priv.gl_area.as(gtk.Widget).grabFocus();
}
//---------------------------------------------------------------
// Virtual Methods

View File

@ -210,6 +210,9 @@ pub const Window = extern struct {
/// The configuration that this surface is using.
config: ?*Config = null,
/// See tabOverviewOpen for why we have this.
tab_overview_focus_timer: ?c_uint = null,
// Template bindings
tab_bar: *adw.TabBar,
tab_view: *adw.TabView,
@ -632,6 +635,55 @@ pub const Window = extern struct {
return self.newTabPage(if (self.getActiveSurface()) |v| v.core() else null);
}
fn tabOverviewOpen(
tab_overview: *adw.TabOverview,
_: *gobject.ParamSpec,
self: *Self,
) callconv(.c) void {
// We only care about when the tab overview is closed.
if (tab_overview.getOpen() != 0) return;
// On tab overview close, focus is sometimes lost. This is an
// upstream issue in libadwaita[1]. When this is resolved we
// can put a runtime version check here to avoid this workaround.
//
// Our workaround is to start a timer after 500ms to refocus
// the currently selected tab. We choose 500ms because the adw
// animation is 400ms.
//
// [1]: https://gitlab.gnome.org/GNOME/libadwaita/-/issues/670
// If we have an old timer remove it
const priv = self.private();
if (priv.tab_overview_focus_timer) |timer| {
_ = glib.Source.remove(timer);
}
// Restart our timer
priv.tab_overview_focus_timer = glib.timeoutAdd(
500,
tabOverviewFocusTimer,
self,
);
}
fn tabOverviewFocusTimer(
ud: ?*anyopaque,
) callconv(.c) c_int {
const self: *Self = @ptrCast(@alignCast(ud orelse return 0));
// Always note our timer is removed
self.private().tab_overview_focus_timer = null;
// Get our currently active surface which should respect the newly
// selected tab. Grab focus.
const surface = self.getActiveSurface() orelse return 0;
surface.grabFocus();
// Remove the timer
return 0;
}
fn windowCloseRequest(
_: *gtk.Window,
self: *Self,
@ -1105,6 +1157,7 @@ pub const Window = extern struct {
// Template Callbacks
class.bindTemplateCallback("new_tab", &btnNewTab);
class.bindTemplateCallback("overview_create_tab", &tabOverviewCreateTab);
class.bindTemplateCallback("overview_notify_open", &tabOverviewOpen);
class.bindTemplateCallback("close_request", &windowCloseRequest);
class.bindTemplateCallback("close_page", &tabViewClosePage);
class.bindTemplateCallback("page_attached", &tabViewPageAttached);

View File

@ -19,6 +19,7 @@ template $GhosttyWindow: Adw.ApplicationWindow {
content: Adw.TabOverview tab_overview {
create-tab => $overview_create_tab();
notify::open => $overview_notify_open();
enable-new-tab: true;
view: tab_view;