Merge branch 'NSToolbar-Deprication-Warning-Fix' of github.com:johnseth97/ghostty into NSToolbar-Deprication-Warning-Fix

This commit is contained in:
johnseth97
2024-10-19 19:09:00 -04:00
committed by Mitchell Hashimoto
17 changed files with 264 additions and 37 deletions

View File

@ -61,6 +61,7 @@
A59FB5CF2AE0DB50009128F3 /* InspectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */; }; A59FB5CF2AE0DB50009128F3 /* InspectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */; };
A59FB5D12AE0DEA7009128F3 /* MetalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5D02AE0DEA7009128F3 /* MetalView.swift */; }; A59FB5D12AE0DEA7009128F3 /* MetalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5D02AE0DEA7009128F3 /* MetalView.swift */; };
A5A1F8852A489D6800D1E8BC /* terminfo in Resources */ = {isa = PBXBuildFile; fileRef = A5A1F8842A489D6800D1E8BC /* terminfo */; }; A5A1F8852A489D6800D1E8BC /* terminfo in Resources */ = {isa = PBXBuildFile; fileRef = A5A1F8842A489D6800D1E8BC /* terminfo */; };
A5A6F72A2CC41B8900B232A5 /* Xcode.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A6F7292CC41B8700B232A5 /* Xcode.swift */; };
A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5B30538299BEAAB0047F10C /* Assets.xcassets */; }; A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5B30538299BEAAB0047F10C /* Assets.xcassets */; };
A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */; }; A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */; };
A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0572C9F30860017A1AE /* Cursor.swift */; }; A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0572C9F30860017A1AE /* Cursor.swift */; };
@ -139,6 +140,7 @@
A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorView.swift; sourceTree = "<group>"; }; A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorView.swift; sourceTree = "<group>"; };
A59FB5D02AE0DEA7009128F3 /* MetalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetalView.swift; sourceTree = "<group>"; }; A59FB5D02AE0DEA7009128F3 /* MetalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetalView.swift; sourceTree = "<group>"; };
A5A1F8842A489D6800D1E8BC /* terminfo */ = {isa = PBXFileReference; lastKnownFileType = folder; name = terminfo; path = "../zig-out/share/terminfo"; sourceTree = "<group>"; }; A5A1F8842A489D6800D1E8BC /* terminfo */ = {isa = PBXFileReference; lastKnownFileType = folder; name = terminfo; path = "../zig-out/share/terminfo"; sourceTree = "<group>"; };
A5A6F7292CC41B8700B232A5 /* Xcode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Xcode.swift; sourceTree = "<group>"; };
A5B30531299BEAAA0047F10C /* Ghostty.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ghostty.app; sourceTree = BUILT_PRODUCTS_DIR; }; A5B30531299BEAAA0047F10C /* Ghostty.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ghostty.app; sourceTree = BUILT_PRODUCTS_DIR; };
A5B30538299BEAAB0047F10C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; A5B30538299BEAAB0047F10C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ghostty.entitlements; sourceTree = "<group>"; }; A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ghostty.entitlements; sourceTree = "<group>"; };
@ -233,6 +235,7 @@
A534263D2A7DCBB000EBB7A2 /* Helpers */ = { A534263D2A7DCBB000EBB7A2 /* Helpers */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
A5A6F7292CC41B8700B232A5 /* Xcode.swift */,
A5CEAFFE29C2410700646FDA /* Backport.swift */, A5CEAFFE29C2410700646FDA /* Backport.swift */,
A5333E1B2B5A1CE3008AEFF7 /* CrossKit.swift */, A5333E1B2B5A1CE3008AEFF7 /* CrossKit.swift */,
A5CBD0572C9F30860017A1AE /* Cursor.swift */, A5CBD0572C9F30860017A1AE /* Cursor.swift */,
@ -582,6 +585,7 @@
A52FFF5D2CAB4D08000C6A5B /* NSScreen+Extension.swift in Sources */, A52FFF5D2CAB4D08000C6A5B /* NSScreen+Extension.swift in Sources */,
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */, A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */,
A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */, A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */,
A5A6F72A2CC41B8900B232A5 /* Xcode.swift in Sources */,
A52FFF5B2CAA54B1000C6A5B /* FullscreenMode+Extension.swift in Sources */, A52FFF5B2CAA54B1000C6A5B /* FullscreenMode+Extension.swift in Sources */,
A5333E222B5A2128008AEFF7 /* SurfaceView_AppKit.swift in Sources */, A5333E222B5A2128008AEFF7 /* SurfaceView_AppKit.swift in Sources */,
A5CDF1952AAFA19600513312 /* ConfigurationErrorsView.swift in Sources */, A5CDF1952AAFA19600513312 /* ConfigurationErrorsView.swift in Sources */,

View File

@ -14,7 +14,7 @@
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/> <customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" titlebarAppearsTransparent="YES" id="QvC-M9-y7g"> <window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" titlebarAppearsTransparent="YES" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES"/> <windowStyleMask key="styleMask" titled="YES" closable="YES" fullSizeContentView="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="300" height="172"/> <rect key="contentRect" x="196" y="240" width="300" height="172"/>
<rect key="screenRect" x="0.0" y="0.0" width="3008" height="1667"/> <rect key="screenRect" x="0.0" y="0.0" width="3008" height="1667"/>

View File

@ -10,6 +10,7 @@ class AboutController: NSWindowController, NSWindowDelegate {
override func windowDidLoad() { override func windowDidLoad() {
guard let window = window else { return } guard let window = window else { return }
window.center() window.center()
window.isMovableByWindowBackground = true
window.contentView = NSHostingView(rootView: AboutView()) window.contentView = NSHostingView(rootView: AboutView())
} }

View File

@ -1,35 +1,136 @@
import SwiftUI import SwiftUI
struct AboutView: View { struct AboutView: View {
@Environment(\.openURL) var openURL
private let githubLink = URL(string: "https://github.com/ghostty-org/ghostty")
/// Read the commit from the bundle. /// Read the commit from the bundle.
var build: String? { Bundle.main.infoDictionary?["CFBundleVersion"] as? String } private var build: String? { Bundle.main.infoDictionary?["CFBundleVersion"] as? String }
var commit: String? { Bundle.main.infoDictionary?["GhosttyCommit"] as? String } private var commit: String? { Bundle.main.infoDictionary?["GhosttyCommit"] as? String }
var version: String? { Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String } private var version: String? { Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String }
private var copyright: String? { Bundle.main.infoDictionary?["NSHumanReadableCopyright"] as? String }
private var properties: [KeyValue<String>] {
let list: [KeyValue<String?>] = [
.init(key: "Version", value: version),
.init(key: "Build", value: build),
.init(key: "Commit", value: commit == "" ? nil : commit)
]
return list.compactMap {
guard let value = $0.value else { return nil }
return .init(key: $0.key, value: value)
}
}
private struct KeyValue<Value: Equatable>: Identifiable {
var id = UUID()
public let key: LocalizedStringResource
public let value: Value
}
#if os(macOS)
// This creates a background style similar to the Apple "About My Mac" Window
private struct VisualEffectBackground: NSViewRepresentable {
let material: NSVisualEffectView.Material
let blendingMode: NSVisualEffectView.BlendingMode
let isEmphasized: Bool
init(material: NSVisualEffectView.Material,
blendingMode: NSVisualEffectView.BlendingMode = .behindWindow,
isEmphasized: Bool = false)
{
self.material = material
self.blendingMode = blendingMode
self.isEmphasized = isEmphasized
}
func updateNSView(_ nsView: NSVisualEffectView, context: Context) {
nsView.material = material
nsView.blendingMode = blendingMode
nsView.isEmphasized = isEmphasized
}
func makeNSView(context: Context) -> NSVisualEffectView {
let visualEffect = NSVisualEffectView()
visualEffect.autoresizingMask = [.width, .height]
return visualEffect
}
}
#endif
var body: some View { var body: some View {
VStack(alignment: .center) { VStack(alignment: .center) {
Image("AppIconImage") Image("AppIconImage")
.resizable() .resizable()
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(maxHeight: 96) .frame(height: 128)
Text("Ghostty") VStack(alignment: .center, spacing: 32) {
.font(.title3) VStack(alignment: .center, spacing: 8) {
Text("Ghostty")
.bold()
.font(.title)
Text("Fast, native, feature-rich terminal \nemulator pushing modern features.")
.multilineTextAlignment(.center)
.fixedSize(horizontal: false, vertical: true)
.font(.caption)
.tint(.secondary)
.opacity(0.8)
}
.textSelection(.enabled) .textSelection(.enabled)
VStack(spacing: 2) {
ForEach(properties) { item in
HStack(spacing: 4) {
Text(item.key)
.frame(width: 126, alignment: .trailing)
.padding(.trailing, 2)
Text(item.value)
.frame(width: 125, alignment: .leading)
.padding(.leading, 2)
.tint(.secondary)
.opacity(0.8)
}
.font(.callout)
.textSelection(.enabled)
.frame(maxWidth: .infinity)
}
}
.frame(maxWidth: .infinity)
if let version = self.version { HStack(spacing: 8) {
Text("Version: \(version)") if let url = githubLink {
.font(.body) Button("GitHub") {
.textSelection(.enabled) openURL(url)
} }
}
if let build = self.build { }
Text("Build: \(build)")
.font(.body) if let copy = self.copyright {
.textSelection(.enabled) Text(copy)
.font(.caption)
.textSelection(.enabled)
.tint(.secondary)
.opacity(0.8)
.multilineTextAlignment(.center)
.frame(maxWidth: .infinity)
}
} }
.frame(maxWidth: .infinity)
} }
.frame(minWidth: 300) .padding(.top, 8)
.padding() .padding(32)
.frame(minWidth: 256)
#if os(macOS)
.background(VisualEffectBackground(material: .underWindowBackground).ignoresSafeArea())
#endif
}
}
struct AboutView_Previews: PreviewProvider {
static var previews: some View {
AboutView()
} }
} }

View File

@ -57,6 +57,14 @@ class BaseTerminalController: NSWindowController,
/// Event monitor (see individual events for why) /// Event monitor (see individual events for why)
private var eventMonitor: Any? = nil private var eventMonitor: Any? = nil
/// The previous frame information from the window
private var savedFrame: SavedFrame? = nil
struct SavedFrame {
let window: NSRect
let screen: NSRect
}
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) is not supported for this view") fatalError("init(coder:) is not supported for this view")
} }
@ -80,6 +88,11 @@ class BaseTerminalController: NSWindowController,
selector: #selector(onConfirmClipboardRequest), selector: #selector(onConfirmClipboardRequest),
name: Ghostty.Notification.confirmClipboard, name: Ghostty.Notification.confirmClipboard,
object: nil) object: nil)
center.addObserver(
self,
selector: #selector(didChangeScreenParametersNotification),
name: NSApplication.didChangeScreenParametersNotification,
object: nil)
// Listen for local events that we need to know of outside of // Listen for local events that we need to know of outside of
// single surface handlers. // single surface handlers.
@ -89,6 +102,8 @@ class BaseTerminalController: NSWindowController,
} }
deinit { deinit {
NotificationCenter.default.removeObserver(self)
if let eventMonitor { if let eventMonitor {
NSEvent.removeMonitor(eventMonitor) NSEvent.removeMonitor(eventMonitor)
} }
@ -121,6 +136,57 @@ class BaseTerminalController: NSWindowController,
} }
} }
// Call this whenever the frame changes
private func windowFrameDidChange() {
// We need to update our saved frame information in case of monitor
// changes (see didChangeScreenParameters notification).
savedFrame = nil
guard let window, let screen = window.screen else { return }
savedFrame = .init(window: window.frame, screen: screen.visibleFrame)
}
// MARK: Notifications
@objc private func didChangeScreenParametersNotification(_ notification: Notification) {
// If we have a window that is visible and it is outside the bounds of the
// screen then we clamp it back to within the screen.
guard let window else { return }
guard window.isVisible else { return }
guard let screen = window.screen else { return }
let visibleFrame = screen.visibleFrame
var newFrame = window.frame
// Clamp width/height
if newFrame.size.width > visibleFrame.size.width {
newFrame.size.width = visibleFrame.size.width
}
if newFrame.size.height > visibleFrame.size.height {
newFrame.size.height = visibleFrame.size.height
}
// Ensure the window is on-screen. We only do this if the previous frame
// was also on screen. If a user explicitly wanted their window off screen
// then we let it stay that way.
x: if newFrame.origin.x < visibleFrame.origin.x {
if let savedFrame, savedFrame.window.origin.x < savedFrame.screen.origin.x {
break x;
}
newFrame.origin.x = visibleFrame.origin.x
}
y: if newFrame.origin.y < visibleFrame.origin.y {
if let savedFrame, savedFrame.window.origin.y < savedFrame.screen.origin.y {
break y;
}
newFrame.origin.y = visibleFrame.origin.y
}
// Apply the new window frame
window.setFrame(newFrame, display: true)
}
// MARK: Local Events // MARK: Local Events
private func localEventHandler(_ event: NSEvent) -> NSEvent? { private func localEventHandler(_ event: NSEvent) -> NSEvent? {
@ -371,6 +437,14 @@ class BaseTerminalController: NSWindowController,
} }
} }
func windowDidResize(_ notification: Notification) {
windowFrameDidChange()
}
func windowDidMove(_ notification: Notification) {
windowFrameDidChange()
}
// MARK: First Responder // MARK: First Responder
@IBAction func close(_ sender: Any) { @IBAction func close(_ sender: Any) {

View File

@ -358,7 +358,8 @@ class TerminalController: BaseTerminalController {
self.fixTabBar() self.fixTabBar()
} }
func windowDidMove(_ notification: Notification) { override func windowDidMove(_ notification: Notification) {
super.windowDidMove(notification)
self.fixTabBar() self.fixTabBar()
} }

View File

@ -43,8 +43,8 @@ class TerminalToolbar: NSToolbar, NSToolbarDelegate {
item.view = self.titleTextField item.view = self.titleTextField
item.visibilityPriority = .user item.visibilityPriority = .user
// This ensures the title text field doesn't disappear when shrinking the view
self.titleTextField.translatesAutoresizingMaskIntoConstraints = false self.titleTextField.translatesAutoresizingMaskIntoConstraints = false
self.titleTextField.setContentHuggingPriority(.defaultLow, for: .horizontal) self.titleTextField.setContentHuggingPriority(.defaultLow, for: .horizontal)
self.titleTextField.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) self.titleTextField.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
@ -52,7 +52,6 @@ class TerminalToolbar: NSToolbar, NSToolbarDelegate {
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
// Set the height constraint to match the toolbar's height // Set the height constraint to match the toolbar's height
self.titleTextField.heightAnchor.constraint(equalToConstant: 22), // Adjust as needed self.titleTextField.heightAnchor.constraint(equalToConstant: 22), // Adjust as needed
]) ])
item.isEnabled = true item.isEnabled = true
@ -82,7 +81,6 @@ class TerminalToolbar: NSToolbar, NSToolbarDelegate {
fileprivate class CenteredDynamicLabel: NSTextField { fileprivate class CenteredDynamicLabel: NSTextField {
override func viewDidMoveToSuperview() { override func viewDidMoveToSuperview() {
// Configure the text field // Configure the text field
isEditable = false isEditable = false
isBordered = false isBordered = false
drawsBackground = false drawsBackground = false

View File

@ -56,7 +56,13 @@ extension Ghostty {
// same filesystem concept. // same filesystem concept.
#if os(macOS) #if os(macOS)
ghostty_config_load_default_files(cfg); ghostty_config_load_default_files(cfg);
ghostty_config_load_cli_args(cfg);
// We only load CLI args when not running in Xcode because in Xcode we
// pass some special parameters to control the debugger.
if !isRunningInXcode() {
ghostty_config_load_cli_args(cfg);
}
ghostty_config_load_recursive_files(cfg); ghostty_config_load_recursive_files(cfg);
#endif #endif

View File

@ -0,0 +1,10 @@
import Foundation
/// True if we appear to be running in Xcode.
func isRunningInXcode() -> Bool {
if let _ = ProcessInfo.processInfo.environment["__XCODE_BUILT_PRODUCTS_DIR_PATHS"] {
return true
}
return false
}

View File

@ -500,6 +500,7 @@ pub fn init(
try termio.Termio.init(&self.io, alloc, .{ try termio.Termio.init(&self.io, alloc, .{
.grid_size = grid_size, .grid_size = grid_size,
.cell_size = cell_size,
.screen_size = screen_size, .screen_size = screen_size,
.padding = padding, .padding = padding,
.full_config = config, .full_config = config,
@ -1331,6 +1332,7 @@ fn setCellSize(self: *Surface, size: renderer.CellSize) !void {
self.io.queueMessage(.{ self.io.queueMessage(.{
.resize = .{ .resize = .{
.grid_size = self.grid_size, .grid_size = self.grid_size,
.cell_size = self.cell_size,
.screen_size = self.screen_size, .screen_size = self.screen_size,
.padding = self.padding, .padding = self.padding,
}, },
@ -1435,6 +1437,7 @@ fn resize(self: *Surface, size: renderer.ScreenSize) !void {
self.io.queueMessage(.{ self.io.queueMessage(.{
.resize = .{ .resize = .{
.grid_size = self.grid_size, .grid_size = self.grid_size,
.cell_size = self.cell_size,
.screen_size = self.screen_size, .screen_size = self.screen_size,
.padding = self.padding, .padding = self.padding,
}, },

View File

@ -23,7 +23,7 @@ pub fn run(alloc: Allocator) !u8 {
defer opts.deinit(); defer opts.deinit();
{ {
var iter = try std.process.argsWithAllocator(alloc); var iter = try args.argsIterator(alloc);
defer iter.deinit(); defer iter.deinit();
try args.parse(Options, alloc, &opts, &iter); try args.parse(Options, alloc, &opts, &iter);
} }

View File

@ -1456,8 +1456,13 @@ keybind: Keybinds = .{},
/// Note that if an *Option*-sequence doesn't produce a printable character, it /// Note that if an *Option*-sequence doesn't produce a printable character, it
/// will be treated as *Alt* regardless of this setting. (i.e. `alt+ctrl+a`). /// will be treated as *Alt* regardless of this setting. (i.e. `alt+ctrl+a`).
/// ///
/// The default value is `left`. This allows alt-based bindings to work
/// with the left *Option* key while still allowing the right *Option* key
/// to be used for Unicode input. This is a common setup for users of
/// certain keyboard layouts.
///
/// This does not work with GLFW builds. /// This does not work with GLFW builds.
@"macos-option-as-alt": OptionAsAlt = .false, @"macos-option-as-alt": OptionAsAlt = .left,
/// Whether to enable the macOS window shadow. The default value is true. /// Whether to enable the macOS window shadow. The default value is true.
/// With some window managers and window transparency settings, you may /// With some window managers and window transparency settings, you may

View File

@ -54,8 +54,9 @@ pub fn add(self: *CodepointMap, alloc: Allocator, entry: Entry) !void {
/// Get a descriptor for a codepoint. /// Get a descriptor for a codepoint.
pub fn get(self: *const CodepointMap, cp: u21) ?discovery.Descriptor { pub fn get(self: *const CodepointMap, cp: u21) ?discovery.Descriptor {
const items = self.list.items(.range); const items = self.list.items(.range);
for (items, 0..) |range, forward_i| { for (0..items.len) |forward_i| {
const i = items.len - forward_i - 1; const i = items.len - forward_i - 1;
const range = items[i];
if (range[0] <= cp and cp <= range[1]) { if (range[0] <= cp and cp <= range[1]) {
const descs = self.list.items(.descriptor); const descs = self.list.items(.descriptor);
return descs[i]; return descs[i];
@ -110,4 +111,15 @@ test "codepointmap" {
// Non-matching // Non-matching
try testing.expect(m.get(0) == null); try testing.expect(m.get(0) == null);
try testing.expect(m.get(3) == null); try testing.expect(m.get(3) == null);
try m.add(alloc, .{ .range = .{ 3, 4 }, .descriptor = .{ .family = "C" } });
try m.add(alloc, .{ .range = .{ 5, 6 }, .descriptor = .{ .family = "D" } });
{
const d = m.get(3).?;
try testing.expectEqualStrings("C", d.family.?);
}
{
const d = m.get(1).?;
try testing.expectEqualStrings("B", d.family.?);
}
} }

View File

@ -11,6 +11,9 @@ const termio = @import("../termio.zig");
/// The size of the terminal grid. /// The size of the terminal grid.
grid_size: renderer.GridSize, grid_size: renderer.GridSize,
/// The size of a single cell, in pixels.
cell_size: renderer.CellSize,
/// The size of the viewport in pixels. /// The size of the viewport in pixels.
screen_size: renderer.ScreenSize, screen_size: renderer.ScreenSize,

View File

@ -60,6 +60,9 @@ surface_mailbox: apprt.surface.Mailbox,
/// The cached grid size whenever a resize is called. /// The cached grid size whenever a resize is called.
grid_size: renderer.GridSize, grid_size: renderer.GridSize,
/// The size of a single cell. Used for size reports.
cell_size: renderer.CellSize,
/// The mailbox implementation to use. /// The mailbox implementation to use.
mailbox: termio.Mailbox, mailbox: termio.Mailbox,
@ -171,9 +174,8 @@ pub fn init(self: *Termio, alloc: Allocator, opts: termio.Options) !void {
backend.initTerminal(&term); backend.initTerminal(&term);
// Setup our terminal size in pixels for certain requests. // Setup our terminal size in pixels for certain requests.
const screen_size = opts.screen_size.subPadding(opts.padding); term.width_px = opts.grid_size.columns * opts.cell_size.width;
term.width_px = screen_size.width; term.height_px = opts.grid_size.rows * opts.cell_size.height;
term.height_px = screen_size.height;
// Create our stream handler. This points to memory in self so it // Create our stream handler. This points to memory in self so it
// isn't safe to use until self.* is set. // isn't safe to use until self.* is set.
@ -214,6 +216,7 @@ pub fn init(self: *Termio, alloc: Allocator, opts: termio.Options) !void {
.renderer_mailbox = opts.renderer_mailbox, .renderer_mailbox = opts.renderer_mailbox,
.surface_mailbox = opts.surface_mailbox, .surface_mailbox = opts.surface_mailbox,
.grid_size = opts.grid_size, .grid_size = opts.grid_size,
.cell_size = opts.cell_size,
.backend = opts.backend, .backend = opts.backend,
.mailbox = opts.mailbox, .mailbox = opts.mailbox,
.terminal_stream = .{ .terminal_stream = .{
@ -348,6 +351,7 @@ pub fn resize(
self: *Termio, self: *Termio,
td: *ThreadData, td: *ThreadData,
grid_size: renderer.GridSize, grid_size: renderer.GridSize,
cell_size: renderer.CellSize,
screen_size: renderer.ScreenSize, screen_size: renderer.ScreenSize,
padding: renderer.Padding, padding: renderer.Padding,
) !void { ) !void {
@ -357,6 +361,7 @@ pub fn resize(
// Update our cached grid size // Update our cached grid size
self.grid_size = grid_size; self.grid_size = grid_size;
self.cell_size = cell_size;
// Enter the critical area that we want to keep small // Enter the critical area that we want to keep small
{ {
@ -371,8 +376,8 @@ pub fn resize(
); );
// Update our pixel sizes // Update our pixel sizes
self.terminal.width_px = padded_size.width; self.terminal.width_px = self.grid_size.columns * self.cell_size.width;
self.terminal.height_px = padded_size.height; self.terminal.height_px = self.grid_size.rows * self.cell_size.height;
// Disable synchronized output mode so that we show changes // Disable synchronized output mode so that we show changes
// immediately for a resize. This is allowed by the spec. // immediately for a resize. This is allowed by the spec.
@ -412,24 +417,24 @@ fn sizeReportLocked(self: *Termio, td: *ThreadData, style: termio.Message.SizeRe
.{ .{
self.grid_size.rows, self.grid_size.rows,
self.grid_size.columns, self.grid_size.columns,
self.terminal.height_px, self.grid_size.rows * self.cell_size.height,
self.terminal.width_px, self.grid_size.columns * self.cell_size.width,
}, },
), ),
.csi_14_t => try std.fmt.bufPrint( .csi_14_t => try std.fmt.bufPrint(
&buf, &buf,
"\x1b[4;{};{}t", "\x1b[4;{};{}t",
.{ .{
self.terminal.height_px, self.grid_size.rows * self.cell_size.height,
self.terminal.width_px, self.grid_size.columns * self.cell_size.width,
}, },
), ),
.csi_16_t => try std.fmt.bufPrint( .csi_16_t => try std.fmt.bufPrint(
&buf, &buf,
"\x1b[6;{};{}t", "\x1b[6;{};{}t",
.{ .{
self.terminal.height_px / self.grid_size.rows, self.cell_size.height,
self.terminal.width_px / self.grid_size.columns, self.cell_size.width,
}, },
), ),
.csi_18_t => try std.fmt.bufPrint( .csi_18_t => try std.fmt.bufPrint(

View File

@ -383,6 +383,7 @@ fn coalesceCallback(
cb.io.resize( cb.io.resize(
&cb.data, &cb.data,
v.grid_size, v.grid_size,
v.cell_size,
v.screen_size, v.screen_size,
v.padding, v.padding,
) catch |err| { ) catch |err| {

View File

@ -20,6 +20,9 @@ pub const Message = union(enum) {
/// The grid size for the given screen size with padding applied. /// The grid size for the given screen size with padding applied.
grid_size: renderer.GridSize, grid_size: renderer.GridSize,
/// The updated cell size.
cell_size: renderer.CellSize,
/// The full screen (drawable) size. This does NOT include padding. /// The full screen (drawable) size. This does NOT include padding.
/// This should be sent on to the renderer. /// This should be sent on to the renderer.
screen_size: renderer.ScreenSize, screen_size: renderer.ScreenSize,