mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
Merge pull request #471 from mitchellh/mode-warning
macos, gtk: show warning when running with debug build
This commit is contained in:
@ -284,9 +284,22 @@ typedef struct {
|
||||
bool physical;
|
||||
} ghostty_input_trigger_s;
|
||||
|
||||
typedef enum {
|
||||
GHOSTTY_BUILD_MODE_DEBUG,
|
||||
GHOSTTY_BUILD_MODE_RELEASE_SAFE,
|
||||
GHOSTTY_BUILD_MODE_RELEASE_FAST,
|
||||
GHOSTTY_BUILD_MODE_RELEASE_SMALL,
|
||||
} ghostty_build_mode_e;
|
||||
|
||||
// Fully defined types. This MUST be kept in sync with equivalent Zig
|
||||
// structs. To find the Zig struct, grep for this type name. The documentation
|
||||
// for all of these types is available in the Zig source.
|
||||
typedef struct {
|
||||
ghostty_build_mode_e build_mode;
|
||||
const char *version;
|
||||
uintptr_t version_len;
|
||||
} ghostty_info_s;
|
||||
|
||||
typedef struct {
|
||||
const char *message;
|
||||
} ghostty_error_s;
|
||||
@ -338,6 +351,7 @@ typedef struct {
|
||||
// Published API
|
||||
|
||||
int ghostty_init(void);
|
||||
ghostty_info_s ghostty_info(void);
|
||||
|
||||
ghostty_config_t ghostty_config_new();
|
||||
void ghostty_config_free(ghostty_config_t);
|
||||
|
@ -94,38 +94,46 @@ struct PrimaryView: View {
|
||||
self.appDelegate.confirmQuit = $0
|
||||
})
|
||||
|
||||
Ghostty.TerminalSplit(onClose: Self.closeWindow, baseConfig: self.baseConfig)
|
||||
.ghosttyApp(ghostty.app!)
|
||||
.ghosttyConfig(ghostty.config!)
|
||||
.background(WindowAccessor(window: $window))
|
||||
.onReceive(gotoTab) { onGotoTab(notification: $0) }
|
||||
.onReceive(toggleFullscreen) { onToggleFullscreen(notification: $0) }
|
||||
.focused($focused)
|
||||
.onAppear { self.focused = true }
|
||||
.onChange(of: focusedSurface) { newValue in
|
||||
self.focusedSurfaceWrapper.surface = newValue?.surface
|
||||
VStack(spacing: 0) {
|
||||
// If we're running in debug mode we show a warning so that users
|
||||
// know that performance will be degraded.
|
||||
if (ghostty.info.mode == GHOSTTY_BUILD_MODE_DEBUG) {
|
||||
DebugBuildWarningView()
|
||||
}
|
||||
.onChange(of: title) { newValue in
|
||||
// We need to handle this manually because we are using AppKit lifecycle
|
||||
// so navigationTitle no longer works.
|
||||
guard let window = self.window else { return }
|
||||
window.title = newValue
|
||||
}
|
||||
.confirmationDialog(
|
||||
"Quit Ghostty?",
|
||||
isPresented: confirmQuitting) {
|
||||
Button("Close Ghostty") {
|
||||
NSApplication.shared.reply(toApplicationShouldTerminate: true)
|
||||
}
|
||||
.keyboardShortcut(.defaultAction)
|
||||
|
||||
Button("Cancel", role: .cancel) {
|
||||
NSApplication.shared.reply(toApplicationShouldTerminate: false)
|
||||
}
|
||||
.keyboardShortcut(.cancelAction)
|
||||
} message: {
|
||||
Text("All terminal sessions will be terminated.")
|
||||
|
||||
Ghostty.TerminalSplit(onClose: Self.closeWindow, baseConfig: self.baseConfig)
|
||||
.ghosttyApp(ghostty.app!)
|
||||
.ghosttyConfig(ghostty.config!)
|
||||
.background(WindowAccessor(window: $window))
|
||||
.onReceive(gotoTab) { onGotoTab(notification: $0) }
|
||||
.onReceive(toggleFullscreen) { onToggleFullscreen(notification: $0) }
|
||||
.focused($focused)
|
||||
.onAppear { self.focused = true }
|
||||
.onChange(of: focusedSurface) { newValue in
|
||||
self.focusedSurfaceWrapper.surface = newValue?.surface
|
||||
}
|
||||
.onChange(of: title) { newValue in
|
||||
// We need to handle this manually because we are using AppKit lifecycle
|
||||
// so navigationTitle no longer works.
|
||||
guard let window = self.window else { return }
|
||||
window.title = newValue
|
||||
}
|
||||
.confirmationDialog(
|
||||
"Quit Ghostty?",
|
||||
isPresented: confirmQuitting) {
|
||||
Button("Close Ghostty") {
|
||||
NSApplication.shared.reply(toApplicationShouldTerminate: true)
|
||||
}
|
||||
.keyboardShortcut(.defaultAction)
|
||||
|
||||
Button("Cancel", role: .cancel) {
|
||||
NSApplication.shared.reply(toApplicationShouldTerminate: false)
|
||||
}
|
||||
.keyboardShortcut(.cancelAction)
|
||||
} message: {
|
||||
Text("All terminal sessions will be terminated.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,3 +204,34 @@ struct PrimaryView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DebugBuildWarningView: View {
|
||||
@State private var isPopover = false
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
Image(systemName: "exclamationmark.triangle.fill")
|
||||
.foregroundColor(.yellow)
|
||||
|
||||
Text("You're running a debug build of Ghostty! Performance will be degraded.")
|
||||
.padding(.all, 8)
|
||||
.popover(isPresented: $isPopover, arrowEdge: .bottom) {
|
||||
Text("""
|
||||
Debug builds of Ghostty are very slow and you may experience
|
||||
performance problems. Debug builds are only recommended during
|
||||
development.
|
||||
""")
|
||||
.padding(.all)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.background(Color(.windowBackgroundColor))
|
||||
.frame(maxWidth: .infinity)
|
||||
.onTapGesture {
|
||||
isPopover = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,11 @@ extension Ghostty {
|
||||
case loading, error, ready
|
||||
}
|
||||
|
||||
struct Info {
|
||||
var mode: ghostty_build_mode_e
|
||||
var version: String
|
||||
}
|
||||
|
||||
/// The AppState is the global state that is associated with the Swift app. This handles initially
|
||||
/// initializing Ghostty, loading the configuration, etc.
|
||||
class AppState: ObservableObject {
|
||||
@ -46,6 +51,18 @@ extension Ghostty {
|
||||
return ghostty_app_needs_confirm_quit(app)
|
||||
}
|
||||
|
||||
/// Build information
|
||||
var info: Info {
|
||||
let raw = ghostty_info()
|
||||
let version = NSString(
|
||||
bytes: raw.version,
|
||||
length: Int(raw.version_len),
|
||||
encoding: NSUTF8StringEncoding
|
||||
) ?? "unknown"
|
||||
|
||||
return Info(mode: raw.build_mode, version: String(version))
|
||||
}
|
||||
|
||||
/// Cached clipboard string for `read_clipboard` callback.
|
||||
private var cached_clipboard_string: String? = nil
|
||||
|
||||
|
@ -392,14 +392,32 @@ const Window = struct {
|
||||
c.gtk_notebook_set_show_tabs(notebook, 0);
|
||||
c.gtk_notebook_set_show_border(notebook, 0);
|
||||
|
||||
// This is important so the notebook expands to fit available space.
|
||||
// Otherwise, it will be zero/zero in the box below.
|
||||
c.gtk_widget_set_vexpand(notebook_widget, 1);
|
||||
c.gtk_widget_set_hexpand(notebook_widget, 1);
|
||||
|
||||
// Create our add button for new tabs
|
||||
const notebook_add_btn = c.gtk_button_new_from_icon_name("list-add-symbolic");
|
||||
c.gtk_notebook_set_action_widget(notebook, notebook_add_btn, c.GTK_PACK_END);
|
||||
_ = c.g_signal_connect_data(notebook_add_btn, "clicked", c.G_CALLBACK(>kTabAddClick), self, null, G_CONNECT_DEFAULT);
|
||||
_ = c.g_signal_connect_data(notebook, "switch-page", c.G_CALLBACK(>kSwitchPage), self, null, G_CONNECT_DEFAULT);
|
||||
|
||||
// The notebook is our main child
|
||||
c.gtk_window_set_child(gtk_window, notebook_widget);
|
||||
// Create our box which will hold our widgets.
|
||||
const box = c.gtk_box_new(c.GTK_ORIENTATION_VERTICAL, 0);
|
||||
|
||||
// In debug we show a warning. This is a really common issue where
|
||||
// people build from source in debug and performance is really bad.
|
||||
if (builtin.mode == .Debug) {
|
||||
const warning = c.gtk_label_new("⚠️ You're running a debug build of Ghostty! Performance will be degraded.");
|
||||
c.gtk_widget_set_margin_top(warning, 10);
|
||||
c.gtk_widget_set_margin_bottom(warning, 10);
|
||||
c.gtk_box_append(@ptrCast(box), warning);
|
||||
}
|
||||
c.gtk_box_append(@ptrCast(box), notebook_widget);
|
||||
|
||||
// The box is our main child
|
||||
c.gtk_window_set_child(gtk_window, box);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Window) void {
|
||||
|
@ -9,6 +9,7 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const builtin = @import("builtin");
|
||||
const build_config = @import("build_config.zig");
|
||||
const main = @import("main.zig");
|
||||
const apprt = @import("apprt.zig");
|
||||
|
||||
@ -23,6 +24,20 @@ pub const std_options = main.std_options;
|
||||
pub usingnamespace @import("config.zig").CAPI;
|
||||
pub usingnamespace apprt.runtime.CAPI;
|
||||
|
||||
/// ghostty_info_s
|
||||
const Info = extern struct {
|
||||
mode: BuildMode,
|
||||
version: [*]const u8,
|
||||
version_len: usize,
|
||||
|
||||
const BuildMode = enum(c_int) {
|
||||
debug,
|
||||
release_safe,
|
||||
release_fast,
|
||||
release_small,
|
||||
};
|
||||
};
|
||||
|
||||
/// Initialize ghostty global state. It is possible to have more than
|
||||
/// one global state but it has zero practical benefit.
|
||||
export fn ghostty_init() c_int {
|
||||
@ -33,3 +48,16 @@ export fn ghostty_init() c_int {
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
export fn ghostty_info() Info {
|
||||
return .{
|
||||
.mode = switch (builtin.mode) {
|
||||
.Debug => .debug,
|
||||
.ReleaseSafe => .release_safe,
|
||||
.ReleaseFast => .release_fast,
|
||||
.ReleaseSmall => .release_small,
|
||||
},
|
||||
.version = build_config.version_string.ptr,
|
||||
.version_len = build_config.version_string.len,
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user