apprt/gtk: handle scenario where OpenGL area becomes unrealized

This commit is contained in:
Mitchell Hashimoto
2023-09-16 09:38:28 -07:00
parent a19acf14d2
commit f7272d506e
3 changed files with 36 additions and 3 deletions

View File

@ -192,9 +192,7 @@ pub fn newWindow(self: *App, parent_: ?*CoreSurface) !void {
//
// The allocation is owned by the GtkWindow created. It will be
// freed when the window is closed.
var window = try alloc.create(Window);
errdefer alloc.destroy(window);
try window.init(self);
var window = try Window.create(alloc, self);
// Add our initial tab
try window.newTab(parent_);

View File

@ -158,6 +158,7 @@ pub fn init(self: *Surface, app: *App, opts: Options) !void {
// GL events
_ = c.g_signal_connect_data(opts.gl_area, "realize", c.G_CALLBACK(&gtkRealize), self, null, c.G_CONNECT_DEFAULT);
_ = c.g_signal_connect_data(opts.gl_area, "unrealize", c.G_CALLBACK(&gtkUnrealize), self, null, c.G_CONNECT_DEFAULT);
_ = c.g_signal_connect_data(opts.gl_area, "destroy", c.G_CALLBACK(&gtkDestroy), self, null, c.G_CONNECT_DEFAULT);
_ = c.g_signal_connect_data(opts.gl_area, "render", c.G_CALLBACK(&gtkRender), self, null, c.G_CONNECT_DEFAULT);
_ = c.g_signal_connect_data(opts.gl_area, "resize", c.G_CALLBACK(&gtkResize), self, null, c.G_CONNECT_DEFAULT);
@ -177,6 +178,16 @@ pub fn init(self: *Surface, app: *App, opts: Options) !void {
}
fn realize(self: *Surface) !void {
// If this surface has already been realized, then we don't need to
// reinitialize. This can happen if a surface is moved from one GDK surface
// to another (i.e. a tab is pulled out into a window).
if (self.realized) {
// If we have no OpenGL state though, we do need to reinitialize.
// We allow the renderer to figure that out
try self.core_surface.renderer.displayRealize();
return;
}
// Add ourselves to the list of surfaces on the app.
try self.app.core_app.addSurface(self);
errdefer self.app.core_app.deleteSurface(self);
@ -479,6 +490,15 @@ fn gtkRealize(area: *c.GtkGLArea, ud: ?*anyopaque) callconv(.C) void {
};
}
/// This is called when the underlying OpenGL resources must be released.
/// This is usually due to the OpenGL area changing GDK surfaces.
fn gtkUnrealize(area: *c.GtkGLArea, ud: ?*anyopaque) callconv(.C) void {
_ = area;
const self = userdataSelf(ud.?);
self.core_surface.renderer.displayUnrealized();
}
/// render signal
fn gtkRender(area: *c.GtkGLArea, ctx: *c.GdkGLContext, ud: ?*anyopaque) callconv(.C) c.gboolean {
_ = area;

View File

@ -3,6 +3,7 @@ const Window = @This();
const std = @import("std");
const builtin = @import("builtin");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const configpkg = @import("../../config.zig");
const font = @import("../../font/main.zig");
@ -29,6 +30,20 @@ notebook: *c.GtkNotebook,
/// pointer to this because GTK can use it at any time.
icon_search_dir: ?[:0]const u8 = null,
pub fn create(alloc: Allocator, app: *App) !*Window {
// Allocate a fixed pointer for our window. We try to minimize
// allocations but windows and other GUI requirements are so minimal
// compared to the steady-state terminal operation so we use heap
// allocation for this.
//
// The allocation is owned by the GtkWindow created. It will be
// freed when the window is closed.
var window = try alloc.create(Window);
errdefer alloc.destroy(window);
try window.init(app);
return window;
}
pub fn init(self: *Window, app: *App) !void {
// Set up our own state
self.* = .{