mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-09-05 19:08:17 +00:00
apprt/gtk-ng: hook up Tab signals to surface
This commit is contained in:
@@ -1318,6 +1318,11 @@ pub const Surface = extern struct {
|
||||
return self.private().pwd;
|
||||
}
|
||||
|
||||
/// Returns the focus state of this surface.
|
||||
pub fn getFocused(self: *Self) bool {
|
||||
return self.private().focused;
|
||||
}
|
||||
|
||||
/// Change the configuration for this surface.
|
||||
pub fn setConfig(self: *Self, config: *Config) void {
|
||||
const priv = self.private();
|
||||
@@ -1654,6 +1659,7 @@ pub const Surface = extern struct {
|
||||
priv.focused = true;
|
||||
priv.im_context.as(gtk.IMContext).focusIn();
|
||||
_ = glib.idleAddOnce(idleFocus, self.ref());
|
||||
self.as(gobject.Object).notifyByPspec(properties.focused.impl.param_spec);
|
||||
}
|
||||
|
||||
fn ecFocusLeave(_: *gtk.EventControllerFocus, self: *Self) callconv(.c) void {
|
||||
@@ -1661,6 +1667,7 @@ pub const Surface = extern struct {
|
||||
priv.focused = false;
|
||||
priv.im_context.as(gtk.IMContext).focusOut();
|
||||
_ = glib.idleAddOnce(idleFocus, self.ref());
|
||||
self.as(gobject.Object).notifyByPspec(properties.focused.impl.param_spec);
|
||||
}
|
||||
|
||||
/// The focus callback must be triggered on an idle loop source because
|
||||
|
@@ -139,7 +139,6 @@ pub const Tab = extern struct {
|
||||
|
||||
// Template bindings
|
||||
split_tree: *SplitTree,
|
||||
surface: *Surface,
|
||||
|
||||
pub var offset: c_int = 0;
|
||||
};
|
||||
@@ -147,12 +146,10 @@ pub const Tab = extern struct {
|
||||
/// Set the parent of this tab page. This only affects the first surface
|
||||
/// ever created for a tab. If a surface was already created this does
|
||||
/// nothing.
|
||||
pub fn setParent(
|
||||
self: *Self,
|
||||
parent: *CoreSurface,
|
||||
) void {
|
||||
const priv = self.private();
|
||||
priv.surface.setParent(parent);
|
||||
pub fn setParent(self: *Self, parent: *CoreSurface) void {
|
||||
if (self.getActiveSurface()) |surface| {
|
||||
surface.setParent(parent);
|
||||
}
|
||||
}
|
||||
|
||||
fn init(self: *Self, _: *Class) callconv(.c) void {
|
||||
@@ -175,10 +172,6 @@ pub const Tab = extern struct {
|
||||
.{},
|
||||
);
|
||||
|
||||
// TODO: Eventually this should be set dynamically based on the
|
||||
// current active surface.
|
||||
priv.surface_bindings.setSource(priv.surface.as(gobject.Object));
|
||||
|
||||
// We need to do this so that the title initializes properly,
|
||||
// I think because its a dynamic getter.
|
||||
self.as(gobject.Object).notifyByPspec(properties.@"active-surface".impl.param_spec);
|
||||
@@ -194,14 +187,62 @@ pub const Tab = extern struct {
|
||||
priv.split_tree.setTree(&tree);
|
||||
}
|
||||
|
||||
fn connectSurfaceHandlers(
|
||||
self: *Self,
|
||||
tree: *const Surface.Tree,
|
||||
) void {
|
||||
var it = tree.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const surface = entry.view;
|
||||
_ = Surface.signals.@"close-request".connect(
|
||||
surface,
|
||||
*Self,
|
||||
surfaceCloseRequest,
|
||||
self,
|
||||
.{},
|
||||
);
|
||||
_ = gobject.Object.signals.notify.connect(
|
||||
surface,
|
||||
*Self,
|
||||
propSurfaceFocused,
|
||||
self,
|
||||
.{ .detail = "focused" },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn disconnectSurfaceHandlers(
|
||||
self: *Self,
|
||||
tree: *const Surface.Tree,
|
||||
) void {
|
||||
var it = tree.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const surface = entry.view;
|
||||
_ = gobject.signalHandlersDisconnectMatched(
|
||||
surface.as(gobject.Object),
|
||||
.{ .data = true },
|
||||
0,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
self,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Properties
|
||||
|
||||
/// Get the currently active surface. See the "active-surface" property.
|
||||
/// This does not ref the value.
|
||||
pub fn getActiveSurface(self: *Self) *Surface {
|
||||
const priv = self.private();
|
||||
return priv.surface;
|
||||
pub fn getActiveSurface(self: *Self) ?*Surface {
|
||||
const tree = self.getSurfaceTree() orelse return null;
|
||||
var it = tree.iterator();
|
||||
while (it.next()) |entry| {
|
||||
if (entry.view.getFocused()) return entry.view;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Get the surface tree of this tab.
|
||||
@@ -219,7 +260,7 @@ pub const Tab = extern struct {
|
||||
/// Returns true if this tab needs confirmation before quitting based
|
||||
/// on the various Ghostty configurations.
|
||||
pub fn getNeedsConfirmQuit(self: *Self) bool {
|
||||
const surface = self.getActiveSurface();
|
||||
const surface = self.getActiveSurface() orelse return false;
|
||||
const core_surface = surface.core() orelse return false;
|
||||
return core_surface.needsConfirmQuit();
|
||||
}
|
||||
@@ -283,6 +324,20 @@ pub const Tab = extern struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn splitTreeWillChange(
|
||||
split_tree: *SplitTree,
|
||||
new_tree: ?*const Surface.Tree,
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
if (split_tree.getTree()) |old_tree| {
|
||||
self.disconnectSurfaceHandlers(old_tree);
|
||||
}
|
||||
|
||||
if (new_tree) |tree| {
|
||||
self.connectSurfaceHandlers(tree);
|
||||
}
|
||||
}
|
||||
|
||||
fn propSplitTree(
|
||||
_: *SplitTree,
|
||||
_: *gobject.ParamSpec,
|
||||
@@ -291,6 +346,27 @@ pub const Tab = extern struct {
|
||||
self.as(gobject.Object).notifyByPspec(properties.@"surface-tree".impl.param_spec);
|
||||
}
|
||||
|
||||
fn propActiveSurface(
|
||||
_: *Self,
|
||||
_: *gobject.ParamSpec,
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
const priv = self.private();
|
||||
priv.surface_bindings.setSource(null);
|
||||
if (self.getActiveSurface()) |surface| {
|
||||
priv.surface_bindings.setSource(surface.as(gobject.Object));
|
||||
}
|
||||
}
|
||||
|
||||
fn propSurfaceFocused(
|
||||
surface: *Surface,
|
||||
_: *gobject.ParamSpec,
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
if (!surface.getFocused()) return;
|
||||
self.as(gobject.Object).notifyByPspec(properties.@"active-surface".impl.param_spec);
|
||||
}
|
||||
|
||||
const C = Common(Self, Private);
|
||||
pub const as = C.as;
|
||||
pub const ref = C.ref;
|
||||
@@ -324,10 +400,10 @@ pub const Tab = extern struct {
|
||||
|
||||
// Bindings
|
||||
class.bindTemplateChildPrivate("split_tree", .{});
|
||||
class.bindTemplateChildPrivate("surface", .{});
|
||||
|
||||
// Template Callbacks
|
||||
class.bindTemplateCallback("surface_close_request", &surfaceCloseRequest);
|
||||
class.bindTemplateCallback("tree_will_change", &splitTreeWillChange);
|
||||
class.bindTemplateCallback("notify_active_surface", &propActiveSurface);
|
||||
class.bindTemplateCallback("notify_tree", &propSplitTree);
|
||||
|
||||
// Signals
|
||||
|
@@ -5,16 +5,13 @@ template $GhosttyTab: Box {
|
||||
"tab",
|
||||
]
|
||||
|
||||
notify::active-surface => $notify_active_surface();
|
||||
orientation: vertical;
|
||||
hexpand: true;
|
||||
vexpand: true;
|
||||
// A tab currently just contains a surface directly. When we introduce
|
||||
// splits we probably want to replace this with the split widget type.
|
||||
$GhosttySurface surface {
|
||||
close-request => $surface_close_request();
|
||||
}
|
||||
|
||||
$GhosttySplitTree split_tree {
|
||||
notify::tree => $notify_tree();
|
||||
tree-will-change => $tree_will_change();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user