aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/apprt/gtk/class/surface.zig
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-06-01 23:05:23 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-06-01 23:05:51 +0300
commit5bd21b7ed468b5ff4d1a5b2ed7e211f401eb138a (patch)
tree672fa4625cca0ecb3e9376fc7f8e33d7b0e9deef /vendor/libghostty-vt/src/apprt/gtk/class/surface.zig
parent32abb3776668ee768200019c170956f67fe33a86 (diff)
chore: update libghostty vendor
refs #276
Diffstat (limited to 'vendor/libghostty-vt/src/apprt/gtk/class/surface.zig')
-rw-r--r--vendor/libghostty-vt/src/apprt/gtk/class/surface.zig84
1 files changed, 81 insertions, 3 deletions
diff --git a/vendor/libghostty-vt/src/apprt/gtk/class/surface.zig b/vendor/libghostty-vt/src/apprt/gtk/class/surface.zig
index 179c779d..629866dc 100644
--- a/vendor/libghostty-vt/src/apprt/gtk/class/surface.zig
+++ b/vendor/libghostty-vt/src/apprt/gtk/class/surface.zig
@@ -169,6 +169,24 @@ pub const Surface = extern struct {
);
};
+ pub const mapped = struct {
+ pub const name = "mapped";
+ const impl = gobject.ext.defineProperty(
+ name,
+ Self,
+ bool,
+ .{
+ .default = false,
+ .accessor = gobject.ext.privateFieldAccessor(
+ Self,
+ Private,
+ &Private.offset,
+ "mapped",
+ ),
+ },
+ );
+ };
+
pub const @"min-size" = struct {
pub const name = "min-size";
const impl = gobject.ext.defineProperty(
@@ -592,11 +610,15 @@ pub const Surface = extern struct {
/// focus events.
focused: bool = true,
+ /// Whether the GLArea widget is mapped. Some operations like grabbing
+ /// focus only work if a widget is mapped.
+ mapped: bool = false,
+
/// Whether this surface is "zoomed" or not. A zoomed surface
/// shows up taking the full bounds of a split view.
zoom: bool = false,
- /// The GLAarea that renders the actual surface. This is a binding
+ /// The GLArea that renders the actual surface. This is a binding
/// to the template so it doesn't have to be unrefed manually.
gl_area: *gtk.GLArea,
@@ -652,6 +674,12 @@ pub const Surface = extern struct {
// false by a parent widget.
bell_ringing: bool = false,
+ // The audio bell's MediaFile, reused across bells so we don't leak a
+ // GStreamer pipeline (and its GL threads) on every ring. Built lazily
+ // on the first audio bell and rebuilt when `bell-audio-path` changes;
+ // unref'd on dispose. See ringBell and media.zig.
+ bell_media: ?*gtk.MediaFile = null,
+
/// True if this surface is in an error state. This is currently
/// a simple boolean with no additional information on WHAT the
/// error state is, because we don't yet need it or use it. For now,
@@ -1768,6 +1796,7 @@ pub const Surface = extern struct {
priv.mouse_shape = .text;
priv.mouse_hidden = false;
priv.focused = true;
+ priv.mapped = false;
priv.size = .{ .width = 0, .height = 0 };
priv.vadj_signal_group = null;
@@ -1831,6 +1860,11 @@ pub const Surface = extern struct {
priv.config = null;
}
+ if (priv.bell_media) |v| {
+ v.unref();
+ priv.bell_media = null;
+ }
+
if (priv.vadj_signal_group) |group| {
group.setTarget(null);
group.as(gobject.Object).unref();
@@ -2019,6 +2053,11 @@ pub const Surface = extern struct {
return self.private().focused;
}
+ /// Returns true if the GLArea of this surface is mapped.
+ pub fn getMapped(self: *Self) bool {
+ return self.private().mapped;
+ }
+
/// Change the configuration for this surface.
pub fn setConfig(self: *Self, config: *Config) void {
const priv = self.private();
@@ -2458,8 +2497,15 @@ pub const Surface = extern struct {
1.0,
);
- const media_file = media.fromFilename(path) orelse break :audio;
- media.playMediaFile(media_file, volume, required);
+ // Reuse one MediaFile per surface (rebuilt only when the path
+ // changes) so each bell replays the same pipeline instead of
+ // leaking a fresh one. Assign unconditionally: bellMediaFile frees
+ // any stale MediaFile and returns the current slot value (possibly
+ // null if the path is now inaccessible), so priv.bell_media never
+ // dangles.
+ priv.bell_media = media.bellMediaFile(priv.bell_media, path, required);
+ const media_file = priv.bell_media orelse break :audio;
+ media.playBell(media_file, volume);
}
}
@@ -3250,6 +3296,35 @@ pub const Surface = extern struct {
priv.im_context.as(gtk.IMContext).setClientWidget(null);
}
+ fn glareaMap(
+ _: *gtk.GLArea,
+ self: *Self,
+ ) callconv(.c) void {
+ self.updateMapped(true);
+ self.updateOcclusion(true);
+ }
+
+ fn glareaUnmap(
+ _: *gtk.GLArea,
+ self: *Self,
+ ) callconv(.c) void {
+ self.updateMapped(false);
+ self.updateOcclusion(false);
+ }
+
+ fn updateMapped(self: *Self, mapped: bool) void {
+ const priv = self.private();
+ priv.mapped = mapped;
+ self.as(gobject.Object).notifyByPspec(properties.mapped.impl.param_spec);
+ }
+
+ fn updateOcclusion(self: *Self, visible: bool) void {
+ const surface = self.core() orelse return;
+ surface.occlusionCallback(visible) catch |err| {
+ log.warn("error in occlusion callback err={}", .{err});
+ };
+ }
+
fn glareaRender(
_: *gtk.GLArea,
_: *gdk.GLContext,
@@ -3560,6 +3635,8 @@ pub const Surface = extern struct {
class.bindTemplateCallback("drop", &dtDrop);
class.bindTemplateCallback("gl_realize", &glareaRealize);
class.bindTemplateCallback("gl_unrealize", &glareaUnrealize);
+ class.bindTemplateCallback("gl_map", &glareaMap);
+ class.bindTemplateCallback("gl_unmap", &glareaUnmap);
class.bindTemplateCallback("gl_render", &glareaRender);
class.bindTemplateCallback("gl_resize", &glareaResize);
class.bindTemplateCallback("im_preedit_start", &imPreeditStart);
@@ -3592,6 +3669,7 @@ pub const Surface = extern struct {
properties.@"error".impl,
properties.@"font-size-request".impl,
properties.focused.impl,
+ properties.mapped.impl,
properties.@"key-sequence".impl,
properties.@"key-table".impl,
properties.@"min-size".impl,