diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-06-01 23:05:23 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-06-01 23:05:51 +0300 |
| commit | 5bd21b7ed468b5ff4d1a5b2ed7e211f401eb138a (patch) | |
| tree | 672fa4625cca0ecb3e9376fc7f8e33d7b0e9deef /vendor/libghostty-vt/src/apprt/gtk/class/surface.zig | |
| parent | 32abb3776668ee768200019c170956f67fe33a86 (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.zig | 84 |
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, |
