mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
gtk: hook up GL area and render a color
This commit is contained in:
@ -231,9 +231,6 @@ pub const Message = union(enum) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
const NewWindow = struct {
|
const NewWindow = struct {
|
||||||
/// Runtime-specific window options.
|
|
||||||
runtime: apprt.runtime.Surface.Options = .{},
|
|
||||||
|
|
||||||
/// The parent surface
|
/// The parent surface
|
||||||
parent: ?*Surface = null,
|
parent: ?*Surface = null,
|
||||||
};
|
};
|
||||||
|
@ -107,37 +107,37 @@ pub const App = struct {
|
|||||||
|
|
||||||
/// Close the given surface.
|
/// Close the given surface.
|
||||||
pub fn closeSurface(self: *App, surface: *Surface) void {
|
pub fn closeSurface(self: *App, surface: *Surface) void {
|
||||||
surface.deinit();
|
_ = self;
|
||||||
self.core_app.alloc.destroy(surface);
|
_ = surface;
|
||||||
|
|
||||||
|
// This shouldn't be called because we should be working within
|
||||||
|
// the GTK lifecycle and we can't just deallocate surfaces here.
|
||||||
|
@panic("This should not be called with GTK.");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newWindow(self: App) !*Surface {
|
pub fn newWindow(self: *App, parent_: ?*CoreSurface) !void {
|
||||||
|
_ = parent_;
|
||||||
|
|
||||||
|
// Grab a surface allocation we'll need it later.
|
||||||
|
var surface = try self.core_app.alloc.create(Surface);
|
||||||
|
errdefer self.core_app.alloc.destroy(surface);
|
||||||
|
|
||||||
const window = c.gtk_application_window_new(self.app);
|
const window = c.gtk_application_window_new(self.app);
|
||||||
c.gtk_window_set_title(@ptrCast(*c.GtkWindow, window), "Ghostty");
|
const gtk_window = @ptrCast(*c.GtkWindow, window);
|
||||||
c.gtk_window_set_default_size(@ptrCast(*c.GtkWindow, window), 200, 200);
|
c.gtk_window_set_title(gtk_window, "Ghostty");
|
||||||
|
c.gtk_window_set_default_size(gtk_window, 200, 200);
|
||||||
const surface = c.gtk_gl_area_new();
|
|
||||||
c.gtk_window_set_child(@ptrCast(*c.GtkWindow, window), surface);
|
|
||||||
_ = c.g_signal_connect_data(
|
|
||||||
surface,
|
|
||||||
"realize",
|
|
||||||
c.G_CALLBACK(&onSurfaceRealize),
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
c.G_CONNECT_DEFAULT,
|
|
||||||
);
|
|
||||||
_ = c.g_signal_connect_data(
|
|
||||||
surface,
|
|
||||||
"render",
|
|
||||||
c.G_CALLBACK(&onSurfaceRender),
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
c.G_CONNECT_DEFAULT,
|
|
||||||
);
|
|
||||||
|
|
||||||
c.gtk_widget_show(window);
|
c.gtk_widget_show(window);
|
||||||
|
|
||||||
return undefined;
|
// Initialize the GtkGLArea and attach it to our surface.
|
||||||
|
// The surface starts in the "unrealized" state because we have to
|
||||||
|
// wait for the "realize" callback from GTK to know that the OpenGL
|
||||||
|
// context is ready. See Surface docs for more info.
|
||||||
|
const gl_area = c.gtk_gl_area_new();
|
||||||
|
try surface.init(self, .{
|
||||||
|
.gl_area = @ptrCast(*c.GtkGLArea, gl_area),
|
||||||
|
});
|
||||||
|
errdefer surface.deinit();
|
||||||
|
c.gtk_window_set_child(gtk_window, gl_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate(app: *c.GtkApplication, ud: ?*anyopaque) callconv(.C) void {
|
fn activate(app: *c.GtkApplication, ud: ?*anyopaque) callconv(.C) void {
|
||||||
@ -150,23 +150,17 @@ pub const App = struct {
|
|||||||
// we reached this point.
|
// we reached this point.
|
||||||
log.debug("application activated", .{});
|
log.debug("application activated", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn onSurfaceRealize(area: *c.GtkGLArea, ud: ?*anyopaque) callconv(.C) void {
|
|
||||||
_ = area;
|
|
||||||
_ = ud;
|
|
||||||
log.debug("gl surface realized", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn onSurfaceRender(area: *c.GtkGLArea, ctx: *c.GdkGLContext, ud: ?*anyopaque) callconv(.C) void {
|
|
||||||
_ = area;
|
|
||||||
_ = ctx;
|
|
||||||
_ = ud;
|
|
||||||
log.debug("gl render", .{});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Surface = struct {
|
pub const Surface = struct {
|
||||||
pub const Options = struct {};
|
pub const Options = struct {
|
||||||
|
gl_area: *c.GtkGLArea,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Whether the surface has been realized or not yet. When a surface is
|
||||||
|
/// "realized" it means that the OpenGL context is ready and the core
|
||||||
|
/// surface has been initialized.
|
||||||
|
realized: bool = false,
|
||||||
|
|
||||||
/// The app we're part of
|
/// The app we're part of
|
||||||
app: *App,
|
app: *App,
|
||||||
@ -174,7 +168,7 @@ pub const Surface = struct {
|
|||||||
/// The core surface backing this surface
|
/// The core surface backing this surface
|
||||||
core_surface: CoreSurface,
|
core_surface: CoreSurface,
|
||||||
|
|
||||||
pub fn init(self: *Surface, app: *App) !void {
|
pub fn init(self: *Surface, app: *App, opts: Options) !void {
|
||||||
// Build our result
|
// Build our result
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.app = app,
|
.app = app,
|
||||||
@ -182,18 +176,80 @@ pub const Surface = struct {
|
|||||||
};
|
};
|
||||||
errdefer self.* = undefined;
|
errdefer self.* = undefined;
|
||||||
|
|
||||||
// Add ourselves to the list of surfaces on the app.
|
// Create the GL area that will contain our surface
|
||||||
try app.app.addSurface(self);
|
_ = c.g_signal_connect_data(
|
||||||
errdefer app.app.deleteSurface(self);
|
opts.gl_area,
|
||||||
|
"realize",
|
||||||
// Initialize our surface now that we have the stable pointer.
|
c.G_CALLBACK(>kRealize),
|
||||||
try self.core_surface.init(
|
null,
|
||||||
app.app.alloc,
|
null,
|
||||||
app.app.config,
|
c.G_CONNECT_DEFAULT,
|
||||||
.{ .rt_app = app, .mailbox = &app.app.mailbox },
|
|
||||||
self,
|
|
||||||
);
|
);
|
||||||
errdefer self.core_surface.deinit();
|
_ = c.g_signal_connect_data(
|
||||||
|
opts.gl_area,
|
||||||
|
"render",
|
||||||
|
c.G_CALLBACK(>kRender),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
c.G_CONNECT_DEFAULT,
|
||||||
|
);
|
||||||
|
_ = c.g_signal_connect_data(
|
||||||
|
opts.gl_area,
|
||||||
|
"destroy",
|
||||||
|
c.G_CALLBACK(>kDestroy),
|
||||||
|
self,
|
||||||
|
null,
|
||||||
|
c.G_CONNECT_DEFAULT,
|
||||||
|
);
|
||||||
|
|
||||||
|
// // Add ourselves to the list of surfaces on the app.
|
||||||
|
// try app.app.addSurface(self);
|
||||||
|
// errdefer app.app.deleteSurface(self);
|
||||||
|
//
|
||||||
|
// // Initialize our surface now that we have the stable pointer.
|
||||||
|
// try self.core_surface.init(
|
||||||
|
// app.app.alloc,
|
||||||
|
// app.app.config,
|
||||||
|
// .{ .rt_app = app, .mailbox = &app.app.mailbox },
|
||||||
|
// self,
|
||||||
|
// );
|
||||||
|
// errdefer self.core_surface.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gtkRealize(area: *c.GtkGLArea, ud: ?*anyopaque) callconv(.C) void {
|
||||||
|
_ = area;
|
||||||
|
_ = ud;
|
||||||
|
|
||||||
|
log.debug("gl surface realized", .{});
|
||||||
|
const opengl = @import("../renderer/opengl/main.zig");
|
||||||
|
log.warn("foo: {}", .{opengl.glad.load(null) catch 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gtkRender(area: *c.GtkGLArea, ctx: *c.GdkGLContext, ud: ?*anyopaque) callconv(.C) c.gboolean {
|
||||||
|
_ = area;
|
||||||
|
_ = ctx;
|
||||||
|
_ = ud;
|
||||||
|
log.debug("gl render", .{});
|
||||||
|
|
||||||
|
const opengl = @import("../renderer/opengl/main.zig");
|
||||||
|
opengl.clearColor(0, 0.5, 1, 1);
|
||||||
|
opengl.clear(opengl.c.GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// "destroy" signal for surface
|
||||||
|
fn gtkDestroy(v: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void {
|
||||||
|
_ = v;
|
||||||
|
|
||||||
|
const self = userdataSelf(ud orelse return);
|
||||||
|
const alloc = self.app.core_app.alloc;
|
||||||
|
self.deinit();
|
||||||
|
alloc.destroy(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn userdataSelf(ud: *anyopaque) *Surface {
|
||||||
|
return @ptrCast(*Surface, @alignCast(@alignOf(Surface), ud));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Surface) void {
|
pub fn deinit(self: *Surface) void {
|
||||||
|
Reference in New Issue
Block a user