Skip to content
20 changes: 15 additions & 5 deletions LilAgents/CharacterContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,16 @@ class KeyableWindow: NSWindow {
override var canBecomeMain: Bool { true }
}

class NonKeyableWindow: NSWindow {
override var canBecomeKey: Bool { false }
override var canBecomeMain: Bool { false }
}

class CharacterContentView: NSView {
weak var character: WalkerCharacter?

override var isOpaque: Bool { false }

override func hitTest(_ point: NSPoint) -> NSView? {
let localPoint = convert(point, from: superview)
guard bounds.contains(localPoint) else { return nil }
Expand All @@ -25,6 +32,11 @@ class CharacterContentView: NSView {
let captureRect = CGRect(x: screenPoint.x - 0.5, y: flippedY - 0.5, width: 1, height: 1)
guard let windowID = window?.windowNumber, windowID > 0 else { return nil }

// Fallback hit rect for when pixel sampling fails or video is paused
let insetX = bounds.width * 0.2
let insetY = bounds.height * 0.15
let hitRect = bounds.insetBy(dx: insetX, dy: insetY)

if let image = CGWindowListCreateImage(
captureRect,
.optionIncludingWindow,
Expand All @@ -43,14 +55,12 @@ class CharacterContentView: NSView {
if pixel[3] > 30 {
return self
}
return nil
// Pixel was transparent — use fallback rect if in center area
return hitRect.contains(localPoint) ? self : nil
}
}

// Fallback: accept click if within center 60% of the view
let insetX = bounds.width * 0.2
let insetY = bounds.height * 0.15
let hitRect = bounds.insetBy(dx: insetX, dy: insetY)
// CGWindowListCreateImage failed — use fallback
return hitRect.contains(localPoint) ? self : nil
}

Expand Down
12 changes: 11 additions & 1 deletion LilAgents/LilAgentsApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}

func applicationWillTerminate(_ notification: Notification) {
controller?.characters.forEach { $0.session?.terminate() }
controller?.characters.forEach {
$0.session?.terminate()
$0.terminateAllDetachedSessions()
}
}

// MARK: - Menu Bar
Expand Down Expand Up @@ -144,17 +147,23 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}

controller?.characters.forEach { char in
if char.hasDetachedChats {
char.refreshDetachedChromeTheme()
char.reapplyAppearanceToAllDetachedTerminals()
}
let wasOpen = char.isIdleForPopover
if wasOpen { char.popoverWindow?.orderOut(nil) }
char.popoverWindow = nil
char.terminalView = nil
char.thinkingBubbleWindow = nil
if wasOpen {
char.createPopoverWindow()
char.rewirePopoverSessionIfNeeded()
if let session = char.session, !session.history.isEmpty {
char.terminalView?.replayHistory(session.history)
}
char.updatePopoverPosition()
char.ensurePopoverAboveCharacterWindow()
char.popoverWindow?.orderFrontRegardless()
char.popoverWindow?.makeKey()
if let terminal = char.terminalView {
Expand All @@ -173,6 +182,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
controller?.characters.forEach { char in
if char.provider == newProvider { return }
char.provider = newProvider
char.discardDetachedChatSilently()
char.session?.terminate()
char.session = nil
char.popoverWindow?.orderOut(nil)
Expand Down
3 changes: 3 additions & 0 deletions LilAgents/LilAgentsController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ class LilAgentsController {
for (i, char) in sorted.enumerated() {
char.window.level = NSWindow.Level(rawValue: NSWindow.Level.statusBar.rawValue + i)
}
for char in activeChars where char.isIdleForPopover {
char.ensurePopoverAboveCharacterWindow()
}
}

deinit {
Expand Down
17 changes: 17 additions & 0 deletions LilAgents/TerminalView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,23 @@ class TerminalView: NSView {
addSubview(inputField)
}

/// Re-apply colors and fonts from the current `theme` (e.g. after global style switch while this view is kept open).
func reapplyAppearanceFromTheme() {
let t = theme
textView.textColor = t.textPrimary
textView.font = t.font
textView.linkTextAttributes = [
.foregroundColor: t.accentColor,
.underlineStyle: NSUnderlineStyle.single.rawValue
]
if let cell = inputField.cell as? PaddedTextFieldCell {
cell.font = t.font
cell.textColor = t.textPrimary
}
updatePlaceholder()
needsDisplay = true
}

func resetState() {
isStreaming = false
currentAssistantText = ""
Expand Down
Loading