Skip to content

Commit f3bd408

Browse files
committed
Support keeping chat panel on top when it overlaps Xcode window
1 parent 3b1f2d0 commit f3bd408

2 files changed

Lines changed: 69 additions & 0 deletions

File tree

Core/Sources/SuggestionWidget/ChatPanelWindow.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,16 @@ final class ChatPanelWindow: NSWindow {
7474
}.store(in: &cancellable)
7575
}
7676

77+
func setFloatOnTop(_ isFloatOnTop: Bool) {
78+
let targetLevel: NSWindow.Level = isFloatOnTop
79+
? .init(NSWindow.Level.floating.rawValue + 1)
80+
: .normal
81+
82+
if targetLevel != level {
83+
level = targetLevel
84+
}
85+
}
86+
7787
var isWindowHidden: Bool = false {
7888
didSet {
7989
alphaValue = isPanelDisplayed && !isWindowHidden ? 1 : 0

Core/Sources/SuggestionWidget/WidgetWindowsController.swift

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,8 @@ extension WidgetWindowsController {
462462
animate: animated
463463
)
464464
}
465+
466+
await adjustChatPanelWindowLevel()
465467
}
466468

467469
let now = Date()
@@ -489,6 +491,53 @@ extension WidgetWindowsController {
489491
}
490492
lastUpdateWindowLocationTime = Date()
491493
}
494+
495+
@MainActor
496+
func adjustChatPanelWindowLevel() async {
497+
let disableFloatOnTopWhenTheChatPanelIsDetached = UserDefaults.shared
498+
.value(for: \.disableFloatOnTopWhenTheChatPanelIsDetached)
499+
500+
let window = windows.chatPanelWindow
501+
guard disableFloatOnTopWhenTheChatPanelIsDetached else {
502+
window.setFloatOnTop(true)
503+
return
504+
}
505+
506+
let state = store.withState { $0 }
507+
let isChatPanelDetached = state.chatPanelState.isDetached
508+
509+
guard isChatPanelDetached else {
510+
window.setFloatOnTop(true)
511+
return
512+
}
513+
514+
let floatOnTopWhenOverlapsXcode = UserDefaults.shared
515+
.value(for: \.keepFloatOnTopIfChatPanelAndXcodeOverlaps)
516+
517+
if !floatOnTopWhenOverlapsXcode {
518+
window.setFloatOnTop(false)
519+
} else {
520+
guard let xcode = await xcodeInspector.safe.latestActiveXcode else { return }
521+
let windowElements = xcode.appElement.windows
522+
let windowRects = windowElements.compactMap {
523+
if let position = $0.position, let size = $0.size {
524+
return CGRect(
525+
x: position.x,
526+
y: position.y,
527+
width: size.width,
528+
height: size.height
529+
)
530+
}
531+
return nil
532+
}
533+
534+
let overlap = windowRects.contains {
535+
$0.intersects(window.frame)
536+
}
537+
538+
window.setFloatOnTop(overlap)
539+
}
540+
}
492541
}
493542

494543
// MARK: - NSWindowDelegate
@@ -504,6 +553,16 @@ extension WidgetWindowsController: NSWindowDelegate {
504553
}
505554
}
506555

556+
nonisolated
557+
func windowDidMove(_ notification: Notification) {
558+
guard let window = notification.object as? NSWindow else { return }
559+
Task { @MainActor in
560+
guard window === windows.chatPanelWindow else { return }
561+
await Task.yield()
562+
await adjustChatPanelWindowLevel()
563+
}
564+
}
565+
507566
nonisolated
508567
func windowWillEnterFullScreen(_ notification: Notification) {
509568
guard let window = notification.object as? NSWindow else { return }

0 commit comments

Comments
 (0)