mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
Merge pull request #1165 from mitchellh/dangling-notification
macos: notifications use surface UUID for lookups
This commit is contained in:
@ -332,6 +332,16 @@ class AppDelegate: NSObject,
|
||||
|
||||
//MARK: - GhosttyAppStateDelegate
|
||||
|
||||
func findSurface(forUUID uuid: UUID) -> Ghostty.SurfaceView? {
|
||||
for c in terminalManager.windows {
|
||||
if let v = c.controller.surfaceTree?.findUUID(uuid: uuid) {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func configDidReload(_ state: Ghostty.AppState) {
|
||||
// Depending on the "window-save-state" setting we have to set the NSQuitAlwaysKeepsWindows
|
||||
// configuration. This is the only way to carefully control whether macOS invokes the
|
||||
|
@ -5,6 +5,10 @@ import GhosttyKit
|
||||
protocol GhosttyAppStateDelegate: AnyObject {
|
||||
/// Called when the configuration did finish reloading.
|
||||
func configDidReload(_ state: Ghostty.AppState)
|
||||
|
||||
/// Called when a callback needs access to a specific surface. This should return nil
|
||||
/// when the surface is no longer valid.
|
||||
func findSurface(forUUID uuid: UUID) -> Ghostty.SurfaceView?
|
||||
}
|
||||
|
||||
extension Ghostty {
|
||||
@ -608,9 +612,9 @@ extension Ghostty {
|
||||
/// Handle a received user notification. This is called when a user notification is clicked or dismissed by the user
|
||||
func handleUserNotification(response: UNNotificationResponse) {
|
||||
let userInfo = response.notification.request.content.userInfo
|
||||
guard let address = userInfo["address"] as? Int else { return }
|
||||
guard let userdata = UnsafeMutableRawPointer(bitPattern: address) else { return }
|
||||
let surface = Ghostty.AppState.surfaceUserdata(from: userdata)
|
||||
guard let uuidString = userInfo["surface"] as? String,
|
||||
let uuid = UUID(uuidString: uuidString),
|
||||
let surface = delegate?.findSurface(forUUID: uuid) else { return }
|
||||
|
||||
switch (response.actionIdentifier) {
|
||||
case UNNotificationDefaultActionIdentifier, Ghostty.userNotificationActionShow:
|
||||
@ -627,11 +631,10 @@ extension Ghostty {
|
||||
/// Determine if a given notification should be presented to the user when Ghostty is running in the foreground.
|
||||
func shouldPresentNotification(notification: UNNotification) -> Bool {
|
||||
let userInfo = notification.request.content.userInfo
|
||||
guard let address = userInfo["address"] as? Int else { return false }
|
||||
guard let userdata = UnsafeMutableRawPointer(bitPattern: address) else { return false }
|
||||
let surface = Ghostty.AppState.surfaceUserdata(from: userdata)
|
||||
|
||||
guard let window = surface.window else { return false }
|
||||
guard let uuidString = userInfo["surface"] as? String,
|
||||
let uuid = UUID(uuidString: uuidString),
|
||||
let surface = delegate?.findSurface(forUUID: uuid),
|
||||
let window = surface.window else { return false }
|
||||
return !window.isKeyWindow || !surface.focused
|
||||
}
|
||||
|
||||
|
@ -1145,16 +1145,7 @@ extension Ghostty {
|
||||
content.body = body
|
||||
content.sound = UNNotificationSound.default
|
||||
content.categoryIdentifier = Ghostty.userNotificationCategory
|
||||
|
||||
// The userInfo must conform to NSSecureCoding, which SurfaceView
|
||||
// does not. So instead we pass an integer representation of the
|
||||
// SurfaceView's address, which is reconstructed back into a
|
||||
// SurfaceView if the notification is clicked. This is safe to do
|
||||
// so long as the SurfaceView removes all of its notifications when
|
||||
// it closes so that there are no dangling pointers.
|
||||
content.userInfo = [
|
||||
"address": Int(bitPattern: Unmanaged.passUnretained(self).toOpaque()),
|
||||
]
|
||||
content.userInfo = ["surface": self.uuid.uuidString]
|
||||
|
||||
let uuid = UUID().uuidString
|
||||
let request = UNNotificationRequest(
|
||||
|
Reference in New Issue
Block a user