From e3fbbe8fe31e821116aa5270c764aed7712ab021 Mon Sep 17 00:00:00 2001 From: Leah Amelia Chen Date: Tue, 18 Mar 2025 08:33:28 +0100 Subject: [PATCH 1/6] ci(test/translations): ignore untranslated entries --- .github/workflows/test.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 056151373..037c7bb15 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -697,7 +697,10 @@ jobs: msgcmp "$old_pot" po/com.mitchellh.ghostty.pot --use-untranslated # Compare all other POs to current POT - for f in po/*.po; do msgcmp "$f" po/com.mitchellh.ghostty.pot; done + for f in po/*.po; do + # Ignore untranslated entries + msgcmp --use-untranslated "$f" po/com.mitchellh.ghostty.pot; + done test-pkg-linux: strategy: From 1ee9c85954d5d607293fe0d0c276981d1121710a Mon Sep 17 00:00:00 2001 From: Leah Amelia Chen Date: Tue, 18 Mar 2025 10:39:54 +0100 Subject: [PATCH 2/6] gtk: port inspector & key handling to zig-gobject --- src/apprt/gtk/ClipboardConfirmationWindow.zig | 1 - src/apprt/gtk/ImguiWidget.zig | 328 +++++++++++------- src/apprt/gtk/inspector.zig | 37 +- src/apprt/gtk/key.zig | 271 +++++++-------- 4 files changed, 354 insertions(+), 283 deletions(-) diff --git a/src/apprt/gtk/ClipboardConfirmationWindow.zig b/src/apprt/gtk/ClipboardConfirmationWindow.zig index 9260d1c7b..803660794 100644 --- a/src/apprt/gtk/ClipboardConfirmationWindow.zig +++ b/src/apprt/gtk/ClipboardConfirmationWindow.zig @@ -12,7 +12,6 @@ const gio = @import("gio"); const apprt = @import("../../apprt.zig"); const CoreSurface = @import("../../Surface.zig"); const App = @import("App.zig"); -const View = @import("View.zig"); const Builder = @import("Builder.zig"); const adwaita = @import("adwaita.zig"); diff --git a/src/apprt/gtk/ImguiWidget.zig b/src/apprt/gtk/ImguiWidget.zig index 735629341..71b1c7f1d 100644 --- a/src/apprt/gtk/ImguiWidget.zig +++ b/src/apprt/gtk/ImguiWidget.zig @@ -3,10 +3,12 @@ const ImguiWidget = @This(); const std = @import("std"); const assert = std.debug.assert; +const gdk = @import("gdk"); +const gtk = @import("gtk"); const cimgui = @import("cimgui"); -const c = @import("c.zig").c; -const key = @import("key.zig"); const gl = @import("opengl"); + +const key = @import("key.zig"); const input = @import("../../input.zig"); const log = std.log.scoped(.gtk_imgui_widget); @@ -16,8 +18,8 @@ render_callback: ?*const fn (?*anyopaque) void = null, render_userdata: ?*anyopaque = null, /// Our OpenGL widget -gl_area: *c.GtkGLArea, -im_context: *c.GtkIMContext, +gl_area: *gtk.GLArea, +im_context: *gtk.IMContext, /// ImGui Context ig_ctx: *cimgui.c.ImGuiContext, @@ -36,65 +38,145 @@ pub fn init(self: *ImguiWidget) !void { io.BackendPlatformName = "ghostty_gtk"; // Our OpenGL area for drawing - const gl_area = c.gtk_gl_area_new(); - c.gtk_gl_area_set_auto_render(@ptrCast(gl_area), 1); + const gl_area = gtk.GLArea.new(); + gl_area.setAutoRender(@intFromBool(true)); // The GL area has to be focusable so that it can receive events - c.gtk_widget_set_focusable(@ptrCast(gl_area), 1); - c.gtk_widget_set_focus_on_click(@ptrCast(gl_area), 1); + gl_area.as(gtk.Widget).setFocusable(@intFromBool(true)); + gl_area.as(gtk.Widget).setFocusOnClick(@intFromBool(true)); // Clicks - const gesture_click = c.gtk_gesture_click_new(); - errdefer c.g_object_unref(gesture_click); - c.gtk_gesture_single_set_button(@ptrCast(gesture_click), 0); - c.gtk_widget_add_controller(@ptrCast(gl_area), @ptrCast(gesture_click)); + const gesture_click = gtk.GestureClick.new(); + errdefer gesture_click.unref(); + gesture_click.as(gtk.GestureSingle).setButton(0); + gl_area.as(gtk.Widget).addController(gesture_click.as(gtk.EventController)); // Mouse movement - const ec_motion = c.gtk_event_controller_motion_new(); - errdefer c.g_object_unref(ec_motion); - c.gtk_widget_add_controller(@ptrCast(gl_area), ec_motion); + const ec_motion = gtk.EventControllerMotion.new(); + errdefer ec_motion.unref(); + gl_area.as(gtk.Widget).addController(ec_motion.as(gtk.EventController)); // Scroll events - const ec_scroll = c.gtk_event_controller_scroll_new( - c.GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES | - c.GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, - ); - errdefer c.g_object_unref(ec_scroll); - c.gtk_widget_add_controller(@ptrCast(gl_area), ec_scroll); + const ec_scroll = gtk.EventControllerScroll.new(.flags_both_axes); + errdefer ec_scroll.unref(); + gl_area.as(gtk.Widget).addController(ec_scroll.as(gtk.EventController)); // Focus controller will tell us about focus enter/exit events - const ec_focus = c.gtk_event_controller_focus_new(); - errdefer c.g_object_unref(ec_focus); - c.gtk_widget_add_controller(@ptrCast(gl_area), ec_focus); + const ec_focus = gtk.EventControllerFocus.new(); + errdefer ec_focus.unref(); + gl_area.as(gtk.Widget).addController(ec_focus.as(gtk.EventController)); // Key event controller will tell us about raw keypress events. - const ec_key = c.gtk_event_controller_key_new(); - errdefer c.g_object_unref(ec_key); - c.gtk_widget_add_controller(@ptrCast(gl_area), ec_key); - errdefer c.gtk_widget_remove_controller(@ptrCast(gl_area), ec_key); + const ec_key = gtk.EventControllerKey.new(); + errdefer ec_key.unref(); + gl_area.as(gtk.Widget).addController(ec_key.as(gtk.EventController)); + errdefer gl_area.as(gtk.Widget).removeController(ec_key.as(gtk.EventController)); // The input method context that we use to translate key events into // characters. This doesn't have an event key controller attached because // we call it manually from our own key controller. - const im_context = c.gtk_im_multicontext_new(); - errdefer c.g_object_unref(im_context); + const im_context = gtk.IMMulticontext.new(); + errdefer im_context.unref(); // Signals - _ = c.g_signal_connect_data(gl_area, "destroy", c.G_CALLBACK(>kDestroy), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(gl_area, "realize", c.G_CALLBACK(>kRealize), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(gl_area, "unrealize", c.G_CALLBACK(>kUnrealize), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(gl_area, "render", c.G_CALLBACK(>kRender), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(gl_area, "resize", c.G_CALLBACK(>kResize), self, null, c.G_CONNECT_DEFAULT); - - _ = c.g_signal_connect_data(ec_focus, "enter", c.G_CALLBACK(>kFocusEnter), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(ec_focus, "leave", c.G_CALLBACK(>kFocusLeave), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(ec_key, "key-pressed", c.G_CALLBACK(>kKeyPressed), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(ec_key, "key-released", c.G_CALLBACK(>kKeyReleased), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(ec_motion, "motion", c.G_CALLBACK(>kMouseMotion), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(ec_scroll, "scroll", c.G_CALLBACK(>kMouseScroll), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(gesture_click, "pressed", c.G_CALLBACK(>kMouseDown), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(gesture_click, "released", c.G_CALLBACK(>kMouseUp), self, null, c.G_CONNECT_DEFAULT); - _ = c.g_signal_connect_data(im_context, "commit", c.G_CALLBACK(>kInputCommit), self, null, c.G_CONNECT_DEFAULT); + _ = gtk.Widget.signals.realize.connect( + gl_area, + *ImguiWidget, + gtkRealize, + self, + .{}, + ); + _ = gtk.Widget.signals.unrealize.connect( + gl_area, + *ImguiWidget, + gtkUnrealize, + self, + .{}, + ); + _ = gtk.Widget.signals.destroy.connect( + gl_area, + *ImguiWidget, + gtkDestroy, + self, + .{}, + ); + _ = gtk.GLArea.signals.render.connect( + gl_area, + *ImguiWidget, + gtkRender, + self, + .{}, + ); + _ = gtk.GLArea.signals.resize.connect( + gl_area, + *ImguiWidget, + gtkResize, + self, + .{}, + ); + _ = gtk.EventControllerKey.signals.key_pressed.connect( + ec_key, + *ImguiWidget, + gtkKeyPressed, + self, + .{}, + ); + _ = gtk.EventControllerKey.signals.key_released.connect( + ec_key, + *ImguiWidget, + gtkKeyReleased, + self, + .{}, + ); + _ = gtk.EventControllerFocus.signals.enter.connect( + ec_focus, + *ImguiWidget, + gtkFocusEnter, + self, + .{}, + ); + _ = gtk.EventControllerFocus.signals.leave.connect( + ec_focus, + *ImguiWidget, + gtkFocusLeave, + self, + .{}, + ); + _ = gtk.GestureClick.signals.pressed.connect( + gesture_click, + *ImguiWidget, + gtkMouseDown, + self, + .{}, + ); + _ = gtk.GestureClick.signals.released.connect( + gesture_click, + *ImguiWidget, + gtkMouseUp, + self, + .{}, + ); + _ = gtk.EventControllerMotion.signals.motion.connect( + ec_motion, + *ImguiWidget, + gtkMouseMotion, + self, + .{}, + ); + _ = gtk.EventControllerScroll.signals.scroll.connect( + ec_scroll, + *ImguiWidget, + gtkMouseScroll, + self, + .{}, + ); + _ = gtk.IMContext.signals.commit.connect( + im_context, + *ImguiWidget, + gtkInputCommit, + self, + .{}, + ); self.* = .{ .gl_area = @ptrCast(gl_area), @@ -113,7 +195,7 @@ pub fn deinit(self: *ImguiWidget) void { /// This should be called anytime the underlying data for the UI changes /// so that the UI can be refreshed. pub fn queueRender(self: *const ImguiWidget) void { - c.gtk_gl_area_queue_render(self.gl_area); + self.gl_area.queueRender(); } /// Initialize the frame. Expects that the context is already current. @@ -130,7 +212,7 @@ fn newFrame(self: *ImguiWidget) !void { self.instant = now; } -fn translateMouseButton(button: c.guint) ?c_int { +fn translateMouseButton(button: c_uint) ?c_int { return switch (button) { 1 => cimgui.c.ImGuiMouseButton_Left, 2 => cimgui.c.ImGuiMouseButton_Middle, @@ -139,45 +221,39 @@ fn translateMouseButton(button: c.guint) ?c_int { }; } -fn gtkDestroy(v: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void { - _ = v; +fn gtkDestroy(_: *gtk.GLArea, self: *ImguiWidget) callconv(.C) void { log.debug("imgui widget destroy", .{}); - - const self: *ImguiWidget = @ptrCast(@alignCast(ud.?)); self.deinit(); } -fn gtkRealize(area: *c.GtkGLArea, ud: ?*anyopaque) callconv(.C) void { +fn gtkRealize(area: *gtk.GLArea, self: *ImguiWidget) callconv(.C) void { log.debug("gl surface realized", .{}); // We need to make the context current so we can call GL functions. - c.gtk_gl_area_make_current(area); - if (c.gtk_gl_area_get_error(area)) |err| { - log.err("surface failed to realize: {s}", .{err.*.message}); + area.makeCurrent(); + if (area.getError()) |err| { + log.err("surface failed to realize: {s}", .{err.f_message orelse "(unknown)"}); return; } // realize means that our OpenGL context is ready, so we can now // initialize the ImgUI OpenGL backend for our context. - const self: *ImguiWidget = @ptrCast(@alignCast(ud.?)); cimgui.c.igSetCurrentContext(self.ig_ctx); _ = cimgui.ImGui_ImplOpenGL3_Init(null); } -fn gtkUnrealize(area: *c.GtkGLArea, ud: ?*anyopaque) callconv(.C) void { +fn gtkUnrealize(area: *gtk.GLArea, self: *ImguiWidget) callconv(.C) void { _ = area; log.debug("gl surface unrealized", .{}); - const self: *ImguiWidget = @ptrCast(@alignCast(ud.?)); cimgui.c.igSetCurrentContext(self.ig_ctx); cimgui.ImGui_ImplOpenGL3_Shutdown(); } -fn gtkResize(area: *c.GtkGLArea, width: c.gint, height: c.gint, ud: ?*anyopaque) callconv(.C) void { - const self: *ImguiWidget = @ptrCast(@alignCast(ud.?)); +fn gtkResize(area: *gtk.GLArea, width: c_int, height: c_int, self: *ImguiWidget) callconv(.C) void { cimgui.c.igSetCurrentContext(self.ig_ctx); const io: *cimgui.c.ImGuiIO = cimgui.c.igGetIO(); - const scale_factor = c.gtk_widget_get_scale_factor(@ptrCast(area)); + const scale_factor = area.as(gtk.Widget).getScaleFactor(); log.debug("gl resize width={} height={} scale={}", .{ width, height, @@ -197,10 +273,7 @@ fn gtkResize(area: *c.GtkGLArea, width: c.gint, height: c.gint, ud: ?*anyopaque) active_style.* = style.*; } -fn gtkRender(area: *c.GtkGLArea, ctx: *c.GdkGLContext, ud: ?*anyopaque) callconv(.C) c.gboolean { - _ = area; - _ = ctx; - const self: *ImguiWidget = @ptrCast(@alignCast(ud.?)); +fn gtkRender(_: *gtk.GLArea, _: *gdk.GLContext, self: *ImguiWidget) callconv(.C) c_int { cimgui.c.igSetCurrentContext(self.ig_ctx); // Setup our frame. We render twice because some ImGui behaviors @@ -230,17 +303,14 @@ fn gtkRender(area: *c.GtkGLArea, ctx: *c.GdkGLContext, ud: ?*anyopaque) callconv } fn gtkMouseMotion( - _: *c.GtkEventControllerMotion, - x: c.gdouble, - y: c.gdouble, - ud: ?*anyopaque, + _: *gtk.EventControllerMotion, + x: f64, + y: f64, + self: *ImguiWidget, ) callconv(.C) void { - const self: *ImguiWidget = @ptrCast(@alignCast(ud.?)); cimgui.c.igSetCurrentContext(self.ig_ctx); const io: *cimgui.c.ImGuiIO = cimgui.c.igGetIO(); - const scale_factor: f64 = @floatFromInt(c.gtk_widget_get_scale_factor( - @ptrCast(self.gl_area), - )); + const scale_factor: f64 = @floatFromInt(self.gl_area.as(gtk.Widget).getScaleFactor()); cimgui.c.ImGuiIO_AddMousePosEvent( io, @floatCast(x * scale_factor), @@ -250,48 +320,46 @@ fn gtkMouseMotion( } fn gtkMouseDown( - gesture: *c.GtkGestureClick, - _: c.gint, - _: c.gdouble, - _: c.gdouble, - ud: ?*anyopaque, + gesture: *gtk.GestureClick, + _: c_int, + _: f64, + _: f64, + self: *ImguiWidget, ) callconv(.C) void { - const self: *ImguiWidget = @ptrCast(@alignCast(ud.?)); self.queueRender(); cimgui.c.igSetCurrentContext(self.ig_ctx); const io: *cimgui.c.ImGuiIO = cimgui.c.igGetIO(); - const gdk_button = c.gtk_gesture_single_get_current_button(@ptrCast(gesture)); + + const gdk_button = gesture.as(gtk.GestureSingle).getCurrentButton(); if (translateMouseButton(gdk_button)) |button| { cimgui.c.ImGuiIO_AddMouseButtonEvent(io, button, true); } } fn gtkMouseUp( - gesture: *c.GtkGestureClick, - _: c.gint, - _: c.gdouble, - _: c.gdouble, - ud: ?*anyopaque, + gesture: *gtk.GestureClick, + _: c_int, + _: f64, + _: f64, + self: *ImguiWidget, ) callconv(.C) void { - const self: *ImguiWidget = @ptrCast(@alignCast(ud.?)); self.queueRender(); cimgui.c.igSetCurrentContext(self.ig_ctx); const io: *cimgui.c.ImGuiIO = cimgui.c.igGetIO(); - const gdk_button = c.gtk_gesture_single_get_current_button(@ptrCast(gesture)); + const gdk_button = gesture.as(gtk.GestureSingle).getCurrentButton(); if (translateMouseButton(gdk_button)) |button| { cimgui.c.ImGuiIO_AddMouseButtonEvent(io, button, false); } } fn gtkMouseScroll( - _: *c.GtkEventControllerScroll, - x: c.gdouble, - y: c.gdouble, - ud: ?*anyopaque, -) callconv(.C) void { - const self: *ImguiWidget = @ptrCast(@alignCast(ud.?)); + _: *gtk.EventControllerScroll, + x: f64, + y: f64, + self: *ImguiWidget, +) callconv(.C) c_int { self.queueRender(); cimgui.c.igSetCurrentContext(self.ig_ctx); @@ -301,10 +369,11 @@ fn gtkMouseScroll( @floatCast(x), @floatCast(-y), ); + + return @intFromBool(true); } -fn gtkFocusEnter(_: *c.GtkEventControllerFocus, ud: ?*anyopaque) callconv(.C) void { - const self: *ImguiWidget = @ptrCast(@alignCast(ud.?)); +fn gtkFocusEnter(_: *gtk.EventControllerFocus, self: *ImguiWidget) callconv(.C) void { self.queueRender(); cimgui.c.igSetCurrentContext(self.ig_ctx); @@ -312,8 +381,7 @@ fn gtkFocusEnter(_: *c.GtkEventControllerFocus, ud: ?*anyopaque) callconv(.C) vo cimgui.c.ImGuiIO_AddFocusEvent(io, true); } -fn gtkFocusLeave(_: *c.GtkEventControllerFocus, ud: ?*anyopaque) callconv(.C) void { - const self: *ImguiWidget = @ptrCast(@alignCast(ud.?)); +fn gtkFocusLeave(_: *gtk.EventControllerFocus, self: *ImguiWidget) callconv(.C) void { self.queueRender(); cimgui.c.igSetCurrentContext(self.ig_ctx); @@ -322,11 +390,10 @@ fn gtkFocusLeave(_: *c.GtkEventControllerFocus, ud: ?*anyopaque) callconv(.C) vo } fn gtkInputCommit( - _: *c.GtkIMContext, + _: *gtk.IMMulticontext, bytes: [*:0]u8, - ud: ?*anyopaque, + self: *ImguiWidget, ) callconv(.C) void { - const self: *ImguiWidget = @ptrCast(@alignCast(ud.?)); self.queueRender(); cimgui.c.igSetCurrentContext(self.ig_ctx); @@ -335,44 +402,53 @@ fn gtkInputCommit( } fn gtkKeyPressed( - ec_key: *c.GtkEventControllerKey, - keyval: c.guint, - keycode: c.guint, - gtk_mods: c.GdkModifierType, - ud: ?*anyopaque, -) callconv(.C) c.gboolean { - return if (keyEvent(.press, ec_key, keyval, keycode, gtk_mods, ud)) 1 else 0; + ec_key: *gtk.EventControllerKey, + keyval: c_uint, + keycode: c_uint, + gtk_mods: gdk.ModifierType, + self: *ImguiWidget, +) callconv(.C) c_int { + return @intFromBool(self.keyEvent( + .press, + ec_key, + keyval, + keycode, + gtk_mods, + )); } fn gtkKeyReleased( - ec_key: *c.GtkEventControllerKey, - keyval: c.guint, - keycode: c.guint, - state: c.GdkModifierType, - ud: ?*anyopaque, -) callconv(.C) c.gboolean { - return if (keyEvent(.release, ec_key, keyval, keycode, state, ud)) 1 else 0; + ec_key: *gtk.EventControllerKey, + keyval: c_uint, + keycode: c_uint, + gtk_mods: gdk.ModifierType, + self: *ImguiWidget, +) callconv(.C) void { + _ = self.keyEvent( + .release, + ec_key, + keyval, + keycode, + gtk_mods, + ); } fn keyEvent( + self: *ImguiWidget, action: input.Action, - ec_key: *c.GtkEventControllerKey, - keyval: c.guint, - keycode: c.guint, - gtk_mods: c.GdkModifierType, - ud: ?*anyopaque, + ec_key: *gtk.EventControllerKey, + keyval: c_uint, + keycode: c_uint, + gtk_mods: gdk.ModifierType, ) bool { _ = keycode; - const self: *ImguiWidget = @ptrCast(@alignCast(ud.?)); self.queueRender(); cimgui.c.igSetCurrentContext(self.ig_ctx); const io: *cimgui.c.ImGuiIO = cimgui.c.igGetIO(); - // FIXME: when this file get converted to zig-gobject - // Translate the GTK mods and update the modifiers on every keypress - const mods = key.translateMods(@bitCast(gtk_mods)); + const mods = key.translateMods(gtk_mods); cimgui.c.ImGuiIO_AddKeyEvent(io, cimgui.c.ImGuiKey_LeftShift, mods.shift); cimgui.c.ImGuiIO_AddKeyEvent(io, cimgui.c.ImGuiKey_LeftCtrl, mods.ctrl); cimgui.c.ImGuiIO_AddKeyEvent(io, cimgui.c.ImGuiKey_LeftAlt, mods.alt); @@ -386,9 +462,9 @@ fn keyEvent( } // Try to process the event as text - const event = c.gtk_event_controller_get_current_event(@ptrCast(ec_key)); - if (event != null) - _ = c.gtk_im_context_filter_keypress(self.im_context, event); + if (ec_key.as(gtk.EventController).getCurrentEvent()) |event| { + _ = self.im_context.filterKeypress(event); + } return true; } diff --git a/src/apprt/gtk/inspector.zig b/src/apprt/gtk/inspector.zig index e08e98120..aa4f6e435 100644 --- a/src/apprt/gtk/inspector.zig +++ b/src/apprt/gtk/inspector.zig @@ -2,12 +2,14 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; +const gtk = @import("gtk"); + const build_config = @import("../../build_config.zig"); +const i18n = @import("../../os/main.zig").i18n; const App = @import("App.zig"); const Surface = @import("Surface.zig"); const TerminalWindow = @import("Window.zig"); const ImguiWidget = @import("ImguiWidget.zig"); -const c = @import("c.zig").c; const CoreInspector = @import("../../inspector/main.zig").Inspector; const log = std.log.scoped(.inspector); @@ -124,7 +126,7 @@ pub const Inspector = struct { /// A dedicated window to hold an inspector instance. const Window = struct { inspector: *Inspector, - window: *c.GtkWindow, + window: *gtk.ApplicationWindow, imgui_widget: ImguiWidget, pub fn init(self: *Window, inspector: *Inspector) !void { @@ -136,15 +138,14 @@ const Window = struct { }; // Create the window - const window = c.gtk_application_window_new(@ptrCast(@alignCast(inspector.surface.app.app))); - const gtk_window: *c.GtkWindow = @ptrCast(window); - errdefer c.gtk_window_destroy(gtk_window); - self.window = gtk_window; - c.gtk_window_set_title(gtk_window, "Ghostty: Terminal Inspector"); - c.gtk_window_set_default_size(gtk_window, 1000, 600); - c.gtk_window_set_icon_name(gtk_window, build_config.bundle_id); - c.gtk_widget_add_css_class(@ptrCast(@alignCast(gtk_window)), "window"); - c.gtk_widget_add_css_class(@ptrCast(@alignCast(gtk_window)), "inspector-window"); + self.window = gtk.ApplicationWindow.new(inspector.surface.app.app.as(gtk.Application)); + errdefer self.window.as(gtk.Window).destroy(); + + self.window.as(gtk.Window).setTitle(i18n._("Ghostty: Terminal Inspector")); + self.window.as(gtk.Window).setDefaultSize(1000, 600); + self.window.as(gtk.Window).setIconName(build_config.bundle_id); + self.window.as(gtk.Widget).addCssClass("window"); + self.window.as(gtk.Widget).addCssClass("inspector-window"); // Initialize our imgui widget try self.imgui_widget.init(); @@ -154,11 +155,10 @@ const Window = struct { CoreInspector.setup(); // Signals - _ = c.g_signal_connect_data(window, "destroy", c.G_CALLBACK(>kDestroy), self, null, c.G_CONNECT_DEFAULT); - + _ = gtk.Widget.signals.destroy.connect(self.window, *Window, gtkDestroy, self, .{}); // Show the window - c.gtk_window_set_child(gtk_window, @ptrCast(self.imgui_widget.gl_area)); - c.gtk_widget_show(window); + self.window.as(gtk.Window).setChild(self.imgui_widget.gl_area.as(gtk.Widget)); + self.window.as(gtk.Window).present(); } pub fn deinit(self: *Window) void { @@ -166,7 +166,7 @@ const Window = struct { } pub fn close(self: *const Window) void { - c.gtk_window_destroy(self.window); + self.window.as(gtk.Window).destroy(); } fn imguiRender(ud: ?*anyopaque) void { @@ -177,11 +177,8 @@ const Window = struct { } /// "destroy" signal for the window - fn gtkDestroy(v: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void { - _ = v; + fn gtkDestroy(_: *gtk.ApplicationWindow, self: *Window) callconv(.C) void { log.debug("window destroy", .{}); - - const self: *Window = @ptrCast(@alignCast(ud.?)); self.deinit(); } }; diff --git a/src/apprt/gtk/key.zig b/src/apprt/gtk/key.zig index f59d0080d..2e00552a6 100644 --- a/src/apprt/gtk/key.zig +++ b/src/apprt/gtk/key.zig @@ -6,7 +6,6 @@ const glib = @import("glib"); const gtk = @import("gtk"); const input = @import("../../input.zig"); -const c = @import("c.zig").c; const winproto = @import("winproto.zig"); /// Returns a GTK accelerator string from a trigger. @@ -24,12 +23,12 @@ pub fn accelFromTrigger(buf: []u8, trigger: input.Binding.Trigger) !?[:0]const u switch (trigger.key) { .physical, .translated => |k| { const keyval = keyvalFromKey(k) orelse return null; - try writer.writeAll(std.mem.sliceTo(c.gdk_keyval_name(keyval), 0)); + try writer.writeAll(std.mem.span(gdk.keyvalName(keyval) orelse return null)); }, .unicode => |cp| { - if (c.gdk_keyval_name(cp)) |name| { - try writer.writeAll(std.mem.sliceTo(name, 0)); + if (gdk.keyvalName(cp)) |name| { + try writer.writeAll(std.mem.span(name)); } else { try writer.print("{u}", .{cp}); } @@ -170,7 +169,7 @@ pub fn eventMods( } /// Returns an input key from a keyval or null if we don't have a mapping. -pub fn keyFromKeyval(keyval: c.guint) ?input.Key { +pub fn keyFromKeyval(keyval: c_uint) ?input.Key { for (keymap) |entry| { if (entry[0] == keyval) return entry[1]; } @@ -179,7 +178,7 @@ pub fn keyFromKeyval(keyval: c.guint) ?input.Key { } /// Returns a keyval from an input key or null if we don't have a mapping. -pub fn keyvalFromKey(key: input.Key) ?c.guint { +pub fn keyvalFromKey(key: input.Key) ?c_uint { switch (key) { inline else => |key_comptime| { return comptime value: { @@ -211,145 +210,145 @@ test "accelFromTrigger" { /// A raw entry in the keymap. Our keymap contains mappings between /// GDK keys and our own key enum. -const RawEntry = struct { c.guint, input.Key }; +const RawEntry = struct { c_uint, input.Key }; const keymap: []const RawEntry = &.{ - .{ c.GDK_KEY_a, .a }, - .{ c.GDK_KEY_b, .b }, - .{ c.GDK_KEY_c, .c }, - .{ c.GDK_KEY_d, .d }, - .{ c.GDK_KEY_e, .e }, - .{ c.GDK_KEY_f, .f }, - .{ c.GDK_KEY_g, .g }, - .{ c.GDK_KEY_h, .h }, - .{ c.GDK_KEY_i, .i }, - .{ c.GDK_KEY_j, .j }, - .{ c.GDK_KEY_k, .k }, - .{ c.GDK_KEY_l, .l }, - .{ c.GDK_KEY_m, .m }, - .{ c.GDK_KEY_n, .n }, - .{ c.GDK_KEY_o, .o }, - .{ c.GDK_KEY_p, .p }, - .{ c.GDK_KEY_q, .q }, - .{ c.GDK_KEY_r, .r }, - .{ c.GDK_KEY_s, .s }, - .{ c.GDK_KEY_t, .t }, - .{ c.GDK_KEY_u, .u }, - .{ c.GDK_KEY_v, .v }, - .{ c.GDK_KEY_w, .w }, - .{ c.GDK_KEY_x, .x }, - .{ c.GDK_KEY_y, .y }, - .{ c.GDK_KEY_z, .z }, + .{ gdk.KEY_a, .a }, + .{ gdk.KEY_b, .b }, + .{ gdk.KEY_c, .c }, + .{ gdk.KEY_d, .d }, + .{ gdk.KEY_e, .e }, + .{ gdk.KEY_f, .f }, + .{ gdk.KEY_g, .g }, + .{ gdk.KEY_h, .h }, + .{ gdk.KEY_i, .i }, + .{ gdk.KEY_j, .j }, + .{ gdk.KEY_k, .k }, + .{ gdk.KEY_l, .l }, + .{ gdk.KEY_m, .m }, + .{ gdk.KEY_n, .n }, + .{ gdk.KEY_o, .o }, + .{ gdk.KEY_p, .p }, + .{ gdk.KEY_q, .q }, + .{ gdk.KEY_r, .r }, + .{ gdk.KEY_s, .s }, + .{ gdk.KEY_t, .t }, + .{ gdk.KEY_u, .u }, + .{ gdk.KEY_v, .v }, + .{ gdk.KEY_w, .w }, + .{ gdk.KEY_x, .x }, + .{ gdk.KEY_y, .y }, + .{ gdk.KEY_z, .z }, - .{ c.GDK_KEY_0, .zero }, - .{ c.GDK_KEY_1, .one }, - .{ c.GDK_KEY_2, .two }, - .{ c.GDK_KEY_3, .three }, - .{ c.GDK_KEY_4, .four }, - .{ c.GDK_KEY_5, .five }, - .{ c.GDK_KEY_6, .six }, - .{ c.GDK_KEY_7, .seven }, - .{ c.GDK_KEY_8, .eight }, - .{ c.GDK_KEY_9, .nine }, + .{ gdk.KEY_0, .zero }, + .{ gdk.KEY_1, .one }, + .{ gdk.KEY_2, .two }, + .{ gdk.KEY_3, .three }, + .{ gdk.KEY_4, .four }, + .{ gdk.KEY_5, .five }, + .{ gdk.KEY_6, .six }, + .{ gdk.KEY_7, .seven }, + .{ gdk.KEY_8, .eight }, + .{ gdk.KEY_9, .nine }, - .{ c.GDK_KEY_semicolon, .semicolon }, - .{ c.GDK_KEY_space, .space }, - .{ c.GDK_KEY_apostrophe, .apostrophe }, - .{ c.GDK_KEY_comma, .comma }, - .{ c.GDK_KEY_grave, .grave_accent }, - .{ c.GDK_KEY_period, .period }, - .{ c.GDK_KEY_slash, .slash }, - .{ c.GDK_KEY_minus, .minus }, - .{ c.GDK_KEY_equal, .equal }, - .{ c.GDK_KEY_bracketleft, .left_bracket }, - .{ c.GDK_KEY_bracketright, .right_bracket }, - .{ c.GDK_KEY_backslash, .backslash }, + .{ gdk.KEY_semicolon, .semicolon }, + .{ gdk.KEY_space, .space }, + .{ gdk.KEY_apostrophe, .apostrophe }, + .{ gdk.KEY_comma, .comma }, + .{ gdk.KEY_grave, .grave_accent }, + .{ gdk.KEY_period, .period }, + .{ gdk.KEY_slash, .slash }, + .{ gdk.KEY_minus, .minus }, + .{ gdk.KEY_equal, .equal }, + .{ gdk.KEY_bracketleft, .left_bracket }, + .{ gdk.KEY_bracketright, .right_bracket }, + .{ gdk.KEY_backslash, .backslash }, - .{ c.GDK_KEY_Up, .up }, - .{ c.GDK_KEY_Down, .down }, - .{ c.GDK_KEY_Right, .right }, - .{ c.GDK_KEY_Left, .left }, - .{ c.GDK_KEY_Home, .home }, - .{ c.GDK_KEY_End, .end }, - .{ c.GDK_KEY_Insert, .insert }, - .{ c.GDK_KEY_Delete, .delete }, - .{ c.GDK_KEY_Caps_Lock, .caps_lock }, - .{ c.GDK_KEY_Scroll_Lock, .scroll_lock }, - .{ c.GDK_KEY_Num_Lock, .num_lock }, - .{ c.GDK_KEY_Page_Up, .page_up }, - .{ c.GDK_KEY_Page_Down, .page_down }, - .{ c.GDK_KEY_Escape, .escape }, - .{ c.GDK_KEY_Return, .enter }, - .{ c.GDK_KEY_Tab, .tab }, - .{ c.GDK_KEY_BackSpace, .backspace }, - .{ c.GDK_KEY_Print, .print_screen }, - .{ c.GDK_KEY_Pause, .pause }, + .{ gdk.KEY_Up, .up }, + .{ gdk.KEY_Down, .down }, + .{ gdk.KEY_Right, .right }, + .{ gdk.KEY_Left, .left }, + .{ gdk.KEY_Home, .home }, + .{ gdk.KEY_End, .end }, + .{ gdk.KEY_Insert, .insert }, + .{ gdk.KEY_Delete, .delete }, + .{ gdk.KEY_Caps_Lock, .caps_lock }, + .{ gdk.KEY_Scroll_Lock, .scroll_lock }, + .{ gdk.KEY_Num_Lock, .num_lock }, + .{ gdk.KEY_Page_Up, .page_up }, + .{ gdk.KEY_Page_Down, .page_down }, + .{ gdk.KEY_Escape, .escape }, + .{ gdk.KEY_Return, .enter }, + .{ gdk.KEY_Tab, .tab }, + .{ gdk.KEY_BackSpace, .backspace }, + .{ gdk.KEY_Print, .print_screen }, + .{ gdk.KEY_Pause, .pause }, - .{ c.GDK_KEY_F1, .f1 }, - .{ c.GDK_KEY_F2, .f2 }, - .{ c.GDK_KEY_F3, .f3 }, - .{ c.GDK_KEY_F4, .f4 }, - .{ c.GDK_KEY_F5, .f5 }, - .{ c.GDK_KEY_F6, .f6 }, - .{ c.GDK_KEY_F7, .f7 }, - .{ c.GDK_KEY_F8, .f8 }, - .{ c.GDK_KEY_F9, .f9 }, - .{ c.GDK_KEY_F10, .f10 }, - .{ c.GDK_KEY_F11, .f11 }, - .{ c.GDK_KEY_F12, .f12 }, - .{ c.GDK_KEY_F13, .f13 }, - .{ c.GDK_KEY_F14, .f14 }, - .{ c.GDK_KEY_F15, .f15 }, - .{ c.GDK_KEY_F16, .f16 }, - .{ c.GDK_KEY_F17, .f17 }, - .{ c.GDK_KEY_F18, .f18 }, - .{ c.GDK_KEY_F19, .f19 }, - .{ c.GDK_KEY_F20, .f20 }, - .{ c.GDK_KEY_F21, .f21 }, - .{ c.GDK_KEY_F22, .f22 }, - .{ c.GDK_KEY_F23, .f23 }, - .{ c.GDK_KEY_F24, .f24 }, - .{ c.GDK_KEY_F25, .f25 }, + .{ gdk.KEY_F1, .f1 }, + .{ gdk.KEY_F2, .f2 }, + .{ gdk.KEY_F3, .f3 }, + .{ gdk.KEY_F4, .f4 }, + .{ gdk.KEY_F5, .f5 }, + .{ gdk.KEY_F6, .f6 }, + .{ gdk.KEY_F7, .f7 }, + .{ gdk.KEY_F8, .f8 }, + .{ gdk.KEY_F9, .f9 }, + .{ gdk.KEY_F10, .f10 }, + .{ gdk.KEY_F11, .f11 }, + .{ gdk.KEY_F12, .f12 }, + .{ gdk.KEY_F13, .f13 }, + .{ gdk.KEY_F14, .f14 }, + .{ gdk.KEY_F15, .f15 }, + .{ gdk.KEY_F16, .f16 }, + .{ gdk.KEY_F17, .f17 }, + .{ gdk.KEY_F18, .f18 }, + .{ gdk.KEY_F19, .f19 }, + .{ gdk.KEY_F20, .f20 }, + .{ gdk.KEY_F21, .f21 }, + .{ gdk.KEY_F22, .f22 }, + .{ gdk.KEY_F23, .f23 }, + .{ gdk.KEY_F24, .f24 }, + .{ gdk.KEY_F25, .f25 }, - .{ c.GDK_KEY_KP_0, .kp_0 }, - .{ c.GDK_KEY_KP_1, .kp_1 }, - .{ c.GDK_KEY_KP_2, .kp_2 }, - .{ c.GDK_KEY_KP_3, .kp_3 }, - .{ c.GDK_KEY_KP_4, .kp_4 }, - .{ c.GDK_KEY_KP_5, .kp_5 }, - .{ c.GDK_KEY_KP_6, .kp_6 }, - .{ c.GDK_KEY_KP_7, .kp_7 }, - .{ c.GDK_KEY_KP_8, .kp_8 }, - .{ c.GDK_KEY_KP_9, .kp_9 }, - .{ c.GDK_KEY_KP_Decimal, .kp_decimal }, - .{ c.GDK_KEY_KP_Divide, .kp_divide }, - .{ c.GDK_KEY_KP_Multiply, .kp_multiply }, - .{ c.GDK_KEY_KP_Subtract, .kp_subtract }, - .{ c.GDK_KEY_KP_Add, .kp_add }, - .{ c.GDK_KEY_KP_Enter, .kp_enter }, - .{ c.GDK_KEY_KP_Equal, .kp_equal }, + .{ gdk.KEY_KP_0, .kp_0 }, + .{ gdk.KEY_KP_1, .kp_1 }, + .{ gdk.KEY_KP_2, .kp_2 }, + .{ gdk.KEY_KP_3, .kp_3 }, + .{ gdk.KEY_KP_4, .kp_4 }, + .{ gdk.KEY_KP_5, .kp_5 }, + .{ gdk.KEY_KP_6, .kp_6 }, + .{ gdk.KEY_KP_7, .kp_7 }, + .{ gdk.KEY_KP_8, .kp_8 }, + .{ gdk.KEY_KP_9, .kp_9 }, + .{ gdk.KEY_KP_Decimal, .kp_decimal }, + .{ gdk.KEY_KP_Divide, .kp_divide }, + .{ gdk.KEY_KP_Multiply, .kp_multiply }, + .{ gdk.KEY_KP_Subtract, .kp_subtract }, + .{ gdk.KEY_KP_Add, .kp_add }, + .{ gdk.KEY_KP_Enter, .kp_enter }, + .{ gdk.KEY_KP_Equal, .kp_equal }, - .{ c.GDK_KEY_KP_Separator, .kp_separator }, - .{ c.GDK_KEY_KP_Left, .kp_left }, - .{ c.GDK_KEY_KP_Right, .kp_right }, - .{ c.GDK_KEY_KP_Up, .kp_up }, - .{ c.GDK_KEY_KP_Down, .kp_down }, - .{ c.GDK_KEY_KP_Page_Up, .kp_page_up }, - .{ c.GDK_KEY_KP_Page_Down, .kp_page_down }, - .{ c.GDK_KEY_KP_Home, .kp_home }, - .{ c.GDK_KEY_KP_End, .kp_end }, - .{ c.GDK_KEY_KP_Insert, .kp_insert }, - .{ c.GDK_KEY_KP_Delete, .kp_delete }, - .{ c.GDK_KEY_KP_Begin, .kp_begin }, + .{ gdk.KEY_KP_Separator, .kp_separator }, + .{ gdk.KEY_KP_Left, .kp_left }, + .{ gdk.KEY_KP_Right, .kp_right }, + .{ gdk.KEY_KP_Up, .kp_up }, + .{ gdk.KEY_KP_Down, .kp_down }, + .{ gdk.KEY_KP_Page_Up, .kp_page_up }, + .{ gdk.KEY_KP_Page_Down, .kp_page_down }, + .{ gdk.KEY_KP_Home, .kp_home }, + .{ gdk.KEY_KP_End, .kp_end }, + .{ gdk.KEY_KP_Insert, .kp_insert }, + .{ gdk.KEY_KP_Delete, .kp_delete }, + .{ gdk.KEY_KP_Begin, .kp_begin }, - .{ c.GDK_KEY_Shift_L, .left_shift }, - .{ c.GDK_KEY_Control_L, .left_control }, - .{ c.GDK_KEY_Alt_L, .left_alt }, - .{ c.GDK_KEY_Super_L, .left_super }, - .{ c.GDK_KEY_Shift_R, .right_shift }, - .{ c.GDK_KEY_Control_R, .right_control }, - .{ c.GDK_KEY_Alt_R, .right_alt }, - .{ c.GDK_KEY_Super_R, .right_super }, + .{ gdk.KEY_Shift_L, .left_shift }, + .{ gdk.KEY_Control_L, .left_control }, + .{ gdk.KEY_Alt_L, .left_alt }, + .{ gdk.KEY_Super_L, .left_super }, + .{ gdk.KEY_Shift_R, .right_shift }, + .{ gdk.KEY_Control_R, .right_control }, + .{ gdk.KEY_Alt_R, .right_alt }, + .{ gdk.KEY_Super_R, .right_super }, // TODO: media keys }; From 73341b052b5da8cfecf83e7f196f5396d5cda29e Mon Sep 17 00:00:00 2001 From: Leah Amelia Chen Date: Tue, 25 Feb 2025 08:55:56 +0100 Subject: [PATCH 3/6] gtk: port ConfigErrorsWindow to dialogs --- src/apprt/gtk/App.zig | 55 ++--- src/apprt/gtk/ConfigErrorsDialog.zig | 77 +++++++ src/apprt/gtk/ConfigErrorsWindow.zig | 218 ------------------ src/apprt/gtk/gresource.zig | 2 + src/apprt/gtk/ui/1.2/config-errors-dialog.blp | 28 +++ src/apprt/gtk/ui/1.2/config-errors-dialog.ui | 36 +++ src/apprt/gtk/ui/1.5/config-errors-dialog.blp | 28 +++ 7 files changed, 188 insertions(+), 256 deletions(-) create mode 100644 src/apprt/gtk/ConfigErrorsDialog.zig delete mode 100644 src/apprt/gtk/ConfigErrorsWindow.zig create mode 100644 src/apprt/gtk/ui/1.2/config-errors-dialog.blp create mode 100644 src/apprt/gtk/ui/1.2/config-errors-dialog.ui create mode 100644 src/apprt/gtk/ui/1.5/config-errors-dialog.blp diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index 483e7821e..9195355db 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -36,7 +36,7 @@ const CoreSurface = @import("../../Surface.zig"); const cgroup = @import("cgroup.zig"); const Surface = @import("Surface.zig"); const Window = @import("Window.zig"); -const ConfigErrorsWindow = @import("ConfigErrorsWindow.zig"); +const ConfigErrorsDialog = @import("ConfigErrorsDialog.zig"); const ClipboardConfirmationWindow = @import("ClipboardConfirmationWindow.zig"); const CloseDialog = @import("CloseDialog.zig"); const Split = @import("Split.zig"); @@ -71,9 +71,6 @@ single_instance: bool, /// The "none" cursor. We use one that is shared across the entire app. cursor_none: ?*gdk.Cursor, -/// The configuration errors window, if it is currently open. -config_errors_window: ?*ConfigErrorsWindow = null, - /// The clipboard confirmation window, if it is currently open. clipboard_confirmation_window: ?*ClipboardConfirmationWindow = null, @@ -956,16 +953,22 @@ fn configChange( log.warn("error cloning configuration err={}", .{err}); } - self.syncConfigChanges() catch |err| { - log.warn("error handling configuration changes err={}", .{err}); - }; - // App changes needs to show a toast that our configuration // has reloaded. - if (self.core_app.focusedSurface()) |core_surface| { - const surface = core_surface.rt_surface; - if (surface.container.window()) |window| window.onConfigReloaded(); - } + const window = window: { + if (self.core_app.focusedSurface()) |core_surface| { + const surface = core_surface.rt_surface; + if (surface.container.window()) |window| { + window.onConfigReloaded(); + break :window window; + } + } + break :window null; + }; + + self.syncConfigChanges(window) catch |err| { + log.warn("error handling configuration changes err={}", .{err}); + }; }, } } @@ -1001,8 +1004,8 @@ pub fn reloadConfig( } /// Call this anytime the configuration changes. -fn syncConfigChanges(self: *App) !void { - try self.updateConfigErrors(); +fn syncConfigChanges(self: *App, window: ?*Window) !void { + ConfigErrorsDialog.maybePresent(self, window); try self.syncActionAccelerators(); // Load our runtime and custom CSS. If this fails then our window is just stuck @@ -1018,23 +1021,6 @@ fn syncConfigChanges(self: *App) !void { }; } -/// This should be called whenever the configuration changes to update -/// the state of our config errors window. This will show the window if -/// there are new configuration errors and hide the window if the errors -/// are resolved. -fn updateConfigErrors(self: *App) !void { - if (!self.config._diagnostics.empty()) { - if (self.config_errors_window == null) { - try ConfigErrorsWindow.create(self); - assert(self.config_errors_window != null); - } - } - - if (self.config_errors_window) |window| { - window.update(); - } -} - fn syncActionAccelerators(self: *App) !void { try self.syncActionAccelerator("app.quit", .{ .quit = {} }); try self.syncActionAccelerator("app.open-config", .{ .open_config = {} }); @@ -1309,13 +1295,6 @@ pub fn run(self: *App) !void { // Setup our actions self.initActions(); - // On startup, we want to check for configuration errors right away - // so we can show our error window. We also need to setup other initial - // state. - self.syncConfigChanges() catch |err| { - log.warn("error handling configuration changes err={}", .{err}); - }; - while (self.running) { _ = glib.MainContext.iteration(self.ctx, 1); diff --git a/src/apprt/gtk/ConfigErrorsDialog.zig b/src/apprt/gtk/ConfigErrorsDialog.zig new file mode 100644 index 000000000..9bfedc8bc --- /dev/null +++ b/src/apprt/gtk/ConfigErrorsDialog.zig @@ -0,0 +1,77 @@ +/// Configuration errors window. +const ConfigErrorsDialog = @This(); + +const std = @import("std"); +const Allocator = std.mem.Allocator; + +const gobject = @import("gobject"); +const gio = @import("gio"); +const gtk = @import("gtk"); +const adw = @import("adw"); + +const build_config = @import("../../build_config.zig"); +const configpkg = @import("../../config.zig"); +const Config = configpkg.Config; + +const App = @import("App.zig"); +const Window = @import("Window.zig"); +const Builder = @import("Builder.zig"); +const adwaita = @import("adwaita.zig"); + +const log = std.log.scoped(.gtk); + +const DialogType = if (adwaita.supportsDialogs()) adw.AlertDialog else adw.MessageDialog; + +builder: Builder, +dialog: *DialogType, +error_message: *gtk.TextBuffer, + +pub fn maybePresent(app: *App, window: ?*Window) void { + if (app.config._diagnostics.empty()) return; + + var builder = switch (DialogType) { + adw.AlertDialog => Builder.init("config-errors-dialog", 1, 5, .blp), + adw.MessageDialog => Builder.init("config-errors-dialog", 1, 2, .ui), + else => unreachable, + }; + defer builder.deinit(); + + const dialog = builder.getObject(DialogType, "config_errors_dialog").?; + const error_message = builder.getObject(gtk.TextBuffer, "error_message").?; + + var msg_buf: [4095:0]u8 = undefined; + var fbs = std.io.fixedBufferStream(&msg_buf); + + for (app.config._diagnostics.items()) |diag| { + fbs.reset(); + diag.write(fbs.writer()) catch |err| { + log.warn( + "error writing diagnostic to buffer err={}", + .{err}, + ); + continue; + }; + + error_message.insertAtCursor(&msg_buf, @intCast(fbs.pos)); + error_message.insertAtCursor("\n", 1); + } + + _ = DialogType.signals.response.connect(dialog, *App, onResponse, app, .{}); + + const parent: ?*gtk.Widget = if (window) |w| @ptrCast(w.window) else null; + + switch (DialogType) { + adw.AlertDialog => dialog.as(adw.Dialog).present(parent), + adw.MessageDialog => dialog.as(gtk.Window).present(), + else => unreachable, + } +} + +fn onResponse(_: *DialogType, response: [*:0]const u8, app: *App) callconv(.C) void { + if (std.mem.orderZ(u8, response, "reload") == .eq) { + app.reloadConfig(.app, .{}) catch |err| { + log.warn("error reloading config error={}", .{err}); + return; + }; + } +} diff --git a/src/apprt/gtk/ConfigErrorsWindow.zig b/src/apprt/gtk/ConfigErrorsWindow.zig deleted file mode 100644 index 5fbf8e835..000000000 --- a/src/apprt/gtk/ConfigErrorsWindow.zig +++ /dev/null @@ -1,218 +0,0 @@ -/// Configuration errors window. -const ConfigErrors = @This(); - -const std = @import("std"); -const Allocator = std.mem.Allocator; -const build_config = @import("../../build_config.zig"); -const configpkg = @import("../../config.zig"); -const Config = configpkg.Config; - -const App = @import("App.zig"); -const View = @import("View.zig"); -const c = @import("c.zig").c; - -const log = std.log.scoped(.gtk); - -app: *App, -window: *c.GtkWindow, -view: PrimaryView, - -pub fn create(app: *App) !void { - if (app.config_errors_window != null) return error.InvalidOperation; - - const alloc = app.core_app.alloc; - const self = try alloc.create(ConfigErrors); - errdefer alloc.destroy(self); - try self.init(app); - - app.config_errors_window = self; -} - -pub fn update(self: *ConfigErrors) void { - if (self.app.config._diagnostics.empty()) { - c.gtk_window_destroy(@ptrCast(self.window)); - return; - } - - self.view.update(&self.app.config); - _ = c.gtk_window_present(self.window); - _ = c.gtk_widget_grab_focus(@ptrCast(self.window)); -} - -/// Not public because this should be called by the GTK lifecycle. -fn destroy(self: *ConfigErrors) void { - const alloc = self.app.core_app.alloc; - self.app.config_errors_window = null; - alloc.destroy(self); -} - -fn init(self: *ConfigErrors, app: *App) !void { - // Create the window - const window = c.gtk_window_new(); - const gtk_window: *c.GtkWindow = @ptrCast(window); - errdefer c.gtk_window_destroy(gtk_window); - c.gtk_window_set_title(gtk_window, "Configuration Errors"); - c.gtk_window_set_default_size(gtk_window, 600, 275); - c.gtk_window_set_resizable(gtk_window, 0); - c.gtk_window_set_icon_name(gtk_window, build_config.bundle_id); - c.gtk_widget_add_css_class(@ptrCast(@alignCast(gtk_window)), "window"); - c.gtk_widget_add_css_class(@ptrCast(@alignCast(gtk_window)), "config-errors-window"); - _ = c.g_signal_connect_data(window, "destroy", c.G_CALLBACK(>kDestroy), self, null, c.G_CONNECT_DEFAULT); - - // Set some state - self.* = .{ - .app = app, - .window = gtk_window, - .view = undefined, - }; - - // Show the window - const view = try PrimaryView.init(self); - self.view = view; - c.gtk_window_set_child(@ptrCast(window), view.root); - c.gtk_widget_show(window); -} - -fn gtkDestroy(_: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void { - const self = userdataSelf(ud.?); - self.destroy(); -} - -fn userdataSelf(ud: *anyopaque) *ConfigErrors { - return @ptrCast(@alignCast(ud)); -} - -const PrimaryView = struct { - root: *c.GtkWidget, - text: *c.GtkTextView, - - pub fn init(root: *ConfigErrors) !PrimaryView { - // All our widgets - const label = c.gtk_label_new( - "One or more configuration errors were found while loading " ++ - "the configuration. Please review the errors below and reload " ++ - "your configuration or ignore the erroneous lines.", - ); - const buf = contentsBuffer(&root.app.config); - defer c.g_object_unref(buf); - const buttons = try ButtonsView.init(root); - const text_scroll = c.gtk_scrolled_window_new(); - errdefer c.g_object_unref(text_scroll); - const text = c.gtk_text_view_new_with_buffer(buf); - errdefer c.g_object_unref(text); - c.gtk_scrolled_window_set_child(@ptrCast(text_scroll), text); - - // Create our view - const view = try View.init(&.{ - .{ .name = "label", .widget = label }, - .{ .name = "text", .widget = text_scroll }, - .{ .name = "buttons", .widget = buttons.root }, - }, &vfl); - errdefer view.deinit(); - - // We can do additional settings once the layout is setup - c.gtk_label_set_wrap(@ptrCast(label), 1); - c.gtk_text_view_set_editable(@ptrCast(text), 0); - c.gtk_text_view_set_cursor_visible(@ptrCast(text), 0); - c.gtk_text_view_set_top_margin(@ptrCast(text), 8); - c.gtk_text_view_set_bottom_margin(@ptrCast(text), 8); - c.gtk_text_view_set_left_margin(@ptrCast(text), 8); - c.gtk_text_view_set_right_margin(@ptrCast(text), 8); - - return .{ .root = view.root, .text = @ptrCast(text) }; - } - - pub fn update(self: *PrimaryView, config: *const Config) void { - const buf = contentsBuffer(config); - defer c.g_object_unref(buf); - c.gtk_text_view_set_buffer(@ptrCast(self.text), buf); - } - - /// Returns the GtkTextBuffer for the config errors that we want to show. - fn contentsBuffer(config: *const Config) *c.GtkTextBuffer { - const buf = c.gtk_text_buffer_new(null); - errdefer c.g_object_unref(buf); - - var msg_buf: [4096]u8 = undefined; - var fbs = std.io.fixedBufferStream(&msg_buf); - - for (config._diagnostics.items()) |diag| { - fbs.reset(); - diag.write(fbs.writer()) catch |err| { - log.warn( - "error writing diagnostic to buffer err={}", - .{err}, - ); - continue; - }; - - const msg = fbs.getWritten(); - c.gtk_text_buffer_insert_at_cursor(buf, msg.ptr, @intCast(msg.len)); - c.gtk_text_buffer_insert_at_cursor(buf, "\n", -1); - } - - return buf; - } - - const vfl = [_][*:0]const u8{ - "H:|-8-[label]-8-|", - "H:|[text]|", - "H:|[buttons]|", - "V:|[label(<=80)][text(>=100)]-[buttons]-|", - }; -}; - -const ButtonsView = struct { - root: *c.GtkWidget, - - pub fn init(root: *ConfigErrors) !ButtonsView { - const ignore_button = c.gtk_button_new_with_label("Ignore"); - errdefer c.g_object_unref(ignore_button); - - const reload_button = c.gtk_button_new_with_label("Reload Configuration"); - errdefer c.g_object_unref(reload_button); - - // Create our view - const view = try View.init(&.{ - .{ .name = "ignore", .widget = ignore_button }, - .{ .name = "reload", .widget = reload_button }, - }, &vfl); - - // Signals - _ = c.g_signal_connect_data( - ignore_button, - "clicked", - c.G_CALLBACK(>kIgnoreClick), - root, - null, - c.G_CONNECT_DEFAULT, - ); - _ = c.g_signal_connect_data( - reload_button, - "clicked", - c.G_CALLBACK(>kReloadClick), - root, - null, - c.G_CONNECT_DEFAULT, - ); - - return .{ .root = view.root }; - } - - fn gtkIgnoreClick(_: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void { - const self: *ConfigErrors = @ptrCast(@alignCast(ud)); - c.gtk_window_destroy(@ptrCast(self.window)); - } - - fn gtkReloadClick(_: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void { - const self: *ConfigErrors = @ptrCast(@alignCast(ud)); - self.app.reloadConfig(.app, .{}) catch |err| { - log.warn("error reloading config error={}", .{err}); - return; - }; - } - - const vfl = [_][*:0]const u8{ - "H:[ignore]-8-[reload]-8-|", - }; -}; diff --git a/src/apprt/gtk/gresource.zig b/src/apprt/gtk/gresource.zig index 44a1e00bf..64067c199 100644 --- a/src/apprt/gtk/gresource.zig +++ b/src/apprt/gtk/gresource.zig @@ -60,6 +60,7 @@ pub const VersionedBuilderXML = struct { }; pub const ui_files = [_]VersionedBuilderXML{ + .{ .major = 1, .minor = 2, .name = "config-errors-dialog" }, .{ .major = 1, .minor = 2, .name = "ccw-osc-52-read" }, .{ .major = 1, .minor = 2, .name = "ccw-osc-52-write" }, .{ .major = 1, .minor = 2, .name = "ccw-paste" }, @@ -73,6 +74,7 @@ pub const VersionedBlueprint = struct { pub const blueprint_files = [_]VersionedBlueprint{ .{ .major = 1, .minor = 5, .name = "prompt-title-dialog" }, + .{ .major = 1, .minor = 5, .name = "config-errors-dialog" }, .{ .major = 1, .minor = 0, .name = "menu-surface-context_menu" }, .{ .major = 1, .minor = 0, .name = "menu-window-titlebar_menu" }, .{ .major = 1, .minor = 5, .name = "ccw-osc-52-read" }, diff --git a/src/apprt/gtk/ui/1.2/config-errors-dialog.blp b/src/apprt/gtk/ui/1.2/config-errors-dialog.blp new file mode 100644 index 000000000..4f750a3be --- /dev/null +++ b/src/apprt/gtk/ui/1.2/config-errors-dialog.blp @@ -0,0 +1,28 @@ +using Gtk 4.0; +using Adw 1; + +Adw.MessageDialog config_errors_dialog { + heading: _("Configuration Errors"); + body: _("One or more configuration errors were found. Please review the errors below, and either reload your configuration or ignore these errors."); + + responses [ + ignore: _("Ignore"), + reload: _("Reload Configuration") suggested, + ] + + extra-child: ScrolledWindow { + min-content-width: 500; + min-content-height: 100; + + TextView { + editable: false; + cursor-visible: false; + top-margin: 8; + bottom-margin: 8; + left-margin: 8; + right-margin: 8; + + buffer: TextBuffer error_message { }; + } + }; +} diff --git a/src/apprt/gtk/ui/1.2/config-errors-dialog.ui b/src/apprt/gtk/ui/1.2/config-errors-dialog.ui new file mode 100644 index 000000000..1d7517f7a --- /dev/null +++ b/src/apprt/gtk/ui/1.2/config-errors-dialog.ui @@ -0,0 +1,36 @@ + + + + + + Configuration Errors + One or more configuration errors were found. Please review the errors below, and either reload your configuration or ignore these errors. + + Ignore + Reload Configuration + + + + 500 + 100 + + + false + false + 8 + 8 + 8 + 8 + + + + + + + + + diff --git a/src/apprt/gtk/ui/1.5/config-errors-dialog.blp b/src/apprt/gtk/ui/1.5/config-errors-dialog.blp new file mode 100644 index 000000000..e6d81c0df --- /dev/null +++ b/src/apprt/gtk/ui/1.5/config-errors-dialog.blp @@ -0,0 +1,28 @@ +using Gtk 4.0; +using Adw 1; + +Adw.AlertDialog config_errors_dialog { + heading: _("Configuration Errors"); + body: _("One or more configuration errors were found. Please review the errors below, and either reload your configuration or ignore these errors."); + + responses [ + ignore: _("Ignore"), + reload: _("Reload Configuration") suggested, + ] + + extra-child: ScrolledWindow { + min-content-width: 500; + min-content-height: 100; + + TextView { + editable: false; + cursor-visible: false; + top-margin: 8; + bottom-margin: 8; + left-margin: 8; + right-margin: 8; + + buffer: TextBuffer error_message { }; + } + }; +} From a773588c991d8a18348575c44e8e1d166de491ba Mon Sep 17 00:00:00 2001 From: Leah Amelia Chen Date: Tue, 25 Feb 2025 08:55:56 +0100 Subject: [PATCH 4/6] gtk: remove c.zig It has been done. --- src/apprt/gtk/View.zig | 73 --------------------------------------- src/apprt/gtk/c.zig | 8 ----- src/apprt/gtk/version.zig | 21 +++++++---- src/cli/version.zig | 25 ++++++++------ 4 files changed, 28 insertions(+), 99 deletions(-) delete mode 100644 src/apprt/gtk/View.zig delete mode 100644 src/apprt/gtk/c.zig diff --git a/src/apprt/gtk/View.zig b/src/apprt/gtk/View.zig deleted file mode 100644 index ecab1c95e..000000000 --- a/src/apprt/gtk/View.zig +++ /dev/null @@ -1,73 +0,0 @@ -/// View helps with creating a view with a constraint layout by -/// managing all the boilerplate. The caller is responsible for -/// providing the widgets, their names, and the VFL code and gets -/// a root box as a result ready to be used. -const View = @This(); - -const std = @import("std"); -const c = @import("c.zig").c; - -const log = std.log.scoped(.gtk); - -/// The box that contains all of the widgets. -root: *c.GtkWidget, - -/// A single widget used in the view. -pub const Widget = struct { - /// The name of the widget used for the layout code. This is also - /// the name set for the widget for CSS styling. - name: [:0]const u8, - - /// The widget itself. - widget: *c.GtkWidget, -}; - -/// Initialize a new constraint layout view with the given widgets -/// and VFL. -pub fn init(widgets: []const Widget, vfl: []const [*:0]const u8) !View { - // Box to store all our widgets - const box = c.gtk_box_new(c.GTK_ORIENTATION_VERTICAL, 0); - errdefer c.g_object_unref(box); - c.gtk_widget_set_vexpand(box, 1); - c.gtk_widget_set_hexpand(box, 1); - - // Setup our constraint layout and attach it to the box - const layout = c.gtk_constraint_layout_new(); - errdefer c.g_object_unref(layout); - c.gtk_widget_set_layout_manager(@ptrCast(box), layout); - - // Setup our views table - const views = c.g_hash_table_new(c.g_str_hash, c.g_str_equal); - defer c.g_hash_table_unref(views); - - // Add our widgets - for (widgets) |widget| { - c.gtk_widget_set_parent(widget.widget, box); - c.gtk_widget_set_name(widget.widget, widget.name); - _ = c.g_hash_table_insert( - views, - @constCast(@ptrCast(widget.name.ptr)), - widget.widget, - ); - } - - // Add all of our constraints for layout - var err_: ?*c.GError = null; - const list = c.gtk_constraint_layout_add_constraints_from_descriptionv( - @ptrCast(layout), - vfl.ptr, - vfl.len, - 8, - 8, - views, - &err_, - ); - if (err_) |err| { - defer c.g_error_free(err); - log.warn("error building view message={s}", .{err.message}); - return error.OperationFailed; - } - c.g_list_free(list); - - return .{ .root = box }; -} diff --git a/src/apprt/gtk/c.zig b/src/apprt/gtk/c.zig deleted file mode 100644 index 058a8e25a..000000000 --- a/src/apprt/gtk/c.zig +++ /dev/null @@ -1,8 +0,0 @@ -/// Imported C API directly from header files -pub const c = @cImport({ - @cInclude("gtk/gtk.h"); - @cInclude("adwaita.h"); - - // compatibility - @cInclude("ghostty_gtk_compat.h"); -}); diff --git a/src/apprt/gtk/version.zig b/src/apprt/gtk/version.zig index 67e769d11..9129d1f30 100644 --- a/src/apprt/gtk/version.zig +++ b/src/apprt/gtk/version.zig @@ -11,11 +11,17 @@ const gtk = @import("gtk"); const log = std.log.scoped(.gtk); +pub const version: std.SemanticVersion = .{ + .major = c.GTK_MAJOR_VERSION, + .minor = c.GTK_MINOR_VERSION, + .patch = c.GTK_MICRO_VERSION, +}; + pub fn logVersion() void { log.info("GTK version build={d}.{d}.{d} runtime={d}.{d}.{d}", .{ - c.GTK_MAJOR_VERSION, - c.GTK_MINOR_VERSION, - c.GTK_MICRO_VERSION, + version.major, + version.minor, + version.patch, gtk.getMajorVersion(), gtk.getMinorVersion(), gtk.getMicroVersion(), @@ -45,10 +51,11 @@ pub inline fn atLeast( // we can return false immediately. This prevents us from // compiling against unknown symbols and makes runtime checks // very slightly faster. - if (comptime c.GTK_MAJOR_VERSION < major or - (c.GTK_MAJOR_VERSION == major and c.GTK_MINOR_VERSION < minor) or - (c.GTK_MAJOR_VERSION == major and c.GTK_MINOR_VERSION == minor and c.GTK_MICRO_VERSION < micro)) - return false; + if (comptime version.order(.{ + .major = major, + .minor = minor, + .patch = micro, + }) == .lt) return false; // If we're in comptime then we can't check the runtime version. if (@inComptime()) return true; diff --git a/src/cli/version.zig b/src/cli/version.zig index 235cfe40b..ffab102b7 100644 --- a/src/cli/version.zig +++ b/src/cli/version.zig @@ -6,7 +6,10 @@ const build_config = @import("../build_config.zig"); const internal_os = @import("../os/main.zig"); const xev = @import("../global.zig").xev; const renderer = @import("../renderer.zig"); -const gtk = if (build_config.app_runtime == .gtk) @import("../apprt/gtk/c.zig").c else void; + +const gtk_version = @import("../apprt/gtk/version.zig").version; +const gtk = @import("gtk"); +const adw = @import("adw"); pub const Options = struct {}; @@ -42,23 +45,23 @@ pub fn run(alloc: Allocator) !u8 { try stdout.print(" - desktop env: {s}\n", .{@tagName(internal_os.desktopEnvironment())}); try stdout.print(" - GTK version:\n", .{}); try stdout.print(" build : {d}.{d}.{d}\n", .{ - gtk.GTK_MAJOR_VERSION, - gtk.GTK_MINOR_VERSION, - gtk.GTK_MICRO_VERSION, + gtk_version.major, + gtk_version.minor, + gtk_version.patch, }); try stdout.print(" runtime : {d}.{d}.{d}\n", .{ - gtk.gtk_get_major_version(), - gtk.gtk_get_minor_version(), - gtk.gtk_get_micro_version(), + gtk.getMajorVersion(), + gtk.getMinorVersion(), + gtk.getMicroVersion(), }); try stdout.print(" - libadwaita : enabled\n", .{}); try stdout.print(" build : {s}\n", .{ - gtk.ADW_VERSION_S, + adw.VERSION_S, }); try stdout.print(" runtime : {}.{}.{}\n", .{ - gtk.adw_get_major_version(), - gtk.adw_get_minor_version(), - gtk.adw_get_micro_version(), + adw.getMajorVersion(), + adw.getMinorVersion(), + adw.getMicroVersion(), }); if (comptime build_options.x11) { try stdout.print(" - libX11 : enabled\n", .{}); From 8c0ccfc5b35eb5aeea9c947242e279c92bfa4122 Mon Sep 17 00:00:00 2001 From: Leah Amelia Chen Date: Tue, 18 Mar 2025 11:48:31 +0100 Subject: [PATCH 5/6] translations: update --- po/com.mitchellh.ghostty.pot | 45 +++++++++++++++++++++++++----------- po/de_DE.UTF-8.po | 45 +++++++++++++++++++++++++----------- po/zh_CN.UTF-8.po | 45 +++++++++++++++++++++++++----------- 3 files changed, 96 insertions(+), 39 deletions(-) diff --git a/po/com.mitchellh.ghostty.pot b/po/com.mitchellh.ghostty.pot index 779f73fa9..b476e4671 100644 --- a/po/com.mitchellh.ghostty.pot +++ b/po/com.mitchellh.ghostty.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: com.mitchellh.ghostty\n" "Report-Msgid-Bugs-To: m@mitchellh.com\n" -"POT-Creation-Date: 2025-03-06 20:10+0100\n" +"POT-Creation-Date: 2025-03-18 11:48+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -34,6 +34,26 @@ msgstr "" msgid "OK" msgstr "" +#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5 +msgid "Configuration Errors" +msgstr "" + +#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6 +msgid "" +"One or more configuration errors were found. Please review the errors below, " +"and either reload your configuration or ignore these errors." +msgstr "" + +#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9 +msgid "Ignore" +msgstr "" + +#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10 +#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97 +#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95 +msgid "Reload Configuration" +msgstr "" + #: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6 #: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6 msgid "Copy" @@ -123,17 +143,12 @@ msgstr "" msgid "Open Configuration" msgstr "" -#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97 -#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95 -msgid "Reload Configuration" -msgstr "" - #: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85 msgid "Terminal Inspector" msgstr "" #: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102 -#: src/apprt/gtk/Window.zig:933 +#: src/apprt/gtk/Window.zig:958 msgid "About Ghostty" msgstr "" @@ -178,27 +193,31 @@ msgid "" "commands may be executed." msgstr "" -#: src/apprt/gtk/Window.zig:199 +#: src/apprt/gtk/Window.zig:200 msgid "Main Menu" msgstr "" -#: src/apprt/gtk/Window.zig:219 +#: src/apprt/gtk/Window.zig:221 msgid "View Open Tabs" msgstr "" -#: src/apprt/gtk/Window.zig:265 +#: src/apprt/gtk/Window.zig:295 msgid "" "⚠️ You're running a debug build of Ghostty! Performance will be degraded." msgstr "" -#: src/apprt/gtk/Window.zig:681 +#: src/apprt/gtk/Window.zig:725 msgid "Reloaded the configuration" msgstr "" -#: src/apprt/gtk/Window.zig:914 +#: src/apprt/gtk/Window.zig:939 msgid "Ghostty Developers" msgstr "" +#: src/apprt/gtk/inspector.zig:144 +msgid "Ghostty: Terminal Inspector" +msgstr "" + #: src/apprt/gtk/CloseDialog.zig:47 msgid "Close" msgstr "" @@ -235,6 +254,6 @@ msgstr "" msgid "The currently running process in this split will be terminated." msgstr "" -#: src/apprt/gtk/Surface.zig:1128 +#: src/apprt/gtk/Surface.zig:1242 msgid "Copied to clipboard" msgstr "" diff --git a/po/de_DE.UTF-8.po b/po/de_DE.UTF-8.po index f2a2deab6..a5c3c7a35 100644 --- a/po/de_DE.UTF-8.po +++ b/po/de_DE.UTF-8.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: com.mitchellh.ghostty\n" "Report-Msgid-Bugs-To: m@mitchellh.com\n" -"POT-Creation-Date: 2025-03-06 20:10+0100\n" +"POT-Creation-Date: 2025-03-18 11:48+0100\n" "PO-Revision-Date: 2025-03-06 14:57+0100\n" "Last-Translator: Robin \n" "Language-Team: German \n" @@ -35,6 +35,26 @@ msgstr "Abbrechen" msgid "OK" msgstr "OK" +#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5 +msgid "Configuration Errors" +msgstr "" + +#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6 +msgid "" +"One or more configuration errors were found. Please review the errors below, " +"and either reload your configuration or ignore these errors." +msgstr "" + +#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9 +msgid "Ignore" +msgstr "" + +#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10 +#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97 +#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95 +msgid "Reload Configuration" +msgstr "Konfiguration neu laden" + #: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6 #: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6 msgid "Copy" @@ -124,17 +144,12 @@ msgstr "Konfiguration" msgid "Open Configuration" msgstr "Konfiguration öffnen" -#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97 -#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95 -msgid "Reload Configuration" -msgstr "Konfiguration neu laden" - #: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85 msgid "Terminal Inspector" msgstr "Terminalinspektor" #: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102 -#: src/apprt/gtk/Window.zig:933 +#: src/apprt/gtk/Window.zig:958 msgid "About Ghostty" msgstr "Über Ghostty" @@ -185,29 +200,33 @@ msgstr "" "Diesen Text in das Terminal einzufügen könnte möglicherweise gefährlich " "sein. Es scheint, dass Anweisungen ausgeführt werden könnten." -#: src/apprt/gtk/Window.zig:199 +#: src/apprt/gtk/Window.zig:200 msgid "Main Menu" msgstr "Hauptmenü" -#: src/apprt/gtk/Window.zig:219 +#: src/apprt/gtk/Window.zig:221 msgid "View Open Tabs" msgstr "Offene Tabs einblenden" -#: src/apprt/gtk/Window.zig:265 +#: src/apprt/gtk/Window.zig:295 msgid "" "⚠️ You're running a debug build of Ghostty! Performance will be degraded." msgstr "" "⚠️ Du verwendest einen Debug Build von Ghostty! Die Leistung wird reduziert " "sein." -#: src/apprt/gtk/Window.zig:681 +#: src/apprt/gtk/Window.zig:725 msgid "Reloaded the configuration" msgstr "Konfiguration wurde neu geladen" -#: src/apprt/gtk/Window.zig:914 +#: src/apprt/gtk/Window.zig:939 msgid "Ghostty Developers" msgstr "Ghostty-Entwickler" +#: src/apprt/gtk/inspector.zig:144 +msgid "Ghostty: Terminal Inspector" +msgstr "" + #: src/apprt/gtk/CloseDialog.zig:47 msgid "Close" msgstr "Schließen" @@ -244,6 +263,6 @@ msgstr "Alle Terminalsitzungen in diesem Tab werden beendet." msgid "The currently running process in this split will be terminated." msgstr "Der aktuell laufende Prozess in diesem geteilten Fenster wird beendet." -#: src/apprt/gtk/Surface.zig:1128 +#: src/apprt/gtk/Surface.zig:1242 msgid "Copied to clipboard" msgstr "In die Zwischenablage kopiert" diff --git a/po/zh_CN.UTF-8.po b/po/zh_CN.UTF-8.po index 3b6d9047d..95391b66a 100644 --- a/po/zh_CN.UTF-8.po +++ b/po/zh_CN.UTF-8.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: com.mitchellh.ghostty\n" "Report-Msgid-Bugs-To: m@mitchellh.com\n" -"POT-Creation-Date: 2025-03-06 20:10+0100\n" +"POT-Creation-Date: 2025-03-18 11:48+0100\n" "PO-Revision-Date: 2025-02-27 09:16+0100\n" "Last-Translator: Leah \n" "Language-Team: Chinese (simplified) \n" @@ -34,6 +34,26 @@ msgstr "取消" msgid "OK" msgstr "确认" +#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5 +msgid "Configuration Errors" +msgstr "" + +#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6 +msgid "" +"One or more configuration errors were found. Please review the errors below, " +"and either reload your configuration or ignore these errors." +msgstr "" + +#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9 +msgid "Ignore" +msgstr "" + +#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10 +#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97 +#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95 +msgid "Reload Configuration" +msgstr "重新加载设置" + #: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6 #: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6 msgid "Copy" @@ -123,17 +143,12 @@ msgstr "设置" msgid "Open Configuration" msgstr "打开设置文件" -#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97 -#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95 -msgid "Reload Configuration" -msgstr "重新加载设置" - #: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85 msgid "Terminal Inspector" msgstr "终端检视器" #: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102 -#: src/apprt/gtk/Window.zig:933 +#: src/apprt/gtk/Window.zig:958 msgid "About Ghostty" msgstr "关于 Ghostty" @@ -178,27 +193,31 @@ msgid "" "commands may be executed." msgstr "将以下内容粘贴至终端内将可能执行有害命令。" -#: src/apprt/gtk/Window.zig:199 +#: src/apprt/gtk/Window.zig:200 msgid "Main Menu" msgstr "主菜单" -#: src/apprt/gtk/Window.zig:219 +#: src/apprt/gtk/Window.zig:221 msgid "View Open Tabs" msgstr "浏览标签页" -#: src/apprt/gtk/Window.zig:265 +#: src/apprt/gtk/Window.zig:295 msgid "" "⚠️ You're running a debug build of Ghostty! Performance will be degraded." msgstr "⚠️ Ghostty 正在以调试模式运行!性能将大打折扣。" -#: src/apprt/gtk/Window.zig:681 +#: src/apprt/gtk/Window.zig:725 msgid "Reloaded the configuration" msgstr "已重新加载设置" -#: src/apprt/gtk/Window.zig:914 +#: src/apprt/gtk/Window.zig:939 msgid "Ghostty Developers" msgstr "Ghostty 开发团队" +#: src/apprt/gtk/inspector.zig:144 +msgid "Ghostty: Terminal Inspector" +msgstr "" + #: src/apprt/gtk/CloseDialog.zig:47 msgid "Close" msgstr "关闭" @@ -235,6 +254,6 @@ msgstr "标签页内所有运行中的进程将被终止。" msgid "The currently running process in this split will be terminated." msgstr "分屏内正在运行中的进程将被终止。" -#: src/apprt/gtk/Surface.zig:1128 +#: src/apprt/gtk/Surface.zig:1242 msgid "Copied to clipboard" msgstr "已复制至剪切板" From 72017ea4d8711cba60d625b98c7dc66d654299d1 Mon Sep 17 00:00:00 2001 From: Leah Amelia Chen Date: Tue, 18 Mar 2025 12:19:20 +0100 Subject: [PATCH 6/6] translations(zh_CN): update --- po/zh_CN.UTF-8.po | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/po/zh_CN.UTF-8.po b/po/zh_CN.UTF-8.po index 95391b66a..f22e02190 100644 --- a/po/zh_CN.UTF-8.po +++ b/po/zh_CN.UTF-8.po @@ -36,17 +36,19 @@ msgstr "确认" #: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5 msgid "Configuration Errors" -msgstr "" +msgstr "设置错误" #: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6 msgid "" "One or more configuration errors were found. Please review the errors below, " "and either reload your configuration or ignore these errors." msgstr "" +"加载设置时发现了以下错误。请仔细阅读错误信息," +"并选择忽略或重新加载设置文件。" #: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9 msgid "Ignore" -msgstr "" +msgstr "忽略" #: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10 #: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97 @@ -216,7 +218,7 @@ msgstr "Ghostty 开发团队" #: src/apprt/gtk/inspector.zig:144 msgid "Ghostty: Terminal Inspector" -msgstr "" +msgstr "Ghostty 终端检视器" #: src/apprt/gtk/CloseDialog.zig:47 msgid "Close"