mirror of
https://github.com/mmacierzanka/second-display.git
synced 2026-11-05 04:31:46 +01:00
3.5 KiB
3.5 KiB
Second Display – brief
Goal
A native macOS app that shows video from a capture device (camera / capture card) in a window and plays audio from a chosen input. It is meant to work as a "second monitor".
Requirements
- Menus live in the app's main menu bar at the top of the screen (not a status-bar icon): video source, audio source, and an option to turn audio off.
- Optional display-sleep prevention while the app is active. On by default, choice is remembered.
- Optional start in full screen. On by default, choice is remembered.
- Localization: English and Polish (
Resources/{en,pl}.lproj), following the system language. - Extras: per-device format (resolution/FPS), scaling modes (fit/fill/stretch), always on top, mute (⇧⌘M), Window menu (system tiling, full screen ⌃⌘F), automatic resume when a device is unplugged/replugged.
- Autostart menu: launch the app when a chosen USB device is attached (
Sources/Autostart.swift, per-user LaunchAgent with an IOKit match on USB vendor/product ID parsed fromAVCaptureDevice.modelID).uninstall.shmust remove the agent. The agent runs the app executable itself, andmain.swiftmust keep acknowledging thecom.apple.iokit.matchingevent stream — otherwise launchd relaunches the job every 10 s while the device is attached. - Out of scope (for now): launch at login, recording, screenshots, volume slider.
Structure
Sources/– app code (AppKit + AVFoundation, oneAVCaptureSession, audio viaAVCaptureAudioPreviewOutput). TheAppclass is split into extensions:main.swift(entry point),App.swift(state, window, lifecycle),Capture.swift(devices, formats, hot-plug),Menu.swift(menus and actions),Power.swift(sleep prevention),Autostart.swift(launch-on-connect agent),Preferences.swift(UserDefaults-backed settings).Config/Info.plist,Config/second-display.entitlements,Config/dmg/– version, permissions (camera, microphone; hardened runtime).Resources/–AppIcon.icon(Icon Composer, Liquid Glass; compiled byactool),{en,pl}.lproj(Localizable.strings,InfoPlist.strings),uninstall.sh(copied into the bundle; removes the app, preferences, caches, TCC permissions). Bundle ID:com.mmacierzanka.second-display.scripts/check-strings.sh– en/pl translation consistency.scripts/make-dmg-background.swiftregeneratesConfig/dmg/background.png; keep its size and icon coordinates in sync withConfig/dmg/settings.py(dmgbuild layout, installed intobuild/venvon firstmake dmg).Makefile–make(buildsbuild/Second Display.app),run,check,install,uninstall,dmg,clean,help. Builds are universal (arm64 + x86_64, macOS 26+).make dmgmakes an un-notarized DMG withConfig/dmg/Read Me First.txt.SIGN_IDdefaults to ad-hoc (-).
Conventions
- Settings live in
UserDefaults(keys:video,audio,autostart,autostartName,keepAwake,startFull,onTop,gravity,format.<id>). - Add new strings through
NSLocalizedStringand to bothLocalizable.stringsfiles. - Run
make checkbefore committing. Version is inConfig/Info.plist; build number = commit count. - Work on a feature branch (
feature/<topic>,fix/<topic>) and open a PR withgh pr create; do not commit straight tomain. - Commits follow Conventional Commits, in English:
feat:,fix:,docs:,refactor:,build:,chore:(optional scope, e.g.feat(menu):), imperative subject under ~72 chars. Small, one per change, with aCo-Authored-Byline.