mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-09-05 19:08:17 +00:00
gtk: port inspector & key handling to zig-gobject
This commit is contained in:
@@ -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");
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
};
|
||||
|
Reference in New Issue
Block a user