Skip to content

Commit 9df3514

Browse files
committed
Update widget show/hide behavior
1 parent a23c504 commit 9df3514

2 files changed

Lines changed: 60 additions & 21 deletions

File tree

Core/Sources/AXExtension/AXUIElement.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public extension AXUIElement {
1515
var title: String {
1616
(try? copyValue(key: kAXTitleAttribute)) ?? ""
1717
}
18-
18+
1919
var role: String {
2020
(try? copyValue(key: kAXRoleAttribute)) ?? ""
2121
}
@@ -32,12 +32,12 @@ public extension AXUIElement {
3232
var description: String {
3333
(try? copyValue(key: kAXDescriptionAttribute)) ?? ""
3434
}
35-
35+
3636
/// Type in Accessibility Inspector.
3737
var roleDescription: String {
3838
(try? copyValue(key: kAXRoleDescriptionAttribute)) ?? ""
3939
}
40-
40+
4141
var label: String {
4242
(try? copyValue(key: kAXLabelValueAttribute)) ?? ""
4343
}
@@ -113,6 +113,10 @@ public extension AXUIElement {
113113
(try? copyValue(key: kAXWindowsAttribute)) ?? []
114114
}
115115

116+
var isFullScreen: Bool {
117+
(try? copyValue(key: "AXFullScreen")) ?? false
118+
}
119+
116120
var focusedWindow: AXUIElement? {
117121
try? copyValue(key: kAXFocusedWindowAttribute)
118122
}
@@ -164,7 +168,7 @@ public extension AXUIElement {
164168
}
165169
return nil
166170
}
167-
171+
168172
func children(where match: (AXUIElement) -> Bool) -> [AXUIElement] {
169173
var all = [AXUIElement]()
170174
for child in children {
@@ -175,7 +179,7 @@ public extension AXUIElement {
175179
}
176180
return all
177181
}
178-
182+
179183
func firstChild(where match: (AXUIElement) -> Bool) -> AXUIElement? {
180184
for child in children {
181185
if match(child) { return child }
@@ -233,3 +237,4 @@ public extension AXUIElement {
233237
}
234238

235239
extension AXError: Error {}
240+

Core/Sources/SuggestionWidget/SuggestionWidgetController.swift

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@ import UserDefaultsObserver
1010

1111
@MainActor
1212
public final class SuggestionWidgetController: NSObject {
13+
private lazy var fullscreenDetector = {
14+
let it = CanBecomeKeyWindow(
15+
contentRect: .zero,
16+
styleMask: .borderless,
17+
backing: .buffered,
18+
defer: false
19+
)
20+
it.isReleasedWhenClosed = false
21+
it.isOpaque = false
22+
it.backgroundColor = .clear
23+
it.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
24+
it.hasShadow = false
25+
it.setIsVisible(true)
26+
it.canBecomeKeyChecker = { false }
27+
return it
28+
}()
29+
1330
private lazy var widgetWindow = {
1431
let it = CanBecomeKeyWindow(
1532
contentRect: .zero,
@@ -21,7 +38,7 @@ public final class SuggestionWidgetController: NSObject {
2138
it.isOpaque = false
2239
it.backgroundColor = .clear
2340
it.level = .init(19)
24-
it.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
41+
it.collectionBehavior = [.fullScreenAuxiliary]
2542
it.hasShadow = true
2643
it.contentView = NSHostingView(
2744
rootView: WidgetView(
@@ -52,7 +69,7 @@ public final class SuggestionWidgetController: NSObject {
5269
it.isOpaque = false
5370
it.backgroundColor = .clear
5471
it.level = .init(19)
55-
it.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
72+
it.collectionBehavior = [.fullScreenAuxiliary]
5673
it.hasShadow = true
5774
it.contentView = NSHostingView(
5875
rootView: TabView(chatWindowViewModel: chatWindowViewModel)
@@ -64,7 +81,7 @@ public final class SuggestionWidgetController: NSObject {
6481

6582
private lazy var panelWindow = {
6683
let it = CanBecomeKeyWindow(
67-
contentRect: .zero,
84+
contentRect: .init(x: 0, y: 0, width: Style.panelWidth, height: Style.panelHeight),
6885
styleMask: .borderless,
6986
backing: .buffered,
7087
defer: false
@@ -73,16 +90,13 @@ public final class SuggestionWidgetController: NSObject {
7390
it.isOpaque = false
7491
it.backgroundColor = .clear
7592
it.level = .init(NSWindow.Level.floating.rawValue + 1)
76-
it.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
93+
it.collectionBehavior = [.fullScreenAuxiliary]
7794
it.hasShadow = true
7895
it.contentView = NSHostingView(
7996
rootView: SuggestionPanelView(viewModel: suggestionPanelViewModel)
8097
)
8198
it.setIsVisible(true)
82-
it.canBecomeKeyChecker = { [suggestionPanelViewModel] in
83-
if case .promptToCode = suggestionPanelViewModel.content { return true }
84-
return false
85-
}
99+
it.canBecomeKeyChecker = { true }
86100
return it
87101
}()
88102

@@ -97,7 +111,7 @@ public final class SuggestionWidgetController: NSObject {
97111
it.isOpaque = false
98112
it.backgroundColor = .clear
99113
it.level = .floating
100-
it.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
114+
it.collectionBehavior = [.fullScreenAuxiliary]
101115
it.hasShadow = true
102116
it.contentView = NSHostingView(
103117
rootView: ChatWindowView(viewModel: chatWindowViewModel)
@@ -128,6 +142,7 @@ public final class SuggestionWidgetController: NSObject {
128142
private var windowChangeObservationTask: Task<Void, Error>?
129143
private var activeApplicationMonitorTask: Task<Void, Error>?
130144
private var sourceEditorMonitorTask: Task<Void, Error>?
145+
private var fullscreenDetectingTask: Task<Void, Error>?
131146
private var currentFileURL: URL?
132147
private var colorScheme: ColorScheme = .light
133148
private var cancellable = Set<AnyCancellable>()
@@ -174,6 +189,27 @@ public final class SuggestionWidgetController: NSObject {
174189
}
175190
}
176191

192+
Task { @MainActor in
193+
fullscreenDetectingTask = Task { [weak self] in
194+
let sequence = NSWorkspace.shared.notificationCenter
195+
.notifications(named: NSWorkspace.activeSpaceDidChangeNotification)
196+
_ = self?.fullscreenDetector
197+
for await _ in sequence {
198+
try Task.checkCancellation()
199+
guard let self else { return }
200+
guard let activeXcode = ActiveApplicationMonitor.activeXcode else { continue }
201+
guard fullscreenDetector.isOnActiveSpace else { continue }
202+
let app = AXUIElementCreateApplication(activeXcode.processIdentifier)
203+
if let window = app.focusedWindow, window.isFullScreen {
204+
widgetWindow.orderFrontRegardless()
205+
tabWindow.orderFrontRegardless()
206+
panelWindow.orderFrontRegardless()
207+
chatWindow.orderFrontRegardless()
208+
}
209+
}
210+
}
211+
}
212+
177213
Task { @MainActor in
178214
presentationModeChangeObserver.onChange = { [weak self] in
179215
guard let self else { return }
@@ -224,7 +260,7 @@ public final class SuggestionWidgetController: NSObject {
224260
}
225261
}
226262
}
227-
263+
228264
public func detachChat() {
229265
chatWindowViewModel.chatPanelInASeparateWindow = true
230266
}
@@ -499,16 +535,14 @@ extension SuggestionWidgetController {
499535
}
500536

501537
if let app = ActiveApplicationMonitor.activeApplication, app.isXcode {
502-
let application = AXUIElementCreateApplication(app.processIdentifier)
503-
let noFocus = application.focusedWindow == nil
504-
panelWindow.alphaValue = noFocus ? 0 : 1
505-
widgetWindow.alphaValue = noFocus ? 0 : 1
506-
tabWindow.alphaValue = noFocus ? 0 : 1
538+
panelWindow.alphaValue = 1
539+
widgetWindow.alphaValue = 1
540+
tabWindow.alphaValue = 1
507541

508542
if detachChat {
509543
chatWindow.alphaValue = chatWindowViewModel.chat != nil ? 1 : 0
510544
} else {
511-
chatWindow.alphaValue = noFocus ? 0 : 1
545+
chatWindow.alphaValue = 1
512546
}
513547
} else if let app = ActiveApplicationMonitor.activeApplication,
514548
app.bundleIdentifier == Bundle.main.bundleIdentifier

0 commit comments

Comments
 (0)