@@ -476,80 +476,32 @@ extension SuggestionWidgetController {
476476 private func updateWindowLocation( animated: Bool = false ) {
477477 let detachChat = chatWindowViewModel. chatPanelInASeparateWindow
478478
479- if let widgetFrames = {
480- if let application = XcodeInspector . shared. latestActiveXcode? . appElement {
481- if let focusElement = application. focusedElement,
482- focusElement. description == " Source Editor " ,
483- let parent = focusElement. parent,
484- let frame = parent. rect,
485- let screen = NSScreen . screens. first ( where: { $0. frame. origin == . zero } ) ,
486- let firstScreen = NSScreen . main
487- {
488- let mode = UserDefaults . shared. value ( for: \. suggestionWidgetPositionMode)
489- switch mode {
490- case . fixedToBottom:
491- return UpdateLocationStrategy . FixedToBottom ( ) . framesForWindows (
492- editorFrame: frame,
493- mainScreen: screen,
494- activeScreen: firstScreen
495- )
496- case . alignToTextCursor:
497- return UpdateLocationStrategy . AlignToTextCursor ( ) . framesForWindows (
498- editorFrame: frame,
499- mainScreen: screen,
500- activeScreen: firstScreen,
501- editor: focusElement
502- )
503- }
504- } else if var window = application. focusedWindow,
505- var frame = application. focusedWindow? . rect,
506- ![ " menu bar " , " menu bar item " ] . contains ( window. description) ,
507- frame. size. height > 300 ,
508- let screen = NSScreen . screens. first ( where: { $0. frame. origin == . zero } ) ,
509- let firstScreen = NSScreen . main
510- {
511- if [ " open_quickly " ] . contains ( window. identifier)
512- || [ " alert " ] . contains ( window. label)
513- {
514- // fallback to use workspace window
515- guard let workspaceWindow = application. windows
516- . first ( where: { $0. identifier == " Xcode.WorkspaceWindow " } ) ,
517- let rect = workspaceWindow. rect
518- else { return ( . zero, . zero, . zero, false ) }
519-
520- window = workspaceWindow
521- frame = rect
522- }
523-
524- if [ " Xcode.WorkspaceWindow " ] . contains ( window. identifier) {
525- // extra padding to bottom so buttons won't be covered
526- frame. size. height -= 40
527- } else {
528- // move a bit away from the window so buttons won't be covered
529- frame. origin. x -= Style . widgetPadding + Style. widgetWidth / 2
530- frame. size. width += Style . widgetPadding * 2 + Style. widgetWidth
531- }
532-
533- return UpdateLocationStrategy . FixedToBottom ( ) . framesForWindows (
534- editorFrame: frame,
535- mainScreen: screen,
536- activeScreen: firstScreen,
537- preferredInsideEditorMinWidth: 9_999_999_999 // never
538- )
539- }
540- }
541- return nil
542- } ( ) {
543- widgetWindow. setFrame ( widgetFrames. widgetFrame, display: false , animate: animated)
544- panelWindow. setFrame ( widgetFrames. panelFrame, display: false , animate: animated)
545- tabWindow. setFrame ( widgetFrames. tabFrame, display: false , animate: animated)
546- suggestionPanelViewModel. alignTopToAnchor = widgetFrames. alignPanelTopToAnchor
479+ if let widgetLocation = generateWidgetLocation ( ) {
480+ widgetWindow. setFrame ( widgetLocation. widgetFrame, display: false , animate: animated)
481+ tabWindow. setFrame ( widgetLocation. tabFrame, display: false , animate: animated)
482+ panelWindow. setFrame (
483+ ( widgetLocation. suggestionPanelLocation ?? widgetLocation. defaultPanelLocation)
484+ . frame,
485+ display: false ,
486+ animate: animated
487+ )
488+ suggestionPanelViewModel. alignTopToAnchor = (
489+ widgetLocation. suggestionPanelLocation ?? widgetLocation. defaultPanelLocation
490+ ) . alignPanelTop
547491 if detachChat {
548492 if chatWindow. alphaValue == 0 {
549- chatWindow. setFrame ( panelWindow. frame, display: false , animate: animated)
493+ chatWindow. setFrame (
494+ widgetLocation. defaultPanelLocation. frame,
495+ display: false ,
496+ animate: animated
497+ )
550498 }
551499 } else {
552- chatWindow. setFrame ( panelWindow. frame, display: false , animate: animated)
500+ chatWindow. setFrame (
501+ widgetLocation. defaultPanelLocation. frame,
502+ display: false ,
503+ animate: animated
504+ )
553505 }
554506 }
555507
@@ -622,8 +574,113 @@ extension SuggestionWidgetController {
622574 suggestionPanelViewModel. content = nil
623575 }
624576 }
577+
578+ private func generateWidgetLocation( ) -> WidgetLocation ? {
579+ if let application = XcodeInspector . shared. latestActiveXcode? . appElement {
580+ if let focusElement = application. focusedElement,
581+ focusElement. description == " Source Editor " ,
582+ let parent = focusElement. parent,
583+ let frame = parent. rect,
584+ let screen = NSScreen . screens. first ( where: { $0. frame. origin == . zero } ) ,
585+ let firstScreen = NSScreen . main
586+ {
587+ let positionMode = UserDefaults . shared
588+ . value ( for: \. suggestionWidgetPositionMode)
589+ let suggestionMode = UserDefaults . shared
590+ . value ( for: \. suggestionPresentationMode)
591+
592+ switch positionMode {
593+ case . fixedToBottom:
594+ var result = UpdateLocationStrategy . FixedToBottom ( ) . framesForWindows (
595+ editorFrame: frame,
596+ mainScreen: screen,
597+ activeScreen: firstScreen
598+ )
599+ switch suggestionMode {
600+ case . nearbyTextCursor:
601+ result. suggestionPanelLocation = UpdateLocationStrategy
602+ . NearbyTextCursor ( )
603+ . framesForSuggestionWindow (
604+ editorFrame: frame, mainScreen: screen,
605+ activeScreen: firstScreen,
606+ editor: focusElement,
607+ completionPanel: XcodeInspector . shared. completionPanel
608+ )
609+ default :
610+ break
611+ }
612+ return result
613+ case . alignToTextCursor:
614+ var result = UpdateLocationStrategy . AlignToTextCursor ( ) . framesForWindows (
615+ editorFrame: frame,
616+ mainScreen: screen,
617+ activeScreen: firstScreen,
618+ editor: focusElement
619+ )
620+ switch suggestionMode {
621+ case . nearbyTextCursor:
622+ result. suggestionPanelLocation = UpdateLocationStrategy
623+ . NearbyTextCursor ( )
624+ . framesForSuggestionWindow (
625+ editorFrame: frame, mainScreen: screen,
626+ activeScreen: firstScreen,
627+ editor: focusElement,
628+ completionPanel: XcodeInspector . shared. completionPanel
629+ )
630+ default :
631+ break
632+ }
633+ return result
634+ }
635+ } else if var window = application. focusedWindow,
636+ var frame = application. focusedWindow? . rect,
637+ ![ " menu bar " , " menu bar item " ] . contains ( window. description) ,
638+ frame. size. height > 300 ,
639+ let screen = NSScreen . screens. first ( where: { $0. frame. origin == . zero } ) ,
640+ let firstScreen = NSScreen . main
641+ {
642+ if [ " open_quickly " ] . contains ( window. identifier)
643+ || [ " alert " ] . contains ( window. label)
644+ {
645+ // fallback to use workspace window
646+ guard let workspaceWindow = application. windows
647+ . first ( where: { $0. identifier == " Xcode.WorkspaceWindow " } ) ,
648+ let rect = workspaceWindow. rect
649+ else {
650+ return WidgetLocation (
651+ widgetFrame: . zero,
652+ tabFrame: . zero,
653+ defaultPanelLocation: . init( frame: . zero, alignPanelTop: false )
654+ )
655+ }
656+
657+ window = workspaceWindow
658+ frame = rect
659+ }
660+
661+ if [ " Xcode.WorkspaceWindow " ] . contains ( window. identifier) {
662+ // extra padding to bottom so buttons won't be covered
663+ frame. size. height -= 40
664+ } else {
665+ // move a bit away from the window so buttons won't be covered
666+ frame. origin. x -= Style . widgetPadding + Style. widgetWidth / 2
667+ frame. size. width += Style . widgetPadding * 2 + Style. widgetWidth
668+ }
669+
670+ return UpdateLocationStrategy . FixedToBottom ( ) . framesForWindows (
671+ editorFrame: frame,
672+ mainScreen: screen,
673+ activeScreen: firstScreen,
674+ preferredInsideEditorMinWidth: 9_999_999_999 // never
675+ )
676+ }
677+ }
678+ return nil
679+ }
625680}
626681
682+ // MARK: - NSWindowDelegate
683+
627684extension SuggestionWidgetController : NSWindowDelegate {
628685 public func windowWillMove( _ notification: Notification ) {
629686 guard ( notification. object as? NSWindow ) === chatWindow else { return }
@@ -659,6 +716,8 @@ extension SuggestionWidgetController: NSWindowDelegate {
659716 }
660717}
661718
719+ // MARK: - Window Subclasses
720+
662721class CanBecomeKeyWindow : NSWindow {
663722 var canBecomeKeyChecker : ( ) -> Bool = { true }
664723 override var canBecomeKey : Bool { canBecomeKeyChecker ( ) }
0 commit comments