mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-09-05 19:08:17 +00:00
macos: dismiss notifications on focus, application exit
I've only recently been using programs that use user notifications heavily and this commit addresses a number of annoyances I've encountered. 1. Notifications dispatched while the source terminal surface is focused are now only shown for a short time (3 seconds hardcoded) and then automatically dismiss. 2. Notifications are dismissed when the target surface becomes focused from an unfocused state. This dismissal happens immediately (no delay). 3. Notifications are dismissed when the application exits. 4. This fixes a bug where notification callbacks were modifying view state, but the notification center doesn't guarantee that the callback is called on the main thread. We now ensure that the callback is always called on the main thread.
This commit is contained in:
@@ -316,6 +316,13 @@ class AppDelegate: NSObject,
|
||||
}
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ notification: Notification) {
|
||||
// We have no notifications we want to persist after death,
|
||||
// so remove them all now. In the future we may want to be
|
||||
// more selective and only remove surface-targeted notifications.
|
||||
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
|
||||
}
|
||||
|
||||
/// This is called when the application is already open and someone double-clicks the icon
|
||||
/// or clicks the dock icon.
|
||||
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
|
||||
|
@@ -306,6 +306,14 @@ extension Ghostty {
|
||||
|
||||
// We unset our bell state if we gained focus
|
||||
bell = false
|
||||
|
||||
// Remove any notifications for this surface once we gain focus.
|
||||
if !notificationIdentifiers.isEmpty {
|
||||
UNUserNotificationCenter.current()
|
||||
.removeDeliveredNotifications(
|
||||
withIdentifiers: Array(notificationIdentifiers))
|
||||
self.notificationIdentifiers = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1388,13 +1396,29 @@ extension Ghostty {
|
||||
trigger: nil
|
||||
)
|
||||
|
||||
UNUserNotificationCenter.current().add(request) { error in
|
||||
// Note the callback may be executed on a background thread as documented
|
||||
// so we need @MainActor since we're reading/writing view state.
|
||||
UNUserNotificationCenter.current().add(request) { @MainActor error in
|
||||
if let error = error {
|
||||
AppDelegate.logger.error("Error scheduling user notification: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
// We need to keep track of this notification so we can remove it
|
||||
// under certain circumstances
|
||||
self.notificationIdentifiers.insert(uuid)
|
||||
|
||||
// If we're focused then we schedule to remove the notification
|
||||
// after a few seconds. If we gain focus we automatically remove it
|
||||
// in focusDidChange.
|
||||
if (self.focused) {
|
||||
Task { @MainActor [weak self] in
|
||||
try await Task.sleep(for: .seconds(3))
|
||||
self?.notificationIdentifiers.remove(uuid)
|
||||
UNUserNotificationCenter.current()
|
||||
.removeDeliveredNotifications(withIdentifiers: [uuid])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user