diff --git a/src/apprt/glfw.zig b/src/apprt/glfw.zig index 41bfae892..33010b618 100644 --- a/src/apprt/glfw.zig +++ b/src/apprt/glfw.zig @@ -144,6 +144,38 @@ pub const App = struct { return &self.config; } + /// Toggle the window to fullscreen mode. + pub fn toggleFullscreen(self: *App, surface: *Surface) void { + _ = self; + const win = surface.window; + + if (!surface.isFullscreen()) { + const monitor = win.getMonitor() orelse monitor: { + log.warn("window had null monitor, getting primary monitor", .{}); + break :monitor glfw.Monitor.getPrimary() orelse { + log.warn("window could not get any monitor. Will not perform action", .{}); + return; + }; + }; + const position = win.getPos(); + const size = surface.getSize() catch { + log.warn("Failed to get window size. Will not perform fullscreen action", .{}); + return; + }; + + surface.window_dimensions = .{ + .width = size.width, + .height = size.height, + .position_x = position.x, + .position_y = position.y, + }; + + win.setMonitor(monitor, 0, 0, surface.window_dimensions.width, surface.window_dimensions.height, 0); + } else { + win.setMonitor(null, @as(i32, @intCast(surface.window_dimensions.position_x)), @as(i32, @intCast(surface.window_dimensions.position_y)), surface.window_dimensions.width, surface.window_dimensions.height, 0); + } + } + /// Create a new window for the app. pub fn newWindow(self: *App, parent_: ?*CoreSurface) !void { _ = try self.newSurface(parent_); @@ -267,6 +299,15 @@ pub const App = struct { }; }; +/// These are used to keep track of the original monitor values so that we can safely +/// toggle on and off of fullscreen. +const MonitorDimensions = struct { + width: u32, + height: u32, + position_x: i64, + position_y: i64, +}; + /// Surface represents the drawable surface for glfw. In glfw, a surface /// is always a window because that is the only abstraction that glfw exposes. /// @@ -297,17 +338,21 @@ pub const Surface = struct { /// (GLFW guarantees that charCallback is called after keyCallback). key_event: ?input.KeyEvent = null, + window_dimensions: MonitorDimensions, + pub const Options = struct {}; /// Initialize the surface into the given self pointer. This gives a /// stable pointer to the destination that can be used for callbacks. pub fn init(self: *Surface, app: *App) !void { + const fullscreen = if (app.config.fullscreen) glfw.Monitor.getPrimary().? else null; + // Create our window const win = glfw.Window.create( 640, 480, "ghostty", - null, + fullscreen, null, Renderer.glfwWindowHints(&app.config), ) orelse return glfw.mustGetErrorCode(); @@ -320,8 +365,8 @@ pub const Surface = struct { log.warn("window had null monitor, getting primary monitor", .{}); break :monitor glfw.Monitor.getPrimary().?; }; - const physical_size = monitor.getPhysicalSize(); const video_mode = monitor.getVideoMode() orelse return glfw.mustGetErrorCode(); + const physical_size = monitor.getPhysicalSize(); const physical_x_dpi = @as(f32, @floatFromInt(video_mode.getWidth())) / (@as(f32, @floatFromInt(physical_size.width_mm)) / 25.4); const physical_y_dpi = @as(f32, @floatFromInt(video_mode.getHeight())) / (@as(f32, @floatFromInt(physical_size.height_mm)) / 25.4); log.debug("physical dpi x={} y={}", .{ @@ -361,6 +406,7 @@ pub const Surface = struct { .window = win, .cursor = null, .core_surface = undefined, + .window_dimensions = undefined, }; errdefer self.* = undefined; @@ -447,6 +493,15 @@ pub const Surface = struct { try self.app.newTab(&self.core_surface); } + /// Checks if the glfw window is in fullscreen. + pub fn isFullscreen(self: *Surface) bool { + return self.window.getMonitor() != null; + } + + pub fn toggleFullscreen(self: *Surface, _: Config.NonNativeFullscreen) void { + self.app.toggleFullscreen(self); + } + /// Close this surface. pub fn close(self: *Surface, processActive: bool) void { _ = processActive;