mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
macos: set correct title for surface title
This commit is contained in:
@ -10,11 +10,20 @@ import GhosttyKit
|
|||||||
/// since that is what the Metal renderer in Ghostty expects. In the future, it may make more sense to
|
/// since that is what the Metal renderer in Ghostty expects. In the future, it may make more sense to
|
||||||
/// wrap an MTKView and use that, but for legacy reasons we didn't do that to begin with.
|
/// wrap an MTKView and use that, but for legacy reasons we didn't do that to begin with.
|
||||||
struct TerminalSurfaceView: NSViewRepresentable {
|
struct TerminalSurfaceView: NSViewRepresentable {
|
||||||
|
/// This should be set to true wen the surface has focus. This is up to the parent because
|
||||||
|
/// focus is also defined by window focus. It is important this is set correctly since if it is
|
||||||
|
/// false then the surface will idle at almost 0% CPU.
|
||||||
var hasFocus: Bool
|
var hasFocus: Bool
|
||||||
|
|
||||||
|
/// This is set to the title of the surface as defined by the pty. Callers should use this to
|
||||||
|
/// set the appropriate title of the window/tab/split/etc. if they care.
|
||||||
|
@Binding var title: String
|
||||||
|
|
||||||
@StateObject private var state: TerminalSurfaceView_Real
|
@StateObject private var state: TerminalSurfaceView_Real
|
||||||
|
|
||||||
init(app: ghostty_app_t, hasFocus: Bool) {
|
init(_ app: ghostty_app_t, hasFocus: Bool, title: Binding<String>) {
|
||||||
self._state = StateObject(wrappedValue: TerminalSurfaceView_Real(app))
|
self._state = StateObject(wrappedValue: TerminalSurfaceView_Real(app))
|
||||||
|
self._title = title
|
||||||
self.hasFocus = hasFocus
|
self.hasFocus = hasFocus
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,30 +31,62 @@ struct TerminalSurfaceView: NSViewRepresentable {
|
|||||||
// We need the view as part of the state to be created previously because
|
// We need the view as part of the state to be created previously because
|
||||||
// the view is sent to the Ghostty API so that it can manipulate it
|
// the view is sent to the Ghostty API so that it can manipulate it
|
||||||
// directly since we draw on a render thread.
|
// directly since we draw on a render thread.
|
||||||
|
state.delegate = context.coordinator
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNSView(_ view: TerminalSurfaceView_Real, context: Context) {
|
func updateNSView(_ view: TerminalSurfaceView_Real, context: Context) {
|
||||||
|
state.delegate = context.coordinator
|
||||||
state.focusDidChange(hasFocus)
|
state.focusDidChange(hasFocus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeCoordinator() -> Coordinator {
|
||||||
|
return Coordinator(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Coordinator : TerminalSurfaceDelegate {
|
||||||
|
let view: TerminalSurfaceView
|
||||||
|
|
||||||
|
init(_ view: TerminalSurfaceView) {
|
||||||
|
self.view = view
|
||||||
|
}
|
||||||
|
|
||||||
|
func titleDidChange(to: String) {
|
||||||
|
view.title = to
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The actual NSView implementation for the terminal surface.
|
/// We use the delegate pattern to receive notifications about important state changes in the surface.
|
||||||
|
protocol TerminalSurfaceDelegate: AnyObject {
|
||||||
|
func titleDidChange(to: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The actual NSView implementation for the terminal surface.
|
||||||
class TerminalSurfaceView_Real: NSView, NSTextInputClient, ObservableObject {
|
class TerminalSurfaceView_Real: NSView, NSTextInputClient, ObservableObject {
|
||||||
|
weak var delegate: TerminalSurfaceDelegate?
|
||||||
|
|
||||||
|
// The current title of the surface as defined by the pty. This can be
|
||||||
|
// changed with escape codes.
|
||||||
|
var title: String = "" {
|
||||||
|
didSet {
|
||||||
|
if let delegate = self.delegate {
|
||||||
|
delegate.titleDidChange(to: title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var surface: ghostty_surface_t? = nil
|
||||||
|
private var error: Error? = nil
|
||||||
|
private var markedText: NSMutableAttributedString;
|
||||||
|
|
||||||
// We need to support being a first responder so that we can get input events
|
// We need to support being a first responder so that we can get input events
|
||||||
override var acceptsFirstResponder: Bool { return true }
|
override var acceptsFirstResponder: Bool { return true }
|
||||||
|
|
||||||
// I don't thikn we need this but this lets us know we should redraw our layer
|
// I don't thikn we need this but this lets us know we should redraw our layer
|
||||||
// so we'll use that to tell ghostty to refresh.
|
// so we'll use that to tell ghostty to refresh.
|
||||||
override var wantsUpdateLayer: Bool { return true }
|
override var wantsUpdateLayer: Bool { return true }
|
||||||
|
|
||||||
// TODO: Figure out how to hook this up...
|
|
||||||
@Published var title: String = "";
|
|
||||||
|
|
||||||
private var surface: ghostty_surface_t? = nil
|
|
||||||
private var error: Error? = nil
|
|
||||||
private var markedText: NSMutableAttributedString;
|
|
||||||
|
|
||||||
// Mapping of event keyCode to ghostty input key values. This is cribbed from
|
// Mapping of event keyCode to ghostty input key values. This is cribbed from
|
||||||
// glfw mostly since we started as a glfw-based app way back in the day!
|
// glfw mostly since we started as a glfw-based app way back in the day!
|
||||||
static let keycodes: [UInt16 : ghostty_input_key_e] = [
|
static let keycodes: [UInt16 : ghostty_input_key_e] = [
|
||||||
@ -334,11 +375,3 @@ class TerminalSurfaceView_Real: NSView, NSTextInputClient, ObservableObject {
|
|||||||
return ghostty_input_mods_e(mods)
|
return ghostty_input_mods_e(mods)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
struct TerminalSurfaceView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
TerminalSurfaceView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
@ -5,6 +5,7 @@ struct TerminalView: View {
|
|||||||
let app: ghostty_app_t
|
let app: ghostty_app_t
|
||||||
@FocusState private var surfaceFocus: Bool
|
@FocusState private var surfaceFocus: Bool
|
||||||
@Environment(\.isKeyWindow) private var isKeyWindow: Bool
|
@Environment(\.isKeyWindow) private var isKeyWindow: Bool
|
||||||
|
@State private var title: String = "Ghostty"
|
||||||
|
|
||||||
// This is true if the terminal is considered "focused". The terminal is focused if
|
// This is true if the terminal is considered "focused". The terminal is focused if
|
||||||
// it is both individually focused and the containing window is key.
|
// it is both individually focused and the containing window is key.
|
||||||
@ -12,8 +13,9 @@ struct TerminalView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
TerminalSurfaceView(app: app, hasFocus: hasFocus)
|
TerminalSurfaceView(app, hasFocus: hasFocus, title: $title)
|
||||||
.focused($surfaceFocus)
|
.focused($surfaceFocus)
|
||||||
|
.navigationTitle(title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user