Add scripts to create macOS app bundle and LaunchAgent #1244
This change introduces two new helper scripts for macOS users to improve integration with the operating system. The `create-macos-app.sh` script builds a minimal `.app` wrapper for Solaar. This allows Solaar to be treated as a standard macOS application, enabling it to request necessary permissions, such as input monitoring, and to be discoverable by the OS. The script generates the required directory structure, a wrapper executable to launch Solaar, a standard `Info.plist` file, and an application icon from the source PNG. The `create-macos-launchagent.sh` script sets up a LaunchAgent to automatically start Solaar at login and keep it running in the background. This ensures that the Solaar process is always available for device management without requiring manual intervention from the user. The script also configures log file locations for standard output and error streams. Together, these scripts provide a more native and user-friendly experience for Solaar on macOS. https://github.com/pwr-Solaar/Solaar/issues/1244
This commit is contained in:
parent
5c94cf4d9f
commit
8fd14fefa1
|
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/env bash
|
||||
# Helper to build a minimal macOS .app wrapper for Solaar.
|
||||
set -euo pipefail
|
||||
|
||||
APP_ROOT=${1:-/Applications/Solaar.app}
|
||||
SOLAR_PATH=${SOLAR_PATH:-/opt/homebrew/bin/solaar}
|
||||
ICON_SOURCE=${ICON_SOURCE:-share/solaar/icons/solaar-light_100.png}
|
||||
|
||||
if [[ ! -x "${SOLAR_PATH}" ]]; then
|
||||
echo "Error: Unable to execute ${SOLAR_PATH}. Set SOLAR_PATH to the solaar binary." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "${APP_ROOT}" in
|
||||
""|"/"|".")
|
||||
echo "Error: Refusing to create app bundle at unsafe location: \"${APP_ROOT}\"" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Creating Solaar app bundle at ${APP_ROOT}"
|
||||
rm -rf "${APP_ROOT}"
|
||||
|
||||
APP_CONTENTS="${APP_ROOT}/Contents"
|
||||
MACOS_DIR="${APP_CONTENTS}/MacOS"
|
||||
RESOURCES_DIR="${APP_CONTENTS}/Resources"
|
||||
|
||||
mkdir -p "${MACOS_DIR}" "${RESOURCES_DIR}"
|
||||
|
||||
WRAPPER="${MACOS_DIR}/solaar-wrapper"
|
||||
cat > "${WRAPPER}" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
exec "${SOLAR_PATH}" --window=hide "\$@"
|
||||
EOF
|
||||
chmod +x "${WRAPPER}"
|
||||
|
||||
HAVE_ICON=0
|
||||
if command -v sips >/dev/null 2>&1 && command -v iconutil >/dev/null 2>&1 && [[ -f "${ICON_SOURCE}" ]]; then
|
||||
TMP_ICONSET=$(mktemp -d /tmp/solaar-iconset.XXXXXX)
|
||||
trap 'rm -rf "${TMP_ICONSET}"' EXIT
|
||||
for SIZE in 16 32 64 128 256 512; do
|
||||
sips -s format png -z "${SIZE}" "${SIZE}" "${ICON_SOURCE}" --out "${TMP_ICONSET}/icon_${SIZE}x${SIZE}.png" >/dev/null
|
||||
DOUBLE=$((SIZE * 2))
|
||||
sips -s format png -z "${DOUBLE}" "${DOUBLE}" "${ICON_SOURCE}" --out "${TMP_ICONSET}/icon_${SIZE}x${SIZE}@2x.png" >/dev/null
|
||||
done
|
||||
if iconutil -c icns "${TMP_ICONSET}" -o "${RESOURCES_DIR}/solaar.icns" >/dev/null 2>&1; then
|
||||
HAVE_ICON=1
|
||||
echo "Added icon from ${ICON_SOURCE}"
|
||||
else
|
||||
echo "Warning: Failed to create solaar.icns – continuing without custom icon" >&2
|
||||
fi
|
||||
rm -rf "${TMP_ICONSET}"
|
||||
trap - EXIT
|
||||
else
|
||||
echo "Skipping icon generation (requires sips, iconutil, and ${ICON_SOURCE})"
|
||||
fi
|
||||
|
||||
{
|
||||
cat <<EOF
|
||||
<?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>CFBundleExecutable</key>
|
||||
<string>solaar-wrapper</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>io.github.pwr-solaar.solaar</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Solaar</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>11.0</string>
|
||||
<key>NSInputMonitoringUsageDescription</key>
|
||||
<string>Solaar needs to access input devices to configure and monitor your Logitech keyboards, mice, and other peripherals.</string>
|
||||
EOF
|
||||
if [[ ${HAVE_ICON} -eq 1 ]]; then
|
||||
cat <<'EOF'
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>solaar.icns</string>
|
||||
EOF
|
||||
fi
|
||||
cat <<'EOF'
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
} > "${APP_CONTENTS}/Info.plist"
|
||||
|
||||
echo "Solaar app bundle created at ${APP_ROOT}"
|
||||
echo ""
|
||||
echo "To install the LaunchAgent for automatic startup and keep-alive execute:"
|
||||
echo " bash tools/create-macos-launchagent.sh"
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
#!/usr/bin/env bash
|
||||
# Helper to install a LaunchAgent for Solaar to keep it running in the background.
|
||||
set -euo pipefail
|
||||
|
||||
SOLAR_PATH=${SOLAR_PATH:-/opt/homebrew/bin/solaar}
|
||||
|
||||
if [[ ! -x "${SOLAR_PATH}" ]]; then
|
||||
echo "Error: Unable to execute ${SOLAR_PATH}. Set SOLAR_PATH to the solaar binary." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LAUNCH_AGENT_DIR="${HOME}/Library/LaunchAgents"
|
||||
LAUNCH_AGENT_PLIST="${LAUNCH_AGENT_DIR}/io.github.pwr-solaar.solaar.plist"
|
||||
|
||||
mkdir -p "${LAUNCH_AGENT_DIR}"
|
||||
|
||||
echo "Creating LaunchAgent to keep Solaar running..."
|
||||
|
||||
# Unload if already loaded (suppress errors)
|
||||
launchctl unload "${LAUNCH_AGENT_PLIST}" 2>/dev/null || true
|
||||
|
||||
cat > "${LAUNCH_AGENT_PLIST}" <<EOF
|
||||
<?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>Label</key>
|
||||
<string>io.github.pwr-solaar.solaar</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>${SOLAR_PATH}</string>
|
||||
<string>--window=hide</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>${HOME}/Library/Logs/solaar.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>${HOME}/Library/Logs/solaar.error.log</string>
|
||||
<key>ProcessType</key>
|
||||
<string>Background</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
launchctl load "${LAUNCH_AGENT_PLIST}"
|
||||
|
||||
echo "LaunchAgent created at ${LAUNCH_AGENT_PLIST}"
|
||||
echo ""
|
||||
echo "To disable automatic startup:"
|
||||
echo " launchctl unload \"${LAUNCH_AGENT_PLIST}\""
|
||||
echo ""
|
||||
echo "To re-enable automatic startup:"
|
||||
echo " launchctl load \"${LAUNCH_AGENT_PLIST}\""
|
||||
echo ""
|
||||
echo "To start Solaar:"
|
||||
echo " launchctl start io.github.pwr-solaar.solaar"
|
||||
echo ""
|
||||
echo "To stop Solaar:"
|
||||
echo " launchctl stop io.github.pwr-solaar.solaar"
|
||||
echo ""
|
||||
echo "Logs will be written to:"
|
||||
echo " ${HOME}/Library/Logs/solaar.log"
|
||||
echo " ${HOME}/Library/Logs/solaar.error.log"
|
||||
Loading…
Reference in New Issue