@@ -211,6 +211,45 @@ final class MacWindow: Window, CustomStringConvertible {
211211}
212212
213213/// Alternative name: !isPopup
214+ ///
215+ /// Why do we need to filter out non-windows?
216+ /// - "floating by default" workflow
217+ /// - It's annoying that the focus command treats these popups as floating windows
218+ private func isWindowNew( _ axWindow: AXUIElement , _ app: MacApp ) -> Bool {
219+ // Just don't do anything with "Ghostty Quick Terminal" windows.
220+ // Its position and size are managed by the Ghostty itself
221+ // https://github.com/nikitabobko/AeroSpace/issues/103
222+ // https://github.com/ghostty-org/ghostty/discussions/3512
223+ if app. id == " com.mitchellh.ghostty " && axWindow. get ( Ax . identifierAttr) == " com.mitchellh.ghostty.quickTerminal " {
224+ return false
225+ }
226+
227+ // Try to filter out incredibly weird popup like AXWindows without any buttons.
228+ // E.g.
229+ // - Sonoma (macOS 14) keyboard layout switch (AXSubrole == AXDialog)
230+ // - IntelliJ context menu (right mouse click)
231+ // - Telegram context menu (right mouse click)
232+ // - Share window purple "pill" indicator https://github.com/nikitabobko/AeroSpace/issues/1101. Title is not empty
233+ // - Tooltips on links mouse hover in browsers (Chrome, Firefox)
234+ // - Tooltips on buttons (e.g. new tab, Extensions) mouse hover in browsers (Chrome, Firefox). Title is not empty
235+ // Make sure that the following AXWindow remain windows:
236+ // - macOS native file picker ("Open..." menu) (subrole == kAXDialogSubrole)
237+ // - telegram image viewer (subrole == kAXFloatingWindowSubrole)
238+ // - Finder preview (hit space) (subrole == "Quick Look")
239+ // - Firefox non-native video fullscreen (about:config -> full-screen-api.macos-native-full-screen -> false, subrole == AXUnknown)
240+ return axWindow. get ( Ax . closeButtonAttr) != nil ||
241+ axWindow. get ( Ax . fullscreenButtonAttr) != nil ||
242+ axWindow. get ( Ax . zoomButtonAttr) != nil ||
243+ axWindow. get ( Ax . minimizeButtonAttr) != nil ||
244+
245+ axWindow. get ( Ax . isFocused) == true || // 3 different ways to detect if the window is focused
246+ axWindow. get ( Ax . isMainAttr) == true ||
247+ app. getFocusedAxWindow ( ) ? . containingWindowId ( ) == axWindow. containingWindowId ( ) ||
248+
249+ axWindow. get ( Ax . subroleAttr) == kAXStandardWindowSubrole
250+ }
251+
252+ /// Compatibility. Replace isWindow -> isWindowNew in 0.18.0
214253func isWindow( _ axWindow: AXUIElement , _ app: MacApp ) -> Bool {
215254 let subrole = axWindow. get ( Ax . subroleAttr)
216255
@@ -222,6 +261,10 @@ func isWindow(_ axWindow: AXUIElement, _ app: MacApp) -> Bool {
222261 return false
223262 }
224263
264+ if app. id == " org.mozilla.firefox " {
265+ return isWindowNew ( axWindow, app)
266+ }
267+
225268 lazy var title = axWindow. get ( Ax . titleAttr) ?? " "
226269
227270 // Try to filter out incredibly weird popup like AXWindows without any buttons.
@@ -247,11 +290,7 @@ func isWindow(_ axWindow: AXUIElement, _ app: MacApp) -> Bool {
247290 return subrole == kAXStandardWindowSubrole ||
248291 subrole == kAXDialogSubrole || // macOS native file picker ("Open..." menu) (kAXDialogSubrole value)
249292 subrole == kAXFloatingWindowSubrole || // telegram image viewer
250- app. id == " com.apple.finder " && subrole == " Quick Look " || // Finder preview (hit space) is a floating window
251-
252- // Firefox non-native video fullscreen
253- // about:config -> full-screen-api.macos-native-full-screen -> false
254- app. id == " org.mozilla.firefox " && subrole == kAXUnknownSubrole
293+ app. id == " com.apple.finder " && subrole == " Quick Look " // Finder preview (hit space) is a floating window
255294}
256295
257296// This function is referenced in the guide
0 commit comments