mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-09-05 19:08:17 +00:00
5
.github/workflows/test.yml
vendored
5
.github/workflows/test.yml
vendored
@@ -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:
|
||||
|
@@ -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 <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\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 ""
|
||||
|
@@ -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 <r@rpfaeffle.com>\n"
|
||||
"Language-Team: German <translation-team-de@lists.sourceforge.net>\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"
|
||||
|
@@ -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 <hi@pluie.me>\n"
|
||||
"Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
|
||||
@@ -34,6 +34,28 @@ 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 +145,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 +195,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 "Ghostty 终端检视器"
|
||||
|
||||
#: src/apprt/gtk/CloseDialog.zig:47
|
||||
msgid "Close"
|
||||
msgstr "关闭"
|
||||
@@ -235,6 +256,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 "已复制至剪切板"
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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");
|
||||
|
||||
|
77
src/apprt/gtk/ConfigErrorsDialog.zig
Normal file
77
src/apprt/gtk/ConfigErrorsDialog.zig
Normal file
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
@@ -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-|",
|
||||
};
|
||||
};
|
@@ -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;
|
||||
}
|
||||
|
@@ -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 };
|
||||
}
|
@@ -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");
|
||||
});
|
@@ -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" },
|
||||
|
@@ -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();
|
||||
}
|
||||
};
|
||||
|
@@ -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
|
||||
};
|
||||
|
28
src/apprt/gtk/ui/1.2/config-errors-dialog.blp
Normal file
28
src/apprt/gtk/ui/1.2/config-errors-dialog.blp
Normal file
@@ -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 { };
|
||||
}
|
||||
};
|
||||
}
|
36
src/apprt/gtk/ui/1.2/config-errors-dialog.ui
Normal file
36
src/apprt/gtk/ui/1.2/config-errors-dialog.ui
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
DO NOT EDIT!
|
||||
This file was @generated by blueprint-compiler. Instead, edit the
|
||||
corresponding .blp file and regenerate this file with blueprint-compiler.
|
||||
-->
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<object class="AdwMessageDialog" id="config_errors_dialog">
|
||||
<property name="heading" translatable="yes">Configuration Errors</property>
|
||||
<property name="body" translatable="yes">One or more configuration errors were found. Please review the errors below, and either reload your configuration or ignore these errors.</property>
|
||||
<responses>
|
||||
<response id="ignore" translatable="yes">Ignore</response>
|
||||
<response id="reload" translatable="yes" appearance="suggested">Reload Configuration</response>
|
||||
</responses>
|
||||
<property name="extra-child">
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="min-content-width">500</property>
|
||||
<property name="min-content-height">100</property>
|
||||
<child>
|
||||
<object class="GtkTextView">
|
||||
<property name="editable">false</property>
|
||||
<property name="cursor-visible">false</property>
|
||||
<property name="top-margin">8</property>
|
||||
<property name="bottom-margin">8</property>
|
||||
<property name="left-margin">8</property>
|
||||
<property name="right-margin">8</property>
|
||||
<property name="buffer">
|
||||
<object class="GtkTextBuffer" id="error_message"></object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</interface>
|
28
src/apprt/gtk/ui/1.5/config-errors-dialog.blp
Normal file
28
src/apprt/gtk/ui/1.5/config-errors-dialog.blp
Normal file
@@ -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 { };
|
||||
}
|
||||
};
|
||||
}
|
@@ -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;
|
||||
|
@@ -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", .{});
|
||||
|
Reference in New Issue
Block a user