mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
only initialize font discovery mechanism once, cache on App
Fontconfig in particular appears unsafe to initialize multiple times. Font discovery is a singleton object in an application and only ever accessed from the main thread so we can work around this by only initializing and caching the font discovery mechanism exactly once on the app singleton.
This commit is contained in:
21
src/App.zig
21
src/App.zig
@ -45,6 +45,11 @@ quit: bool,
|
|||||||
/// from source. This is null if we can't detect it.
|
/// from source. This is null if we can't detect it.
|
||||||
resources_dir: ?[]const u8 = null,
|
resources_dir: ?[]const u8 = null,
|
||||||
|
|
||||||
|
/// Font discovery mechanism. This is only safe to use from the main thread.
|
||||||
|
/// This is lazily initialized on the first call to fontDiscover so do
|
||||||
|
/// not access this directly.
|
||||||
|
font_discover: ?font.Discover = null,
|
||||||
|
|
||||||
/// Initialize the main app instance. This creates the main window, sets
|
/// Initialize the main app instance. This creates the main window, sets
|
||||||
/// up the renderer state, compiles the shaders, etc. This is the primary
|
/// up the renderer state, compiles the shaders, etc. This is the primary
|
||||||
/// "startup" logic.
|
/// "startup" logic.
|
||||||
@ -80,6 +85,8 @@ pub fn destroy(self: *App) void {
|
|||||||
self.surfaces.deinit(self.alloc);
|
self.surfaces.deinit(self.alloc);
|
||||||
|
|
||||||
if (self.resources_dir) |dir| self.alloc.free(dir);
|
if (self.resources_dir) |dir| self.alloc.free(dir);
|
||||||
|
if (self.font_discover) |*v| v.deinit();
|
||||||
|
|
||||||
self.alloc.destroy(self);
|
self.alloc.destroy(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +158,20 @@ pub fn focusedSurface(self: *const App) ?*Surface {
|
|||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initialize once and return the font discovery mechanism. This remains
|
||||||
|
/// initialized throughout the lifetime of the application because some
|
||||||
|
/// font discovery mechanisms (i.e. fontconfig) are unsafe to reinit.
|
||||||
|
pub fn fontDiscover(self: *App) !?font.Discover {
|
||||||
|
// If we're built without a font discovery mechanism, return null
|
||||||
|
if (comptime font.Discover == void) return null;
|
||||||
|
|
||||||
|
// If we initialized, use it
|
||||||
|
if (self.font_discover) |v| return v;
|
||||||
|
|
||||||
|
self.font_discover = font.Discover.init();
|
||||||
|
return self.font_discover.?;
|
||||||
|
}
|
||||||
|
|
||||||
/// Drain the mailbox.
|
/// Drain the mailbox.
|
||||||
fn drainMailbox(self: *App, rt_app: *apprt.App) !void {
|
fn drainMailbox(self: *App, rt_app: *apprt.App) !void {
|
||||||
while (self.mailbox.pop()) |message| {
|
while (self.mailbox.pop()) |message| {
|
||||||
|
@ -177,8 +177,8 @@ pub fn init(
|
|||||||
self: *Surface,
|
self: *Surface,
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
config: *const configpkg.Config,
|
config: *const configpkg.Config,
|
||||||
|
app: *App,
|
||||||
app_mailbox: App.Mailbox,
|
app_mailbox: App.Mailbox,
|
||||||
app_resources_dir: ?[]const u8,
|
|
||||||
rt_surface: *apprt.runtime.Surface,
|
rt_surface: *apprt.runtime.Surface,
|
||||||
) !void {
|
) !void {
|
||||||
// Initialize our renderer with our initialized surface.
|
// Initialize our renderer with our initialized surface.
|
||||||
@ -217,8 +217,11 @@ pub fn init(
|
|||||||
errdefer group.deinit();
|
errdefer group.deinit();
|
||||||
|
|
||||||
// Search for fonts
|
// Search for fonts
|
||||||
if (font.Discover != void) {
|
if (font.Discover != void) discover: {
|
||||||
var disco = font.Discover.init();
|
const disco = try app.fontDiscover() orelse {
|
||||||
|
log.warn("font discovery not available, cannot search for fonts", .{});
|
||||||
|
break :discover;
|
||||||
|
};
|
||||||
group.discover = disco;
|
group.discover = disco;
|
||||||
|
|
||||||
if (config.@"font-family") |family| {
|
if (config.@"font-family") |family| {
|
||||||
@ -320,16 +323,16 @@ pub fn init(
|
|||||||
|
|
||||||
// If we're on Mac, then we try to use the Apple Emoji font for Emoji.
|
// If we're on Mac, then we try to use the Apple Emoji font for Emoji.
|
||||||
if (builtin.os.tag == .macos and font.Discover != void) {
|
if (builtin.os.tag == .macos and font.Discover != void) {
|
||||||
var disco = font.Discover.init();
|
if (try app.fontDiscover()) |disco| {
|
||||||
defer disco.deinit();
|
var disco_it = try disco.discover(.{
|
||||||
var disco_it = try disco.discover(.{
|
.family = "Apple Color Emoji",
|
||||||
.family = "Apple Color Emoji",
|
.size = font_size.points,
|
||||||
.size = font_size.points,
|
});
|
||||||
});
|
defer disco_it.deinit();
|
||||||
defer disco_it.deinit();
|
if (try disco_it.next()) |face| {
|
||||||
if (try disco_it.next()) |face| {
|
log.info("font emoji: {s}", .{try face.name()});
|
||||||
log.info("font emoji: {s}", .{try face.name()});
|
try group.addFace(alloc, .regular, face);
|
||||||
try group.addFace(alloc, .regular, face);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,7 +405,7 @@ pub fn init(
|
|||||||
.screen_size = screen_size,
|
.screen_size = screen_size,
|
||||||
.full_config = config,
|
.full_config = config,
|
||||||
.config = try termio.Impl.DerivedConfig.init(alloc, config),
|
.config = try termio.Impl.DerivedConfig.init(alloc, config),
|
||||||
.resources_dir = app_resources_dir,
|
.resources_dir = app.resources_dir,
|
||||||
.renderer_state = &self.renderer_state,
|
.renderer_state = &self.renderer_state,
|
||||||
.renderer_wakeup = render_thread.wakeup,
|
.renderer_wakeup = render_thread.wakeup,
|
||||||
.renderer_mailbox = render_thread.mailbox,
|
.renderer_mailbox = render_thread.mailbox,
|
||||||
|
@ -196,8 +196,8 @@ pub const Surface = struct {
|
|||||||
try self.core_surface.init(
|
try self.core_surface.init(
|
||||||
app.core_app.alloc,
|
app.core_app.alloc,
|
||||||
&config,
|
&config,
|
||||||
|
app.core_app,
|
||||||
.{ .rt_app = app, .mailbox = &app.core_app.mailbox },
|
.{ .rt_app = app, .mailbox = &app.core_app.mailbox },
|
||||||
app.core_app.resources_dir,
|
|
||||||
self,
|
self,
|
||||||
);
|
);
|
||||||
errdefer self.core_surface.deinit();
|
errdefer self.core_surface.deinit();
|
||||||
|
@ -374,8 +374,8 @@ pub const Surface = struct {
|
|||||||
try self.core_surface.init(
|
try self.core_surface.init(
|
||||||
app.app.alloc,
|
app.app.alloc,
|
||||||
&config,
|
&config,
|
||||||
|
app.app,
|
||||||
.{ .rt_app = app, .mailbox = &app.app.mailbox },
|
.{ .rt_app = app, .mailbox = &app.app.mailbox },
|
||||||
app.app.resources_dir,
|
|
||||||
self,
|
self,
|
||||||
);
|
);
|
||||||
errdefer self.core_surface.deinit();
|
errdefer self.core_surface.deinit();
|
||||||
|
@ -789,8 +789,8 @@ pub const Surface = struct {
|
|||||||
try self.core_surface.init(
|
try self.core_surface.init(
|
||||||
self.app.core_app.alloc,
|
self.app.core_app.alloc,
|
||||||
&config,
|
&config,
|
||||||
|
self.app.core_app,
|
||||||
.{ .rt_app = self.app, .mailbox = &self.app.core_app.mailbox },
|
.{ .rt_app = self.app, .mailbox = &self.app.core_app.mailbox },
|
||||||
self.app.core_app.resources_dir,
|
|
||||||
self,
|
self,
|
||||||
);
|
);
|
||||||
errdefer self.core_surface.deinit();
|
errdefer self.core_surface.deinit();
|
||||||
@ -1203,6 +1203,14 @@ pub const Surface = struct {
|
|||||||
break :key input.Key.fromASCII(self.im_buf[0]) orelse physical_key;
|
break :key input.Key.fromASCII(self.im_buf[0]) orelse physical_key;
|
||||||
} else .invalid;
|
} else .invalid;
|
||||||
|
|
||||||
|
// log.debug("key pressed key={} physical_key={} composing={} text_len={} mods={}", .{
|
||||||
|
// key,
|
||||||
|
// physical_key,
|
||||||
|
// self.im_composing,
|
||||||
|
// self.im_len,
|
||||||
|
// mods,
|
||||||
|
// });
|
||||||
|
|
||||||
// If both keys are invalid then we won't call the key callback. But
|
// If both keys are invalid then we won't call the key callback. But
|
||||||
// if either one is valid, we want to give it a chance.
|
// if either one is valid, we want to give it a chance.
|
||||||
if (key != .invalid or physical_key != .invalid) {
|
if (key != .invalid or physical_key != .invalid) {
|
||||||
@ -1342,6 +1350,8 @@ pub const Surface = struct {
|
|||||||
if (str.len <= self.im_buf.len) {
|
if (str.len <= self.im_buf.len) {
|
||||||
@memcpy(self.im_buf[0..str.len], str);
|
@memcpy(self.im_buf[0..str.len], str);
|
||||||
self.im_len = @intCast(str.len);
|
self.im_len = @intCast(str.len);
|
||||||
|
|
||||||
|
// log.debug("input commit: {x}", .{self.im_buf[0]});
|
||||||
} else {
|
} else {
|
||||||
log.warn("not enough buffer space for input method commit", .{});
|
log.warn("not enough buffer space for input method commit", .{});
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ pub const Fontconfig = struct {
|
|||||||
|
|
||||||
/// Discover fonts from a descriptor. This returns an iterator that can
|
/// Discover fonts from a descriptor. This returns an iterator that can
|
||||||
/// be used to build up the deferred fonts.
|
/// be used to build up the deferred fonts.
|
||||||
pub fn discover(self: *Fontconfig, desc: Descriptor) !DiscoverIterator {
|
pub fn discover(self: *const Fontconfig, desc: Descriptor) !DiscoverIterator {
|
||||||
// Build our pattern that we'll search for
|
// Build our pattern that we'll search for
|
||||||
const pat = desc.toFcPattern();
|
const pat = desc.toFcPattern();
|
||||||
errdefer pat.destroy();
|
errdefer pat.destroy();
|
||||||
|
Reference in New Issue
Block a user