Skip to content

Commit 9d4be4b

Browse files
committed
Treat emacs child frames as popups
Emacs has a concept of "child frames", which are effectively transient UI elements. These should not be managed by Aerospace. These child frames are now detected by checking for an AXSubrole of AXFloatingWindow, and AXMain with value 0 for the emacs bundle ID. Closes #776
1 parent 85f80bd commit 9d4be4b

File tree

4 files changed

+241
-0
lines changed

4 files changed

+241
-0
lines changed

Sources/AppBundle/model/AxUiElementWindowType.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,16 @@ extension AxUiElementMock {
133133
return false
134134
}
135135

136+
// Emacs child frames (posframes, corfu completion popups, etc.)
137+
// These are transient UI elements that should not be managed as windows.
138+
// https://github.com/nikitabobko/AeroSpace/issues/776
139+
if id == .emacs &&
140+
get(Ax.subroleAttr) == kAXFloatingWindowSubrole &&
141+
get(Ax.isMainAttr) == false
142+
{
143+
return false
144+
}
145+
136146
if id?.isFirefox != true {
137147
return isWindowHeuristicOld(axApp: axApp, id)
138148
}

axDumps/emacs.json5

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
{
2+
"AXActivationPoint" : "<AXValue 0xc70311e90> {value = x:75.000000 y:58.000000 type = kAXValueCGPointType}",
3+
"AXCancelButton" : null,
4+
"AXCloseButton" : {
5+
"AXEnabled" : 1,
6+
"AXParent" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
7+
"AXRole" : "AXButton",
8+
"AXSubrole" : "AXCloseButton",
9+
"AXTitle" : null,
10+
"AXTopLevelUIElement" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
11+
"AXWindow" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
12+
"Aero.AxFailed" : "get.AXTitle(noValue)",
13+
"Aero.AxIgnored" : "AXFrame, AXSize, AXFocused, AXHelp, AXPosition, AXRoleDescription, AXEdited"
14+
},
15+
"AXDefaultButton" : null,
16+
"AXDocument" : null,
17+
"AXFocused" : 1,
18+
"AXFrame" : "<AXValue 0xc702753c0> {value = x:5.000000 y:44.000000 w:893.000000 h:1119.000000 type = kAXValueCGRectType}",
19+
"AXFullScreen" : 0,
20+
"AXFullScreenButton" : {
21+
"AXEnabled" : 1,
22+
"AXParent" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
23+
"AXRole" : "AXButton",
24+
"AXSubrole" : "AXFullScreenButton",
25+
"AXTitle" : null,
26+
"AXTopLevelUIElement" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
27+
"AXWindow" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
28+
"Aero.AxFailed" : "get.AXTitle(noValue)",
29+
"Aero.AxIgnored" : "AXFrame, AXSize, AXFocused, AXChildren, AXHelp, AXPosition, AXRoleDescription"
30+
},
31+
"AXGrowArea" : null,
32+
"AXMain" : 1,
33+
"AXMinimizeButton" : {
34+
"AXEnabled" : 1,
35+
"AXParent" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
36+
"AXRole" : "AXButton",
37+
"AXSubrole" : "AXMinimizeButton",
38+
"AXTitle" : null,
39+
"AXTopLevelUIElement" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
40+
"AXWindow" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
41+
"Aero.AxFailed" : "get.AXTitle(noValue)",
42+
"Aero.AxIgnored" : "AXFrame, AXSize, AXFocused, AXHelp, AXPosition, AXRoleDescription"
43+
},
44+
"AXMinimized" : 0,
45+
"AXModal" : 0,
46+
"AXParent" : "<AXUIElement Application 0xc6f7778a0> {pid=6999}",
47+
"AXPosition" : "<AXValue 0xc70312250> {value = x:5.000000 y:44.000000 type = kAXValueCGPointType}",
48+
"AXProxy" : null,
49+
"AXRole" : "AXWindow",
50+
"AXSections" : [
51+
"{\n SectionDescription = Content;\n SectionObject = \"<AXUIElement 0xc6f7778a0> {pid=6999}\";\n SectionUniqueID = AXContent;\n}"
52+
],
53+
"AXSize" : "<AXValue 0xc70312190> {value = w:893.000000 h:1119.000000 type = kAXValueCGSizeType}",
54+
"AXSubrole" : "AXStandardWindow",
55+
"AXTitle" : "*doom* – Doom Emacs — (109 × 67)",
56+
"AXTitleUIElement" : "AXUIElement(AxWindowId=86039, title=nil, role=\"AXStaticText\", subrole=nil)",
57+
"AXToolbarButton" : null,
58+
"AXZoomButton" : {
59+
"AXEnabled" : 1,
60+
"AXParent" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
61+
"AXRole" : "AXButton",
62+
"AXSubrole" : "AXFullScreenButton",
63+
"AXTitle" : null,
64+
"AXTopLevelUIElement" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
65+
"AXWindow" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
66+
"Aero.AxFailed" : "get.AXTitle(noValue)",
67+
"Aero.AxIgnored" : "AXFrame, AXSize, AXFocused, AXChildren, AXHelp, AXPosition, AXRoleDescription"
68+
},
69+
"Aero.AXApp" : {
70+
"AXExtrasMenuBar" : null,
71+
"AXFocusedUIElement" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
72+
"AXFocusedWindow" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
73+
"AXFrame" : null,
74+
"AXFrontmost" : 1,
75+
"AXFunctionRowTopLevelElements" : [
76+
77+
],
78+
"AXMainWindow" : "AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
79+
"AXMenuBar" : "<AXUIElement 0xc6f7778a0> {pid=6999}",
80+
"AXPosition" : null,
81+
"AXRole" : "AXApplication",
82+
"AXSize" : null,
83+
"AXTitle" : "Emacs",
84+
"AXWindows" : [
85+
"AXUIElement(AxWindowId=86039, title=\"*doom* – Doom Emacs — (109 × 67)\", role=\"AXWindow\", subrole=\"AXStandardWindow\")"
86+
],
87+
"Aero.AxFailed" : "isWritable.AXFunctionRowTopLevelElements(failure), get.AXFrame(attributeUnsupported), isWritable.AXFrame(failure), get.AXExtrasMenuBar(noValue), isWritable.AXExtrasMenuBar(failure), get.AXSize(attributeUnsupported), isWritable.AXSize(attributeUnsupported), get.AXPosition(attributeUnsupported), isWritable.AXPosition(attributeUnsupported)",
88+
"Aero.AxIgnored" : "AXChildren, AXChildrenInNavigationOrder, AXEnhancedUserInterface, AXPreferredLanguage, AXRoleDescription, AXHidden",
89+
"Aero.AxWritable" : "AXFrontmost"
90+
},
91+
"Aero.App.appBundleId" : "org.gnu.Emacs",
92+
"Aero.App.nsApp.activationPolicy" : "regular",
93+
"Aero.App.nsApp.appBundlePath" : "file:///opt/homebrew/Cellar/emacs-plus@30/30.2/Emacs.app/",
94+
"Aero.App.nsApp.execPath" : "file:///opt/homebrew/Cellar/emacs-plus@30/30.2/Emacs.app/Contents/MacOS/Emacs-real",
95+
"Aero.App.pid" : 6999,
96+
"Aero.App.version" : "9.0",
97+
"Aero.App.versionShort" : "30.2",
98+
"Aero.AxFailed" : "isWritable.AXFrame(failure), get.AXGrowArea(failure), get.AXDocument(noValue), isWritable.AXActivationPoint(failure), get.AXProxy(noValue), get.AXDefaultButton(noValue), get.AXCancelButton(noValue), get.AXToolbarButton(noValue)",
99+
"Aero.AxIgnored" : "AXChildrenInNavigationOrder, AXChildren, AXRoleDescription",
100+
"Aero.AxUiElementWindowType" : "window",
101+
"Aero.AxUiElementWindowType_isDialogHeuristic" : false,
102+
"Aero.AxWritable" : "AXFullScreen, AXPosition, AXSections, AXMain, AXMinimized, AXSize",
103+
"Aero.axWindowId" : 86039,
104+
"Aero.macOS.version" : "Version 26.2 (Build 25C56)",
105+
"Aero.on-window-detected" : [
106+
107+
],
108+
"Aero.treeNodeParent" : "Optional(AppBundle.TilingContainer)",
109+
"Aero.windowLevel" : "normalWindow",
110+
"Aero.workspace" : "1"
111+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// (enable/configure corfu) -> start typing -> select corfu completion candidate...
2+
{
3+
"AXActivationPoint" : "<AXValue 0x88dc9a940> {value = x:-1.000000 y:1801.000000 type = kAXValueCGPointType}",
4+
"AXCancelButton" : null,
5+
"AXCloseButton" : null,
6+
"AXDefaultButton" : null,
7+
"AXDocument" : null,
8+
"AXFocused" : 0,
9+
"AXFrame" : "<AXValue 0x88c4e4240> {value = x:1518.000000 y:920.000000 w:270.000000 h:242.000000 type = kAXValueCGRectType}",
10+
"AXFullScreen" : 0,
11+
"AXFullScreenButton" : null,
12+
"AXGrowArea" : null,
13+
"AXMain" : 0,
14+
"AXMinimizeButton" : null,
15+
"AXMinimized" : 0,
16+
"AXModal" : 0,
17+
"AXParent" : "<AXUIElement Application 0x88c445200> {pid=39373}",
18+
"AXPosition" : "<AXValue 0x88e0084b0> {value = x:1518.000000 y:920.000000 type = kAXValueCGPointType}",
19+
"AXProxy" : null,
20+
"AXRole" : "AXWindow",
21+
"AXSections" : [],
22+
"AXSize" : "<AXValue 0x88dc9b4e0> {value = w:270.000000 h:242.000000 type = kAXValueCGSizeType}",
23+
"AXSubrole" : "AXFloatingWindow",
24+
"AXTitle" : "EmacsCorfuGUI",
25+
"AXTitleUIElement" : null,
26+
"AXToolbarButton" : null,
27+
"AXZoomButton" : null,
28+
"Aero.AXApp" : {
29+
"AXExtrasMenuBar" : null,
30+
"AXFocusedUIElement" : "AXUIElement(AxWindowId=78408, title=\"test.py – Doom Emacs\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
31+
"AXFocusedWindow" : "AXUIElement(AxWindowId=78408, title=\"test.py – Doom Emacs\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
32+
"AXFrame" : null,
33+
"AXFrontmost" : 1,
34+
"AXFunctionRowTopLevelElements" : [],
35+
"AXMainWindow" : "AXUIElement(AxWindowId=78408, title=\"test.py – Doom Emacs\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
36+
"AXMenuBar" : "<AXUIElement 0x88c445200> {pid=39373}",
37+
"AXPosition" : null,
38+
"AXRole" : "AXApplication",
39+
"AXSize" : null,
40+
"AXTitle" : "Emacs",
41+
"AXWindows" : [
42+
"AXUIElement(AxWindowId=78635, title=\"EmacsCorfuGUI\", role=\"AXWindow\", subrole=\"AXFloatingWindow\")",
43+
"AXUIElement(AxWindowId=78408, title=\"test.py – Doom Emacs\", role=\"AXWindow\", subrole=\"AXStandardWindow\")"
44+
],
45+
"Aero.AxIgnored" : "AXChildren, AXChildrenInNavigationOrder, AXEnhancedUserInterface, AXPreferredLanguage, AXRoleDescription, AXHidden"
46+
},
47+
"Aero.App.appBundleId" : "org.gnu.Emacs",
48+
"Aero.App.nsApp.activationPolicy" : "regular",
49+
"Aero.App.nsApp.execPath" : "file:///opt/homebrew/Cellar/emacs-plus@30/30.2/Emacs.app/Contents/MacOS/Emacs-real",
50+
"Aero.App.version" : "9.0",
51+
"Aero.App.versionShort" : "30.2",
52+
"Aero.AxIgnored" : "AXChildrenInNavigationOrder, AXChildren, AXRoleDescription",
53+
"Aero.axWindowId" : 78635,
54+
"Aero.AxUiElementWindowType_isDialogHeuristic" : true,
55+
"Aero.AxUiElementWindowType" : "popup",
56+
"Aero.on-window-detected" : [],
57+
"Aero.treeNodeParent" : "AppBundle.Workspace",
58+
"Aero.windowLevel" : "normalWindow",
59+
"Aero.workspace" : "1"
60+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// (enable/configure flycheck-posframe) -> provoke syntax error -> select flycheck-posframe error list candidate...
2+
{
3+
"AXActivationPoint" : "<AXValue 0x88dc9b4e0> {value = x:-1.000000 y:1801.000000 type = kAXValueCGPointType}",
4+
"AXCancelButton" : null,
5+
"AXCloseButton" : null,
6+
"AXDefaultButton" : null,
7+
"AXDocument" : null,
8+
"AXFocused" : 0,
9+
"AXFrame" : "<AXValue 0x88c4e5900> {value = x:1607.000000 y:873.000000 w:490.000000 h:32.000000 type = kAXValueCGRectType}",
10+
"AXFullScreen" : 0,
11+
"AXFullScreenButton" : null,
12+
"AXGrowArea" : null,
13+
"AXMain" : 0,
14+
"AXMinimizeButton" : null,
15+
"AXMinimized" : 0,
16+
"AXModal" : 0,
17+
"AXParent" : "<AXUIElement Application 0x88c447570> {pid=39373}",
18+
"AXPosition" : "<AXValue 0x88dc9bcf0> {value = x:1607.000000 y:873.000000 type = kAXValueCGPointType}",
19+
"AXProxy" : null,
20+
"AXRole" : "AXWindow",
21+
"AXSections" : [],
22+
"AXSize" : "<AXValue 0x88dc9bab0> {value = w:490.000000 h:32.000000 type = kAXValueCGSizeType}",
23+
"AXSubrole" : "AXFloatingWindow",
24+
"AXTitle" : "posframe",
25+
"AXTitleUIElement" : null,
26+
"AXToolbarButton" : null,
27+
"AXZoomButton" : null,
28+
"Aero.AXApp" : {
29+
"AXExtrasMenuBar" : null,
30+
"AXFocusedUIElement" : "AXUIElement(AxWindowId=78408, title=\"test.py – Doom Emacs\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
31+
"AXFocusedWindow" : "AXUIElement(AxWindowId=78408, title=\"test.py – Doom Emacs\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
32+
"AXFrame" : null,
33+
"AXFrontmost" : 0,
34+
"AXFunctionRowTopLevelElements" : [],
35+
"AXMainWindow" : "AXUIElement(AxWindowId=78408, title=\"test.py – Doom Emacs\", role=\"AXWindow\", subrole=\"AXStandardWindow\")",
36+
"AXMenuBar" : "<AXUIElement 0x88c447570> {pid=39373}",
37+
"AXPosition" : null,
38+
"AXRole" : "AXApplication",
39+
"AXSize" : null,
40+
"AXTitle" : "Emacs",
41+
"AXWindows" : [
42+
"AXUIElement(AxWindowId=78636, title=\"posframe\", role=\"AXWindow\", subrole=\"AXFloatingWindow\")",
43+
"AXUIElement(AxWindowId=78408, title=\"test.py – Doom Emacs\", role=\"AXWindow\", subrole=\"AXStandardWindow\")"
44+
],
45+
"Aero.AxIgnored" : "AXChildren, AXChildrenInNavigationOrder, AXEnhancedUserInterface, AXPreferredLanguage, AXRoleDescription, AXHidden"
46+
},
47+
"Aero.App.appBundleId" : "org.gnu.Emacs",
48+
"Aero.App.nsApp.activationPolicy" : "regular",
49+
"Aero.App.nsApp.execPath" : "file:///opt/homebrew/Cellar/emacs-plus@30/30.2/Emacs.app/Contents/MacOS/Emacs-real",
50+
"Aero.App.version" : "9.0",
51+
"Aero.App.versionShort" : "30.2",
52+
"Aero.AxIgnored" : "AXChildrenInNavigationOrder, AXChildren, AXRoleDescription",
53+
"Aero.axWindowId" : 78636,
54+
"Aero.AxUiElementWindowType_isDialogHeuristic" : true,
55+
"Aero.AxUiElementWindowType" : "popup",
56+
"Aero.on-window-detected" : [],
57+
"Aero.treeNodeParent" : "AppBundle.Workspace",
58+
"Aero.windowLevel" : "normalWindow",
59+
"Aero.workspace" : "1"
60+
}

0 commit comments

Comments
 (0)