mirror of
https://github.com/mmacierzanka/second-display.git
synced 2026-11-05 04:31:46 +01:00
Replace build.sh with Makefile; add Info.plist, entitlements, hardened runtime, make check
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3885a04560
commit
00fa7f9546
8 files changed
+116
-32
No files matched your search
+1
-1
@@ -1,2 +1,2 @@
|
||||
SecondDisplay.app/
|
||||
build/
|
||||
.DS_Store
|
||||
@@ -13,12 +13,13 @@ Aplikacja natywna na macOS, która wyświetla w oknie obraz z urządzenia przech
|
||||
|
||||
## Struktura
|
||||
- `Sources/main.swift` – cała aplikacja (AppKit + AVFoundation, jedna sesja `AVCaptureSession`, dźwięk przez `AVCaptureAudioPreviewOutput`).
|
||||
- `Resources/{en,pl}.lproj` – `Localizable.strings` i `InfoPlist.strings`.
|
||||
- `Resources/AppIcon.icon` – ikona w formacie Icon Composer (Liquid Glass; otwórz w Icon Composer, warstwy SVG w `Assets/`); `build.sh` kompiluje ją przez `actool`.
|
||||
- `Resources/uninstall.sh` – kopiowany do bundla (`Contents/Resources/uninstall.sh`); usuwa aplikację, preferencje, cache, uprawnienia TCC. Bundle ID: `com.mmacierzanka.seconddisplay`.
|
||||
- `build.sh` – buduje i podpisuje (ad-hoc) `SecondDisplay.app`; uruchom `./build.sh`, potem `open SecondDisplay.app`.
|
||||
- `Config/Info.plist`, `Config/SecondDisplay.entitlements` – wersja, uprawnienia (kamera, mikrofon; hardened runtime).
|
||||
- `Resources/` – `AppIcon.icon` (Icon Composer, Liquid Glass; kompilowana przez `actool`), `{en,pl}.lproj` (`Localizable.strings`, `InfoPlist.strings`), `uninstall.sh` (kopiowany do bundla; usuwa aplikację, preferencje, cache, uprawnienia TCC). Bundle ID: `com.mmacierzanka.seconddisplay`.
|
||||
- `scripts/check-strings.sh` – spójność tłumaczeń en/pl.
|
||||
- `Makefile` – `make` (build do `build/SecondDisplay.app`), `run`, `check`, `install`, `uninstall`, `clean`, `help`. `SIGN_ID` domyślnie ad-hoc (`-`).
|
||||
|
||||
## Konwencje
|
||||
- Ustawienia w `UserDefaults` (klucze: `video`, `audio`, `keepAwake`, `startFull`, `onTop`, `gravity`, `format.<id>`).
|
||||
- Nowe napisy dodawaj przez `NSLocalizedString` oraz do obu plików `Localizable.strings`.
|
||||
- Przed commitem: `make check`. Wersja w `Config/Info.plist`, numer buildu = liczba commitów.
|
||||
- Commity: małe, osobne na funkcję, z linią `Co-Authored-By`.
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key><string>en</string>
|
||||
<key>CFBundleLocalizations</key><array><string>en</string><string>pl</string></array>
|
||||
<key>CFBundleExecutable</key><string>SecondDisplay</string>
|
||||
<key>CFBundleIdentifier</key><string>com.mmacierzanka.seconddisplay</string>
|
||||
<key>CFBundleName</key><string>Second Display</string>
|
||||
<key>CFBundlePackageType</key><string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key><string>0.1.0</string>
|
||||
<key>CFBundleVersion</key><string>1</string>
|
||||
<key>CFBundleIconFile</key><string>AppIcon</string>
|
||||
<key>CFBundleIconName</key><string>AppIcon</string>
|
||||
<key>LSMinimumSystemVersion</key><string>26.0</string>
|
||||
<key>LSApplicationCategoryType</key><string>public.app-category.video</string>
|
||||
<key>NSHumanReadableCopyright</key><string>Copyright © 2026 mmacierzanka</string>
|
||||
<key>NSPrincipalClass</key><string>NSApplication</string>
|
||||
<key>NSCameraUsageDescription</key><string>Shows video from the capture device.</string>
|
||||
<key>NSMicrophoneUsageDescription</key><string>Plays audio from the selected input.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.device.camera</key><true/>
|
||||
<key>com.apple.security.device.audio-input</key><true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,40 @@
|
||||
APP := build/SecondDisplay.app
|
||||
SRC := $(wildcard Sources/*.swift)
|
||||
RES := $(shell find Resources -type f)
|
||||
# "-" = ad-hoc; set SIGN_ID to a Developer ID identity for distribution
|
||||
SIGN_ID ?= -
|
||||
BUILDNUM := $(shell git rev-list --count HEAD 2>/dev/null || echo 1)
|
||||
|
||||
.PHONY: build run clean install uninstall check help
|
||||
build: $(APP) ## Build build/SecondDisplay.app
|
||||
|
||||
$(APP): Makefile $(SRC) $(RES) Config/Info.plist Config/SecondDisplay.entitlements
|
||||
rm -rf $(APP) && mkdir -p $(APP)/Contents/MacOS $(APP)/Contents/Resources
|
||||
swiftc -O $(SRC) -o $(APP)/Contents/MacOS/SecondDisplay
|
||||
cp Config/Info.plist $(APP)/Contents/Info.plist
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $(BUILDNUM)" $(APP)/Contents/Info.plist
|
||||
cp -R Resources/en.lproj Resources/pl.lproj Resources/uninstall.sh $(APP)/Contents/Resources/
|
||||
xcrun actool Resources/AppIcon.icon --compile $(APP)/Contents/Resources --platform macosx \
|
||||
--minimum-deployment-target 26.0 --app-icon AppIcon --output-partial-info-plist /dev/null >/dev/null
|
||||
codesign --force --options runtime --entitlements Config/SecondDisplay.entitlements --sign "$(SIGN_ID)" $(APP)
|
||||
|
||||
run: build ## Build and launch
|
||||
open $(APP)
|
||||
|
||||
clean: ## Remove build output
|
||||
rm -rf build
|
||||
|
||||
install: build ## Copy to ~/Applications
|
||||
mkdir -p ~/Applications && rm -rf ~/Applications/SecondDisplay.app && cp -R $(APP) ~/Applications/
|
||||
|
||||
uninstall: ## Remove the installed app and all its leftovers
|
||||
~/Applications/SecondDisplay.app/Contents/Resources/uninstall.sh
|
||||
|
||||
check: build ## Lint sources, plists, strings and the built bundle
|
||||
swiftc -typecheck $(SRC)
|
||||
plutil -lint Config/Info.plist Config/SecondDisplay.entitlements Resources/*.lproj/*.strings
|
||||
scripts/check-strings.sh
|
||||
codesign --verify --strict $(APP)
|
||||
|
||||
help: ## List targets
|
||||
@grep -E '^[a-z]+:.*##' Makefile | sed 's/:.*##/ -/'
|
||||
@@ -0,0 +1,29 @@
|
||||
# Second Display
|
||||
|
||||
Natywna aplikacja macOS, która pokazuje w oknie obraz z urządzenia przechwytującego (capture card, kamerka) i odtwarza dźwięk z wybranego wejścia — jako "drugi monitor".
|
||||
|
||||
## Wymagania
|
||||
macOS 26+, Xcode (Command Line Tools).
|
||||
|
||||
## Budowanie i uruchamianie
|
||||
```
|
||||
make # buduje build/SecondDisplay.app
|
||||
make run # buduje i uruchamia
|
||||
make check # lint: typecheck, plisty, tłumaczenia, podpis
|
||||
make install # kopiuje do ~/Applications
|
||||
make help # lista poleceń
|
||||
```
|
||||
Podpis jest ad-hoc (działa na tym Macu). Do dystrybucji: `make SIGN_ID="Developer ID Application: ..."` (potrzebna jeszcze notaryzacja).
|
||||
|
||||
## Użycie
|
||||
Menu u góry ekranu: **Obraz** (kamera, format), **Dźwięk** (źródło lub wyłączony), **Opcje** (blokada usypiania, pełny ekran przy starcie, na wierzchu, wyciszenie ⇧⌘M, skalowanie), **Okno** (kafelkowanie, pełny ekran ⌃⌘F).
|
||||
|
||||
## Struktura
|
||||
- `Sources/main.swift` – aplikacja (AppKit + AVFoundation)
|
||||
- `Config/` – `Info.plist`, entitlements (kamera, mikrofon)
|
||||
- `Resources/` – ikona (`AppIcon.icon`, Icon Composer), tłumaczenia en/pl, `uninstall.sh`
|
||||
- `scripts/check-strings.sh` – spójność tłumaczeń
|
||||
|
||||
## Ustawienia i odinstalowanie
|
||||
Ustawienia: `~/Library/Preferences/com.mmacierzanka.seconddisplay.plist`.
|
||||
Pełne usunięcie aplikacji i śladów: `make uninstall` albo `SecondDisplay.app/Contents/Resources/uninstall.sh`.
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/bin/zsh
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
A="SecondDisplay.app"
|
||||
rm -rf "$A"; mkdir -p "$A/Contents/MacOS"
|
||||
swiftc -O Sources/main.swift -o "$A/Contents/MacOS/SecondDisplay"
|
||||
cat > "$A/Contents/Info.plist" <<P
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0"><dict>
|
||||
<key>CFBundleDevelopmentRegion</key><string>en</string>
|
||||
<key>CFBundleLocalizations</key><array><string>en</string><string>pl</string></array>
|
||||
<key>CFBundleExecutable</key><string>SecondDisplay</string>
|
||||
<key>CFBundleIdentifier</key><string>com.mmacierzanka.seconddisplay</string>
|
||||
<key>CFBundleIconFile</key><string>AppIcon</string>
|
||||
<key>CFBundleIconName</key><string>AppIcon</string>
|
||||
<key>CFBundleName</key><string>Second Display</string>
|
||||
<key>CFBundlePackageType</key><string>APPL</string>
|
||||
<key>NSPrincipalClass</key><string>NSApplication</string>
|
||||
<key>NSCameraUsageDescription</key><string>Shows video from the capture device.</string>
|
||||
<key>NSMicrophoneUsageDescription</key><string>Plays audio from the selected input.</string>
|
||||
</dict></plist>
|
||||
P
|
||||
for L in en pl; do mkdir -p "$A/Contents/Resources/$L.lproj"; cp Resources/$L.lproj/*.strings "$A/Contents/Resources/$L.lproj/"; done
|
||||
xcrun actool Resources/AppIcon.icon --compile "$A/Contents/Resources" --platform macosx --minimum-deployment-target 26.0 --app-icon AppIcon --output-partial-info-plist /dev/null >/dev/null
|
||||
cp Resources/uninstall.sh "$A/Contents/Resources/"
|
||||
codesign --force --sign - "$A"
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/zsh
|
||||
# Fails if en/pl Localizable.strings differ in keys or code uses a key missing from them.
|
||||
cd "$(dirname "$0")/.."
|
||||
keys() { grep -o '^"[^"]*"' "Resources/$1.lproj/Localizable.strings" | sort; }
|
||||
used=$(grep -oh 'NSLocalizedString("[^"]*"' Sources/*.swift | sed 's/NSLocalizedString(//' | sort -u)
|
||||
# keys passed through a variable (e.g. the Fit/Fill/Stretch loop) are not caught by the grep above; list them in the pl/en parity check only
|
||||
fail=0
|
||||
diff <(keys en) <(keys pl) >/dev/null || { echo "en and pl keys differ:"; diff <(keys en) <(keys pl); fail=1; }
|
||||
missing=$(comm -23 <(echo "$used") <(keys en))
|
||||
[[ -z "$missing" ]] || { echo "Used but missing in en:"; echo "$missing"; fail=1; }
|
||||
exit $fail
|
||||
Reference in new issue
Block a user