Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 53 additions & 2 deletions macos/Sources/App/macOS/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ class AppDelegate: NSObject,
]

let center = UNUserNotificationCenter.current()

center.setNotificationCategories([
UNNotificationCategory(
identifier: Ghostty.userNotificationCategory,
Expand Down Expand Up @@ -231,6 +232,9 @@ class AppDelegate: NSObject,
// If we're back manually then clear the hidden state because macOS handles it.
self.hiddenState = nil

// Clear the dock badge when the app becomes active
self.setDockBadge(nil)

// First launch stuff
if (!applicationHasBecomeActive) {
applicationHasBecomeActive = true
Expand Down Expand Up @@ -511,6 +515,53 @@ class AppDelegate: NSObject,
@objc private func ghosttyBellDidRing(_ notification: Notification) {
// Bounce the dock icon if we're not focused.
NSApp.requestUserAttention(.informationalRequest)

// Handle setting the dock badge based on permissions
ghosttyUpdateBadgeForBell()
}

private func ghosttyUpdateBadgeForBell() {
let center = UNUserNotificationCenter.current()
center.getNotificationSettings { settings in
switch settings.authorizationStatus {
case .authorized:
// Already authorized, check badge setting and set if enabled
if settings.badgeSetting == .enabled {
DispatchQueue.main.async {
self.setDockBadge()
}
}

case .notDetermined:
// Not determined yet, request authorization for badge
center.requestAuthorization(options: [.badge]) { granted, error in
if let error = error {
Self.logger.warning("Error requesting badge authorization: \(error)")
return
}

if granted {
// Permission granted, set the badge
DispatchQueue.main.async {
self.setDockBadge()
}
}
}

case .denied, .provisional, .ephemeral:
// In these known non-authorized states, do not attempt to set the badge.
break

@unknown default:
// Handle future unknown states by doing nothing.
break
}
}
}

private func setDockBadge(_ label: String? = "•") {
NSApp.dockTile.badgeLabel = label
NSApp.dockTile.display()
}

private func ghosttyConfigDidChange(config: Ghostty.Config) {
Expand Down Expand Up @@ -790,12 +841,12 @@ class AppDelegate: NSObject,
hiddenState?.restore()
hiddenState = nil
}

@IBAction func bringAllToFront(_ sender: Any) {
if !NSApp.isActive {
NSApp.activate(ignoringOtherApps: true)
}

NSApplication.shared.arrangeInFront(sender)
}

Expand Down