diff --git a/macos/Sources/Ghostty/SurfaceView_AppKit.swift b/macos/Sources/Ghostty/SurfaceView_AppKit.swift index f04bf1af3..301ef5a9b 100644 --- a/macos/Sources/Ghostty/SurfaceView_AppKit.swift +++ b/macos/Sources/Ghostty/SurfaceView_AppKit.swift @@ -201,7 +201,14 @@ extension Ghostty { self.eventMonitor = NSEvent.addLocalMonitorForEvents( matching: [ // We need keyUp because command+key events don't trigger keyUp. - .keyUp + .keyUp, + + // We need leftMouseDown to determine if we should focus ourselves + // when the app/window isn't in focus. We do this instead of + // "acceptsFirstMouse" because that forces us to also handle the + // event and encode the event to the pty which we want to avoid. + // (Issue 2595) + .leftMouseDown, ] ) { [weak self] event in self?.localEventHandler(event) } @@ -450,11 +457,40 @@ extension Ghostty { case .keyUp: localEventKeyUp(event) + case .leftMouseDown: + localEventLeftMouseDown(event) + default: event } } + private func localEventLeftMouseDown(_ event: NSEvent) -> NSEvent? { + // We only want to process events that are on this window. + guard let window, + event.window != nil, + window == event.window else { return event } + + // The clicked location in this window should be this view. + let location = convert(event.locationInWindow, from: nil) + guard hitTest(location) == self else { return event } + + // We only want to grab focus if either our app or window was + // not focused. + guard !NSApp.isActive || !window.isKeyWindow else { return event } + + // If we're already focused we do nothing + guard !focused else { return event } + + // Make ourselves the first responder + window.makeFirstResponder(self) + + // We have to keep processing the event so that AppKit can properly + // focus the window and dispatch events. If you return nil here then + // nobody gets a windowDidBecomeKey event and so on. + return event + } + private func localEventKeyUp(_ event: NSEvent) -> NSEvent? { // We only care about events with "command" because all others will // trigger the normal responder chain. @@ -620,14 +656,6 @@ extension Ghostty { ghostty_surface_draw(surface); } - override func acceptsFirstMouse(for event: NSEvent?) -> Bool { - // "Override this method in a subclass to allow instances to respond to - // click-through. This allows the user to click on a view in an inactive - // window, activating the view with one click, instead of clicking first - // to make the window active and then clicking the view." - return true - } - override func mouseDown(with event: NSEvent) { guard let surface = self.surface else { return } let mods = Ghostty.ghosttyMods(event.modifierFlags)