Skip to content

Commit 6f8f92a

Browse files
committed
Add CI: Linux parse-check + macOS build matrix
* .github/workflows/build.yml runs on every push/PR. - swift-parse: Linux job. Installs Swift 6.0.3 and runs `swiftc -parse -enable-bare-slash-regex` on every .swift file in Ice / MenuBarItemService / Shared. Catches raw syntax errors cheaply on free runners before we burn macOS minutes. - build: matrix over macos-26 (has the macOS 26 SDK and Xcode 26) and macos-15 (sanity check that we haven't quietly leaked a macOS 26-only API into an unguarded code path). Both build the Ice and MenuBarItemService schemes in Debug with code signing fully disabled, since we don't have Jordan's team identifier on CI runners. Logs uploaded as artifacts on every run, errors grepped out and surfaced in the job output. * HIDEventManager.isMouseInsideEmptyMenuBarSpace now also rejects "an overlay whose level is above the menu bar at the cursor". This is AlexandrosAlexiou's PR jordanbaird#933, ported to the current codebase (the file was renamed EventManager -> HIDEventManager and the helper namespace MouseCursor -> MouseHelpers in the macos-26 branch refactor; the WindowInfo helper for getting on-screen windows is also named differently here). Without it, show-on-click toggles a section when the click was meant for a third-party HUD/notification overlay drawn above the menu bar.
1 parent 5c09ad6 commit 6f8f92a

2 files changed

Lines changed: 171 additions & 1 deletion

File tree

.github/workflows/build.yml

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
name: Build
2+
3+
on:
4+
push:
5+
branches: ["**"]
6+
paths:
7+
- "**/*.swift"
8+
- "**/*.xcconfig"
9+
- "**/*.entitlements"
10+
- "**/*.xcodeproj/**"
11+
- "**/Resources/**"
12+
- "Package.resolved"
13+
- ".github/workflows/build.yml"
14+
pull_request:
15+
paths:
16+
- "**/*.swift"
17+
- "**/*.xcconfig"
18+
- "**/*.entitlements"
19+
- "**/*.xcodeproj/**"
20+
- "**/Resources/**"
21+
- "Package.resolved"
22+
- ".github/workflows/build.yml"
23+
workflow_dispatch:
24+
25+
concurrency:
26+
group: build-${{ github.ref }}
27+
cancel-in-progress: true
28+
29+
jobs:
30+
# Linux-side smoke test. Cheap, runs on free runners, catches raw
31+
# syntax errors before we burn macOS-runner minutes on them.
32+
swift-parse:
33+
name: Swift parse (Linux)
34+
runs-on: ubuntu-24.04
35+
steps:
36+
- uses: actions/checkout@v4
37+
38+
- name: Install Swift 6.0.3
39+
run: |
40+
set -e
41+
mkdir -p $HOME/swift
42+
cd $HOME/swift
43+
curl -sLO https://download.swift.org/swift-6.0.3-release/ubuntu2404/swift-6.0.3-RELEASE/swift-6.0.3-RELEASE-ubuntu24.04.tar.gz
44+
tar xzf swift-6.0.3-RELEASE-ubuntu24.04.tar.gz
45+
rm swift-6.0.3-RELEASE-ubuntu24.04.tar.gz
46+
echo "$HOME/swift/swift-6.0.3-RELEASE-ubuntu24.04/usr/bin" >> $GITHUB_PATH
47+
48+
- name: Parse-check every Swift file
49+
run: |
50+
set -e
51+
fails=0
52+
while IFS= read -r f; do
53+
output=$(swiftc -parse -enable-bare-slash-regex "$f" 2>&1) || {
54+
fails=$((fails + 1))
55+
echo "::error file=$f::$output"
56+
}
57+
done < <(find Ice MenuBarItemService Shared -name '*.swift')
58+
if [ "$fails" -ne 0 ]; then
59+
echo "$fails files failed parse-check"
60+
exit 1
61+
fi
62+
echo "All Swift files parse cleanly."
63+
64+
build:
65+
name: Build (${{ matrix.runner }})
66+
needs: swift-parse
67+
strategy:
68+
fail-fast: false
69+
matrix:
70+
# macos-26 has the macOS 26 SDK so `@available(macOS 26.0, *)`
71+
# branches actually compile. macos-15 is a sanity check — if a
72+
# macOS 26-only API leaks into an unguarded code path, this is
73+
# what catches it.
74+
runner: [macos-26, macos-15]
75+
runs-on: ${{ matrix.runner }}
76+
steps:
77+
- name: Check out source
78+
uses: actions/checkout@v4
79+
80+
- name: Show toolchain
81+
run: |
82+
ls /Applications | grep -i Xcode || true
83+
xcode-select -p
84+
xcodebuild -version
85+
swift --version
86+
87+
- name: Resolve Swift package dependencies
88+
run: |
89+
xcodebuild \
90+
-resolvePackageDependencies \
91+
-project Ice.xcodeproj \
92+
-scheme Ice
93+
94+
- name: Build Ice (Debug, no signing)
95+
run: |
96+
set -o pipefail
97+
xcodebuild build \
98+
-project Ice.xcodeproj \
99+
-scheme Ice \
100+
-configuration Debug \
101+
-destination 'generic/platform=macOS' \
102+
-skipPackagePluginValidation \
103+
-skipMacroValidation \
104+
CODE_SIGN_IDENTITY="-" \
105+
CODE_SIGNING_REQUIRED=NO \
106+
CODE_SIGNING_ALLOWED=NO \
107+
DEVELOPMENT_TEAM="" \
108+
CODE_SIGN_ENTITLEMENTS="" \
109+
ONLY_ACTIVE_ARCH=NO \
110+
2>&1 | tee xcodebuild-ice.log
111+
112+
- name: Build MenuBarItemService (Debug, no signing)
113+
run: |
114+
set -o pipefail
115+
xcodebuild build \
116+
-project Ice.xcodeproj \
117+
-scheme MenuBarItemService \
118+
-configuration Debug \
119+
-destination 'generic/platform=macOS' \
120+
-skipPackagePluginValidation \
121+
-skipMacroValidation \
122+
CODE_SIGN_IDENTITY="-" \
123+
CODE_SIGNING_REQUIRED=NO \
124+
CODE_SIGNING_ALLOWED=NO \
125+
DEVELOPMENT_TEAM="" \
126+
CODE_SIGN_ENTITLEMENTS="" \
127+
ONLY_ACTIVE_ARCH=NO \
128+
2>&1 | tee xcodebuild-mbis.log
129+
130+
- name: Surface compiler errors
131+
if: always()
132+
run: |
133+
# Pull error-only lines out of the full xcodebuild output so the
134+
# GitHub UI surfaces them as failures even when the log is huge.
135+
grep -E ': (error|warning): ' xcodebuild-ice.log xcodebuild-mbis.log || true
136+
137+
- name: Upload build logs
138+
if: always()
139+
uses: actions/upload-artifact@v4
140+
with:
141+
name: build-logs-${{ matrix.runner }}
142+
path: |
143+
xcodebuild-ice.log
144+
xcodebuild-mbis.log
145+
if-no-files-found: ignore
146+
retention-days: 7

Ice/Events/HIDEventManager.swift

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,13 +518,37 @@ extension HIDEventManager {
518518
return frameOfNotch.contains(mouseLocation)
519519
}
520520

521+
/// A Boolean value that indicates whether the mouse pointer is occluded
522+
/// by a third-party window whose level is above the menu bar.
523+
///
524+
/// Some apps draw HUD-style overlays above the menu bar (notification
525+
/// pill replacements, screen-recording indicators, etc.). When the user
526+
/// clicks the overlay's UI, `isMouseInsideEmptyMenuBarSpace` would
527+
/// previously return `true` and Ice would toggle a section even though
528+
/// the click was meant for the overlay.
529+
func isMouseInsideOverlayAboveMenuBar(appState: AppState) -> Bool {
530+
guard let mouseLocation = MouseHelpers.locationCoreGraphics else {
531+
return false
532+
}
533+
let icePID = ProcessInfo.processInfo.processIdentifier
534+
let menuBarLevel = Int(CGWindowLevelForKey(.mainMenuWindow))
535+
let cursorLevel = Int(CGWindowLevelForKey(.cursorWindow))
536+
return WindowInfo.createWindows(option: .onScreen).contains { window in
537+
window.ownerPID != icePID &&
538+
window.layer > menuBarLevel &&
539+
window.layer < cursorLevel &&
540+
window.bounds.contains(mouseLocation)
541+
}
542+
}
543+
521544
/// A Boolean value that indicates whether the mouse pointer is within
522545
/// the bounds of an empty space in the menu bar.
523546
func isMouseInsideEmptyMenuBarSpace(appState: AppState, screen: NSScreen) -> Bool {
524547
isMouseInsideMenuBar(appState: appState, screen: screen) &&
525548
!isMouseInsideApplicationMenu(appState: appState, screen: screen) &&
526549
!isMouseInsideMenuBarItem(appState: appState, screen: screen) &&
527-
!isMouseInsideNotch(appState: appState, screen: screen)
550+
!isMouseInsideNotch(appState: appState, screen: screen) &&
551+
!isMouseInsideOverlayAboveMenuBar(appState: appState)
528552
}
529553

530554
/// A Boolean value that indicates whether the mouse pointer is within

0 commit comments

Comments
 (0)