From 91270966f9c7012f8eafca6bd1825e985e4c9501 Mon Sep 17 00:00:00 2001 From: Paulchen-Panther <16664240+Paulchen-Panther@users.noreply.github.com> Date: Thu, 16 Nov 2023 21:05:56 +0100 Subject: [PATCH] Refactor/Create APT/DNF Repository (#1648) --- .ci/ci_build.sh | 71 --- .ci/ci_install.sh | 40 -- .devcontainer.json | 37 +- .github/scripts/build.sh | 59 +++ .github/workflows/apt.yml | 154 ------- .github/workflows/apt/amd64.json | 58 --- .github/workflows/apt/arm64.json | 51 --- .github/workflows/apt/armhf.json | 51 --- .github/workflows/cleanup.yml | 4 +- .github/workflows/codeql.yml | 25 +- .github/workflows/nightly.yml | 187 -------- .github/workflows/pull-request.yml | 193 -------- .github/workflows/push-master.yml | 201 -------- .github/workflows/push_pull.yml | 49 ++ .github/workflows/qt5_6.yml | 250 ++++++++++ .github/workflows/release.yml | 9 +- CMakeLists.txt | 431 +++++++++--------- bin/scripts/docker-compile.sh | 153 +++++-- bin/scripts/install_pr.sh | 12 +- bin/service/hyperion.systemd | 2 +- bin/service/hyperion.xml | 22 + cmake/Dependencies.cmake | 51 ++- cmake/Findqmdnsengine.cmake | 8 +- cmake/LDGold.cmake | 17 - .../{hyperiond.desktop => hyperion.desktop} | 4 +- cmake/desktop/hyperion.metainfo.xml | 48 ++ cmake/desktop/hyperiond_128.png | Bin 16979 -> 0 bytes cmake/package-scripts/postinst | 8 +- cmake/package-scripts/prerm | 28 +- cmake/packages.cmake | 2 +- cmake/win/win_rc.cmake | 15 - debian/control.in | 12 - debian/distributions | 58 --- debian/rules.in | 32 -- dependencies/CMakeLists-qmdnsengine.txt.in | 26 -- dependencies/CMakeLists.txt | 86 ++-- dependencies/external/mbedtls | 2 +- include/grabber/OsxFrameGrabberMock.h | 93 ---- .../grabber/{ => amlogic}/AmlogicGrabber.h | 2 +- .../grabber/{ => amlogic}/AmlogicWrapper.h | 2 +- include/grabber/{ => audio}/AudioGrabber.h | 0 .../grabber/{ => audio}/AudioGrabberLinux.h | 31 +- .../grabber/{ => audio}/AudioGrabberWindows.h | 4 +- include/grabber/{ => audio}/AudioWrapper.h | 12 +- .../grabber/{ => directx}/DirectXGrabber.h | 0 .../grabber/{ => directx}/DirectXWrapper.h | 2 +- .../{ => dispmanx}/DispmanxFrameGrabber.h | 0 .../grabber/{ => dispmanx}/DispmanxWrapper.h | 2 +- .../FramebufferFrameGrabber.h | 0 .../{ => framebuffer}/FramebufferWrapper.h | 2 +- include/grabber/{ => osx}/OsxFrameGrabber.h | 4 - include/grabber/{ => osx}/OsxWrapper.h | 2 +- include/grabber/{ => qt}/QtGrabber.h | 0 include/grabber/{ => qt}/QtWrapper.h | 2 +- include/grabber/{ => video}/EncoderThread.h | 12 +- include/grabber/{ => video}/VideoWrapper.h | 4 +- .../{ => video/mediafoundation}/MFGrabber.h | 2 +- .../grabber/{ => video/v4l2}/V4L2Grabber.h | 2 +- include/grabber/{ => x11}/X11Grabber.h | 0 include/grabber/{ => x11}/X11Wrapper.h | 2 +- include/grabber/{ => xcb}/XcbGrabber.h | 0 include/grabber/{ => xcb}/XcbWrapper.h | 2 +- include/hyperion/ImageToLedsMap.h | 2 +- include/utils/Process.h | 9 +- libsrc/CMakeLists.txt | 6 +- libsrc/api/CMakeLists.txt | 32 +- libsrc/api/JsonAPI.cpp | 26 +- libsrc/blackborder/CMakeLists.txt | 14 +- libsrc/boblightserver/CMakeLists.txt | 15 +- libsrc/cec/CMakeLists.txt | 23 +- libsrc/commandline/CMakeLists.txt | 31 +- libsrc/db/CMakeLists.txt | 14 +- libsrc/effectengine/CMakeLists.txt | 57 +-- libsrc/effectengine/EffectEngine.qrc.in | 2 +- libsrc/flatbufserver/CMakeLists.txt | 103 ++--- libsrc/forwarder/CMakeLists.txt | 17 +- libsrc/grabber/CMakeLists.txt | 22 +- libsrc/grabber/amlogic/AmlogicGrabber.cpp | 2 +- libsrc/grabber/amlogic/AmlogicWrapper.cpp | 2 +- libsrc/grabber/amlogic/CMakeLists.txt | 22 +- libsrc/grabber/audio/AudioGrabber.cpp | 2 +- libsrc/grabber/audio/AudioGrabberLinux.cpp | 61 ++- libsrc/grabber/audio/AudioGrabberWindows.cpp | 28 +- libsrc/grabber/audio/AudioWrapper.cpp | 2 +- libsrc/grabber/audio/CMakeLists.txt | 63 +-- libsrc/grabber/directx/CMakeLists.txt | 23 +- libsrc/grabber/directx/DirectXGrabber.cpp | 2 +- libsrc/grabber/directx/DirectXWrapper.cpp | 2 +- libsrc/grabber/dispmanx/CMakeLists.txt | 23 +- .../grabber/dispmanx/DispmanxFrameGrabber.cpp | 2 +- libsrc/grabber/dispmanx/DispmanxWrapper.cpp | 2 +- libsrc/grabber/framebuffer/CMakeLists.txt | 15 +- .../framebuffer/FramebufferFrameGrabber.cpp | 2 +- .../framebuffer/FramebufferWrapper.cpp | 2 +- libsrc/grabber/osx/CMakeLists.txt | 15 +- libsrc/grabber/osx/OsxFrameGrabber.cpp | 2 +- libsrc/grabber/osx/OsxFrameGrabberMock.cpp | 159 ------- libsrc/grabber/osx/OsxWrapper.cpp | 2 +- libsrc/grabber/qt/CMakeLists.txt | 15 +- libsrc/grabber/qt/QtGrabber.cpp | 4 +- libsrc/grabber/qt/QtWrapper.cpp | 2 +- libsrc/grabber/video/CMakeLists.txt | 51 ++- libsrc/grabber/video/EncoderThread.cpp | 2 +- libsrc/grabber/video/VideoWrapper.cpp | 2 +- .../video/mediafoundation/MFGrabber.cpp | 4 +- .../video/mediafoundation/MFSourceReaderCB.h | 2 +- libsrc/grabber/video/v4l2/V4L2Grabber.cpp | 2 +- libsrc/grabber/x11/CMakeLists.txt | 29 +- libsrc/grabber/x11/X11Grabber.cpp | 2 +- libsrc/grabber/x11/X11Wrapper.cpp | 2 +- libsrc/grabber/xcb/CMakeLists.txt | 26 +- libsrc/grabber/xcb/XcbGrabber.cpp | 2 +- libsrc/grabber/xcb/XcbWrapper.cpp | 2 +- libsrc/hyperion/CMakeLists.txt | 64 ++- libsrc/jsonserver/CMakeLists.txt | 17 +- libsrc/leddevice/CMakeLists.txt | 89 ++-- libsrc/mdns/CMakeLists.txt | 23 +- libsrc/protoserver/CMakeLists.txt | 47 +- libsrc/python/CMakeLists.txt | 46 +- libsrc/ssdp/CMakeLists.txt | 15 +- libsrc/utils/CMakeLists.txt | 114 +++-- libsrc/utils/Process.cpp | 137 +++--- libsrc/webserver/CMakeLists.txt | 44 +- resources/CMakeLists.txt | 14 +- resources/icons/hyperion-128px.png | Bin 0 -> 10834 bytes resources/icons/hyperion-16px.png | Bin 0 -> 717 bytes resources/icons/hyperion-192px.png | Bin 0 -> 21900 bytes resources/icons/hyperion-22px.png | Bin 0 -> 1728 bytes resources/icons/hyperion-24px.png | Bin 0 -> 1894 bytes resources/icons/hyperion-256px.png | Bin 0 -> 31694 bytes resources/icons/hyperion-32px.png | Bin 0 -> 1459 bytes resources/icons/hyperion-36px.png | Bin 0 -> 2462 bytes resources/icons/hyperion-48px.png | Bin 0 -> 2556 bytes resources/icons/hyperion-512px.png | Bin 0 -> 86035 bytes resources/icons/hyperion-64px.png | Bin 0 -> 3845 bytes resources/icons/hyperion-72px.png | Bin 0 -> 4451 bytes resources/icons/hyperion-96px.png | Bin 0 -> 7921 bytes resources/icons/hyperion-icon-32px.png | Bin 1454 -> 0 bytes resources/icons/hyperion-icon-512px.png | Bin 69597 -> 0 bytes snap/snapcraft.yaml | 4 +- src/CMakeLists.txt | 6 +- src/hyperion-aml/AmlogicWrapper.h | 2 +- src/hyperion-aml/CMakeLists.txt | 39 +- src/hyperion-dispmanx/CMakeLists.txt | 35 +- src/hyperion-dispmanx/DispmanxWrapper.h | 4 +- src/hyperion-framebuffer/CMakeLists.txt | 42 +- src/hyperion-framebuffer/FramebufferWrapper.h | 2 +- src/hyperion-osx/CMakeLists.txt | 30 +- src/hyperion-osx/OsxWrapper.h | 2 +- src/hyperion-qt/CMakeLists.txt | 49 +- src/hyperion-qt/QtWrapper.h | 2 +- src/hyperion-remote/CMakeLists.txt | 58 +-- src/hyperion-v4l2/CMakeLists.txt | 39 +- src/hyperion-v4l2/hyperion-v4l2.cpp | 4 +- src/hyperion-x11/CMakeLists.txt | 40 +- src/hyperion-x11/X11Wrapper.h | 2 +- src/hyperion-xcb/CMakeLists.txt | 29 +- src/hyperion-xcb/XcbWrapper.h | 2 +- src/hyperiond/CMakeLists.txt | 198 ++++---- src/hyperiond/hyperiond.h | 22 +- src/hyperiond/main.cpp | 2 +- src/hyperiond/systray.cpp | 4 +- test/CMakeLists.txt | 14 +- test/dispmanx2png/CMakeLists.txt | 4 +- test/dispmanx2png/dispmanx2png.cpp | 2 +- 165 files changed, 1916 insertions(+), 2922 deletions(-) delete mode 100755 .ci/ci_build.sh delete mode 100755 .ci/ci_install.sh create mode 100755 .github/scripts/build.sh delete mode 100644 .github/workflows/apt.yml delete mode 100644 .github/workflows/apt/amd64.json delete mode 100644 .github/workflows/apt/arm64.json delete mode 100644 .github/workflows/apt/armhf.json delete mode 100644 .github/workflows/nightly.yml delete mode 100644 .github/workflows/pull-request.yml delete mode 100644 .github/workflows/push-master.yml create mode 100644 .github/workflows/push_pull.yml create mode 100644 .github/workflows/qt5_6.yml create mode 100644 bin/service/hyperion.xml delete mode 100644 cmake/LDGold.cmake rename cmake/desktop/{hyperiond.desktop => hyperion.desktop} (61%) create mode 100644 cmake/desktop/hyperion.metainfo.xml delete mode 100644 cmake/desktop/hyperiond_128.png delete mode 100644 cmake/win/win_rc.cmake delete mode 100644 debian/control.in delete mode 100644 debian/distributions delete mode 100644 debian/rules.in delete mode 100644 dependencies/CMakeLists-qmdnsengine.txt.in delete mode 100644 include/grabber/OsxFrameGrabberMock.h rename include/grabber/{ => amlogic}/AmlogicGrabber.h (97%) rename include/grabber/{ => amlogic}/AmlogicWrapper.h (95%) rename include/grabber/{ => audio}/AudioGrabber.h (100%) rename include/grabber/{ => audio}/AudioGrabberLinux.h (86%) rename include/grabber/{ => audio}/AudioGrabberWindows.h (98%) rename include/grabber/{ => audio}/AudioWrapper.h (90%) rename include/grabber/{ => directx}/DirectXGrabber.h (100%) rename include/grabber/{ => directx}/DirectXWrapper.h (96%) rename include/grabber/{ => dispmanx}/DispmanxFrameGrabber.h (100%) rename include/grabber/{ => dispmanx}/DispmanxWrapper.h (95%) rename include/grabber/{ => framebuffer}/FramebufferFrameGrabber.h (100%) rename include/grabber/{ => framebuffer}/FramebufferWrapper.h (94%) rename include/grabber/{ => osx}/OsxFrameGrabber.h (95%) rename include/grabber/{ => osx}/OsxWrapper.h (95%) rename include/grabber/{ => qt}/QtGrabber.h (100%) rename include/grabber/{ => qt}/QtWrapper.h (97%) rename include/grabber/{ => video}/EncoderThread.h (91%) rename include/grabber/{ => video}/VideoWrapper.h (89%) rename include/grabber/{ => video/mediafoundation}/MFGrabber.h (98%) rename include/grabber/{ => video/v4l2}/V4L2Grabber.h (99%) rename include/grabber/{ => x11}/X11Grabber.h (100%) rename include/grabber/{ => x11}/X11Wrapper.h (97%) rename include/grabber/{ => xcb}/XcbGrabber.h (100%) rename include/grabber/{ => xcb}/XcbWrapper.h (94%) delete mode 100644 libsrc/grabber/osx/OsxFrameGrabberMock.cpp create mode 100644 resources/icons/hyperion-128px.png create mode 100644 resources/icons/hyperion-16px.png create mode 100644 resources/icons/hyperion-192px.png create mode 100644 resources/icons/hyperion-22px.png create mode 100644 resources/icons/hyperion-24px.png create mode 100644 resources/icons/hyperion-256px.png create mode 100644 resources/icons/hyperion-32px.png create mode 100644 resources/icons/hyperion-36px.png create mode 100644 resources/icons/hyperion-48px.png create mode 100644 resources/icons/hyperion-512px.png create mode 100644 resources/icons/hyperion-64px.png create mode 100644 resources/icons/hyperion-72px.png create mode 100644 resources/icons/hyperion-96px.png delete mode 100644 resources/icons/hyperion-icon-32px.png delete mode 100644 resources/icons/hyperion-icon-512px.png diff --git a/.ci/ci_build.sh b/.ci/ci_build.sh deleted file mode 100755 index df276f00e..000000000 --- a/.ci/ci_build.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash - -# detect CI -if [ "$HOME" != "" ]; then - # GitHub Actions - echo "Github Actions detected" - CI_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')" - CI_BUILD_DIR="$GITHUB_WORKSPACE" -else - # for executing in non ci environment - CI_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')" -fi - -# set environment variables if not exists -[ -z "${BUILD_TYPE}" ] && BUILD_TYPE="Debug" - -# Determine cmake build type; tag builds are Release, else Debug (-dev appends to platform) -if [[ $BUILD_SOURCEBRANCH == *"refs/tags"* || $GITHUB_REF == *"refs/tags"* ]]; then - BUILD_TYPE=Release -else - PLATFORM=${PLATFORM}-dev -fi - -echo "Platform: ${PLATFORM}, build type: ${BUILD_TYPE}, CI_NAME: $CI_NAME, docker image: ${DOCKER_IMAGE}, docker type: ${DOCKER_TAG}" - -# Build the package on osx or linux -if [[ "$CI_NAME" == 'osx' || "$CI_NAME" == 'darwin' ]]; then - echo "Compile Hyperion on OSX or Darwin" - # compile prepare - mkdir build || exit 1 - cd build - cmake -DPLATFORM=${PLATFORM} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=/usr/local ../ || exit 2 - make -j $(sysctl -n hw.ncpu) package || exit 3 - cd ${CI_BUILD_DIR} && source /${CI_BUILD_DIR}/test/testrunner.sh || exit 4 - exit 0; - exit 1 || { echo "---> Hyperion compilation failed! Abort"; exit 5; } -elif [[ $CI_NAME == *"mingw64_nt"* || "$CI_NAME" == 'windows_nt' ]]; then - echo "Compile Hyperion on Windows" - # compile prepare - echo "Number of Cores $NUMBER_OF_PROCESSORS" - mkdir build || exit 1 - cd build - cmake -G "Visual Studio 17 2022" -A x64 -DPLATFORM=${PLATFORM} -DCMAKE_BUILD_TYPE="Release" ../ || exit 2 - cmake --build . --target package --config "Release" -- -nologo -v:m -maxcpucount || exit 3 - exit 0; - exit 1 || { echo "---> Hyperion compilation failed! Abort"; exit 5; } -elif [[ "$CI_NAME" == 'linux' ]]; then - echo "Compile Hyperion with DOCKER_IMAGE = ${DOCKER_IMAGE}, DOCKER_TAG = ${DOCKER_TAG} and friendly name DOCKER_NAME = ${DOCKER_NAME}" - # set GitHub Container Registry url - REGISTRY_URL="ghcr.io/hyperion-project/${DOCKER_IMAGE}" - # take ownership of deploy dir - mkdir ${CI_BUILD_DIR}/deploy - - # run docker - docker run --rm \ - -v "${CI_BUILD_DIR}/deploy:/deploy" \ - -v "${CI_BUILD_DIR}:/source:ro" \ - $REGISTRY_URL:$DOCKER_TAG \ - /bin/bash -c "mkdir hyperion && cp -r source/. /hyperion && - cd /hyperion && mkdir build && cd build && - cmake -DPLATFORM=${PLATFORM} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ../ || exit 2 && - make -j $(nproc) package || exit 3 && - cp /hyperion/build/bin/h* /deploy/ 2>/dev/null || : && - cp /hyperion/build/Hyperion-* /deploy/ 2>/dev/null || : && - cd /hyperion && source /hyperion/test/testrunner.sh || exit 4 && - exit 0; - exit 1 " || { echo "---> Hyperion compilation failed! Abort"; exit 5; } - - # overwrite file owner to current user - sudo chown -fR $(stat -c "%U:%G" ${CI_BUILD_DIR}/deploy) ${CI_BUILD_DIR}/deploy -fi diff --git a/.ci/ci_install.sh b/.ci/ci_install.sh deleted file mode 100755 index 86c6ffd4b..000000000 --- a/.ci/ci_install.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -# detect CI -if [ "$HOME" != "" ]; then - # GitHub Actions - CI_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')" - CI_BUILD_DIR="$GITHUB_WORKSPACE" -else - # for executing in non ci environment - CI_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')" -fi - -function installAndUpgrade() -{ - arr=("$@") - for i in "${arr[@]}"; - do - list_output=`brew list --formula | grep $i` - outdated_output=`brew outdated | grep $i` - - if [[ ! -z "$list_output" ]]; then - if [[ ! -z "$outdated_output" ]]; then - echo "Outdated package: ${outdated_output}" - brew unlink ${outdated_output} - brew upgrade $i - brew link --overwrite $i - fi - else - brew install $i - fi - done -} - -# install osx deps for hyperion compile -if [[ $CI_NAME == 'osx' || $CI_NAME == 'darwin' ]]; then - echo "Install dependencies" - brew update - dependencies=("qt5" "python" "libusb" "cmake" "doxygen") - installAndUpgrade "${dependencies[@]}" -fi diff --git a/.devcontainer.json b/.devcontainer.json index 4cce9be71..966a658ba 100644 --- a/.devcontainer.json +++ b/.devcontainer.json @@ -1,20 +1,25 @@ { "name": "Hyperion.ng Linux", - "extensions": [ - "twxs.cmake", - "ms-vscode.cpptools", - "ms-vscode.cmake-tools", - "spmeesseman.vscode-taskexplorer", - "yzhang.markdown-all-in-one", - "CoenraadS.bracket-pair-colorizer", - "vscode-icons-team.vscode-icons", - "editorconfig.editorconfig" - ], - "settings": { - "editor.formatOnSave": false, - "cmake.environment": { - }, - }, + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + "extensions": [ + "twxs.cmake", + "ms-vscode.cpptools", + "ms-vscode.cmake-tools", + "spmeesseman.vscode-taskexplorer", + "yzhang.markdown-all-in-one", + "CoenraadS.bracket-pair-colorizer", + "vscode-icons-team.vscode-icons", + "editorconfig.editorconfig", + "RVSmartPorting.rpm-spec-ext" + ], + "settings": { + "editor.formatOnSave": false, + "cmake.environment": { } + } + } + }, "forwardPorts": [8090, 8092], - "postCreateCommand": "git submodule update --recursive --init && sudo apt-get update && sudo apt-get install -y git cmake build-essential qtbase5-dev libqt5serialport5-dev libqt5sql5-sqlite libqt5svg5-dev libqt5x11extras5-dev libusb-1.0-0-dev python3-dev libcec-dev libxcb-image0-dev libxcb-util0-dev libxcb-shm0-dev libxcb-render0-dev libxcb-randr0-dev libxrandr-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libturbojpeg0-dev libssl-dev" + "postCreateCommand": "git submodule update --recursive --init && sudo apt-get update && sudo apt-get install -y git cmake build-essential qtbase5-dev libqt5serialport5-dev libqt5sql5-sqlite libqt5svg5-dev libqt5x11extras5-dev libusb-1.0-0-dev python3-dev libcec-dev libxcb-image0-dev libxcb-util0-dev libxcb-shm0-dev libxcb-render0-dev libxcb-randr0-dev libxrandr-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libturbojpeg0-dev libssl-dev libasound2-dev" } diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh new file mode 100755 index 000000000..5880abb92 --- /dev/null +++ b/.github/scripts/build.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# set environment variables if not exists +[ -z "${BUILD_TYPE}" ] && BUILD_TYPE="Debug" +[ -z "${TARGET_ARCH}" ] && TARGET_ARCH="linux/amd64" +[ -z "${PLATFORM}" ] && PLATFORM="x11" + +# Determine cmake build type; tag builds are Release, else Debug (-dev appends to platform) +if [[ $GITHUB_REF == *"refs/tags"* ]]; then + BUILD_TYPE=Release +else + PLATFORM=${PLATFORM}-dev +fi + +echo "Compile Hyperion on '${RUNNER_OS}' with build type '${BUILD_TYPE}' and platform '${PLATFORM}'" + +# Build the package on MacOS, Windows or Linux +if [[ "$RUNNER_OS" == 'macOS' ]]; then + mkdir build || exit 1 + cd build + cmake -DPLATFORM=${PLATFORM} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=/usr/local ../ || exit 2 + make -j $(sysctl -n hw.ncpu) package || exit 3 + cd ${GITHUB_WORKSPACE} && source /${GITHUB_WORKSPACE}/test/testrunner.sh || exit 4 + exit 0; + exit 1 || { echo "---> Hyperion compilation failed! Abort"; exit 5; } +elif [[ $RUNNER_OS == "Windows" ]]; then + echo "Number of Cores $NUMBER_OF_PROCESSORS" + mkdir build || exit 1 + cd build + cmake -G "Visual Studio 17 2022" -A x64 -DPLATFORM=${PLATFORM} -DCMAKE_BUILD_TYPE="Release" ../ || exit 2 + cmake --build . --target package --config "Release" -- -nologo -v:m -maxcpucount || exit 3 + exit 0; + exit 1 || { echo "---> Hyperion compilation failed! Abort"; exit 5; } +elif [[ "$RUNNER_OS" == 'Linux' ]]; then + echo "Docker arguments used: DOCKER_IMAGE=${DOCKER_IMAGE}, DOCKER_TAG=${DOCKER_TAG}, TARGET_ARCH=${TARGET_ARCH}" + # verification bypass of external dependencies + git config --global --add safe.directory "${GITHUB_WORKSPACE}/dependencies/external/*" + # set GitHub Container Registry url + REGISTRY_URL="ghcr.io/hyperion-project/${DOCKER_IMAGE}" + # take ownership of deploy dir + mkdir ${GITHUB_WORKSPACE}/deploy + + # run docker + docker run --rm --platform=${TARGET_ARCH} \ + -v "${GITHUB_WORKSPACE}/deploy:/deploy" \ + -v "${GITHUB_WORKSPACE}:/source:rw" \ + $REGISTRY_URL:$DOCKER_TAG \ + /bin/bash -c "mkdir -p /source/build && cd /source/build && + cmake -DPLATFORM=${PLATFORM} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ../ || exit 2 && + cmake --build /source/build --target package -- -j $(nproc) || exit 3 && + cp /source/build/bin/h* /deploy/ 2>/dev/null || : && + cp /source/build/Hyperion-* /deploy/ 2>/dev/null || : && + cd /source && source /source/test/testrunner.sh || exit 5 && + exit 0; + exit 1 " || { echo "---> Hyperion compilation failed! Abort"; exit 5; } + + # overwrite file owner to current user + sudo chown -fR $(stat -c "%U:%G" ${GITHUB_WORKSPACE}/deploy) ${GITHUB_WORKSPACE}/deploy +fi diff --git a/.github/workflows/apt.yml b/.github/workflows/apt.yml deleted file mode 100644 index 99bce2146..000000000 --- a/.github/workflows/apt.yml +++ /dev/null @@ -1,154 +0,0 @@ -name: Hyperion APT Build -on: - workflow_call: - inputs: - head_sha: - type: string - description: The branch, tag or SHA to checkout - required: true - secrets: - APT_GPG: - required: true - APT_USER: - required: true - APT_PASSWORD: - required: true - APT_DRAFT: - required: true - workflow_dispatch: - inputs: - head_sha: - type: string - description: The branch, tag or SHA to checkout - required: true - secrets: - APT_GPG: - required: true - APT_USER: - required: true - APT_PASSWORD: - required: true - APT_DRAFT: - required: true - -jobs: - setup: - name: Setup APT build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set APT matrix - id: apt-ppa - run: | - APT=$(jq -n '.include |= [ inputs[] | select(.["exclude"] != true)]' .github/workflows/apt/*.json --compact-output) - echo "apt=$APT" >> $GITHUB_OUTPUT - - outputs: - apt-matrix: ${{ steps.apt-ppa.outputs.apt }} - - build: - name: ${{ matrix.description }} - needs: [setup] - runs-on: ubuntu-latest - strategy: - matrix: ${{ fromJson(needs.setup.outputs.apt-matrix) }} - - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.inputs.head_sha || github.event.client_payload.head_sha }} - submodules: true - - - name: Generate environment variables - run: | - tr -d '\n' < .version > temp && mv temp .version - VERSION=$(cat .version) - echo VERSION=${VERSION} >> $GITHUB_ENV - if [[ $VERSION == *"-"* ]]; then - echo STANDARDS_VERSION=$(echo ${VERSION%-*}) >> $GITHUB_ENV - echo TARBALL_VERSION=$(echo ${VERSION%-*}) >> $GITHUB_ENV - echo DEBIAN_FORMAT='3.0 (quilt)' >> $GITHUB_ENV - else - echo STANDARDS_VERSION=$(echo ${VERSION%+*}) >> $GITHUB_ENV - echo TARBALL_VERSION=${VERSION}~$(echo ${{ matrix.distribution }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV - echo DEBIAN_FORMAT='3.0 (native)' >> $GITHUB_ENV - fi - echo DISTRIBUTION=$(echo ${{ matrix.distribution }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV - - - name: Build package - shell: bash - run: | - mkdir -p "${GITHUB_WORKSPACE}/deploy" - docker run --rm \ - -v "${GITHUB_WORKSPACE}/deploy:/deploy" \ - -v "${GITHUB_WORKSPACE}:/source:rw" \ - ghcr.io/hyperion-project/${{ matrix.architecture }}:${{ env.DISTRIBUTION }} \ - /bin/bash -c "cd /source && \ - mkdir -p debian/source && echo '${{ env.DEBIAN_FORMAT }}' > debian/source/format && \ - dch --create --distribution ${{ env.DISTRIBUTION }} --package 'hyperion' -v '${{ env.VERSION }}~${{ env.DISTRIBUTION }}' '${{ github.event.commits[0].message }}' && \ - cp -fr LICENSE debian/copyright && \ - sed 's/@BUILD_DEPENDS@/${{ matrix.build-depends }}/g; s/@DEPENDS@/${{ matrix.package-depends }}/g; s/@ARCHITECTURE@/${{ matrix.architecture }}/g; s/@STANDARDS_VERSION@/${{ env.STANDARDS_VERSION }}/g' debian/control.in > debian/control && \ - sed 's/@CMAKE_ENVIRONMENT@/${{ matrix.cmake-environment }}/g' debian/rules.in > debian/rules && \ - tar -cJf ../hyperion_${{ env.TARBALL_VERSION }}.orig.tar.xz . && \ - debuild --no-lintian -uc -us && \ - cp ../hyperion_*.deb /deploy" - - - name: Upload package artifact - if: ${{ startsWith(github.event.ref, 'refs/tags') || github.event_name == 'workflow_dispatch' }} - uses: actions/upload-artifact@v3 - with: - path: deploy - retention-days: 1 - - publish: - name: Publish APT packages - if: ${{ startsWith(github.event.ref, 'refs/tags') || github.event_name == 'workflow_dispatch' }} - needs: [setup, build] - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - ref: ${{ github.event.inputs.head_sha || github.event.client_payload.head_sha }} - - - name: Import GPG key - uses: crazy-max/ghaction-import-gpg@v6.0.0 - with: - gpg_private_key: ${{ secrets.APT_GPG }} - - - name: Install reprepro - run: sudo apt -y install reprepro - - - name: Make build folders, export public GPG key and copy distributions file - run: | - mkdir -p apt/{conf,dists,db} - gpg --armor --output apt/hyperion.pub.key --export 'admin@hyperion-project.org' - cp debian/distributions apt/conf/distributions - - - name: Create initial structure/packages files and symbolic links - run: | - reprepro -Vb apt createsymlinks - reprepro -Vb apt export - - - name: Download artifacts - uses: actions/download-artifact@v3.0.2 - - - name: Include artifacts into the package source - run: | - for file in artifact/hyperion_*.deb; do - if [ -f "$file" ]; then - dist=${file#*~} - dist=${dist%_*} - reprepro -Vb apt/ includedeb "$dist" "$file" - fi - done - - - name: Upload packages to APT server (DRAFT) - uses: SamKirkland/FTP-Deploy-Action@v4.3.4 - with: - server: apt.hyperion-project.org - username: ${{ secrets.APT_USER }} - password: ${{ secrets.APT_PASSWORD }} - local-dir: "./apt/" - server-dir: ${{ secrets.APT_DRAFT }} - dangerous-clean-slate: true diff --git a/.github/workflows/apt/amd64.json b/.github/workflows/apt/amd64.json deleted file mode 100644 index ecfa56c3a..000000000 --- a/.github/workflows/apt/amd64.json +++ /dev/null @@ -1,58 +0,0 @@ -[ - { - "distribution": "Focal", - "architecture": "amd64", - "build-depends": "git, cmake, build-essential, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, libqt5x11extras5-dev, libusb-1.0-0-dev, python3-dev, libcec-dev, libxcb-image0-dev, libxcb-util0-dev, libxcb-shm0-dev, libxcb-render0-dev, libxcb-randr0-dev, libxrandr-dev, libxrender-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libssl-dev, libmbedtls-dev", - "package-depends": "libpython3.8, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls12, libasound2, libturbojpeg, libcec4", - "cmake-environment": "-DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Ubuntu 20.04 (Focal Fossa) (amd64)" - }, - { - "distribution": "Jammy", - "architecture": "amd64", - "build-depends": "git, cmake, build-essential, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, libqt5x11extras5-dev, libusb-1.0-0-dev, python3-dev, libcec-dev, libxcb-image0-dev, libxcb-util0-dev, libxcb-shm0-dev, libxcb-render0-dev, libxcb-randr0-dev, libxrandr-dev, libxrender-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libssl-dev, libmbedtls-dev", - "package-depends": "libpython3.10, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls14, libasound2, libturbojpeg, libcec6", - "cmake-environment": "-DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Ubuntu 22.04 (Jammy Jellyfish) (amd64)" - }, - { - "distribution": "Kinetic", - "architecture": "amd64", - "build-depends": "git, cmake, build-essential, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, libqt5x11extras5-dev, libusb-1.0-0-dev, python3-dev, libcec-dev, libxcb-image0-dev, libxcb-util0-dev, libxcb-shm0-dev, libxcb-render0-dev, libxcb-randr0-dev, libxrandr-dev, libxrender-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libssl-dev, libmbedtls-dev", - "package-depends": "libpython3.10, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls14, libasound2, libturbojpeg, libcec6", - "cmake-environment": "-DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Ubuntu 22.10 (Kinetic Kudu) (amd64)" - }, - { - "distribution": "Lunar", - "architecture": "amd64", - "build-depends": "git, cmake, build-essential, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, libqt5x11extras5-dev, libusb-1.0-0-dev, python3-dev, libcec-dev, libxcb-image0-dev, libxcb-util0-dev, libxcb-shm0-dev, libxcb-render0-dev, libxcb-randr0-dev, libxrandr-dev, libxrender-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libssl-dev, libmbedtls-dev", - "package-depends": "libpython3.11, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls14, libasound2, libturbojpeg, libcec6", - "cmake-environment": "-DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Ubuntu 23.04 (Lunar Lobster) (amd64)" - }, - { - "distribution": "Buster", - "architecture": "amd64", - "build-depends": "git, cmake, build-essential, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, libqt5x11extras5-dev, libusb-1.0-0-dev, python3-dev, libcec-dev, libxcb-image0-dev, libxcb-util0-dev, libxcb-shm0-dev, libxcb-render0-dev, libxcb-randr0-dev, libxrandr-dev, libxrender-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libssl-dev, libmbedtls-dev", - "package-depends": "libpython3.7, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls12, libasound2, libturbojpeg0, libcec4", - "cmake-environment": "-DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Debian 10.x (Buster) (amd64)" - }, - { - "distribution": "Bullseye", - "architecture": "amd64", - "build-depends": "git, cmake, build-essential, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, libqt5x11extras5-dev, libusb-1.0-0-dev, python3-dev, libcec-dev, libxcb-image0-dev, libxcb-util0-dev, libxcb-shm0-dev, libxcb-render0-dev, libxcb-randr0-dev, libxrandr-dev, libxrender-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libssl-dev, libmbedtls-dev", - "package-depends": "libpython3.9, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls12, libasound2, libturbojpeg0, libcec6", - "cmake-environment": "-DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Debian 11.x (Bullseye) (amd64)" - }, - { - "distribution": "Bookworm", - "architecture": "amd64", - "build-depends": "git, cmake, build-essential, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, libqt5x11extras5-dev, libusb-1.0-0-dev, python3-dev, libcec-dev, libxcb-image0-dev, libxcb-util0-dev, libxcb-shm0-dev, libxcb-render0-dev, libxcb-randr0-dev, libxrandr-dev, libxrender-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libssl-dev, libmbedtls-dev", - "package-depends": "libpython3.11, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls14, libasound2, libturbojpeg0, libcec6", - "cmake-environment": "-DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Debian 12.x (Bookworm) (amd64)" - } -] diff --git a/.github/workflows/apt/arm64.json b/.github/workflows/apt/arm64.json deleted file mode 100644 index 8cf6325ea..000000000 --- a/.github/workflows/apt/arm64.json +++ /dev/null @@ -1,51 +0,0 @@ -[ - { - "distribution": "Focal", - "architecture": "arm64", - "build-depends": "git, cmake, build-essential, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, libqt5x11extras5-dev, libusb-1.0-0-dev, python3-dev, libcec-dev, libxcb-image0-dev, libxcb-util0-dev, libxcb-shm0-dev, libxcb-render0-dev, libxcb-randr0-dev, libxrandr-dev, libxrender-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libssl-dev, libmbedtls-dev", - "package-depends": "libpython3.8, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls12, libasound2, libturbojpeg, libcec4", - "cmake-environment": "-DENABLE_DISPMANX=OFF -DENABLE_X11=ON -DENABLE_XCB=ON -DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Ubuntu 20.04 (Focal Fossa) (arm64)" - }, - { - "distribution": "Jammy", - "architecture": "arm64", - "build-depends": "git, cmake, build-essential, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, libqt5x11extras5-dev, libusb-1.0-0-dev, python3-dev, libcec-dev, libxcb-image0-dev, libxcb-util0-dev, libxcb-shm0-dev, libxcb-render0-dev, libxcb-randr0-dev, libxrandr-dev, libxrender-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libssl-dev, libmbedtls-dev", - "package-depends": "libpython3.10, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls14, libasound2, libturbojpeg, libcec6", - "cmake-environment": "-DENABLE_DISPMANX=OFF -DENABLE_X11=ON -DENABLE_XCB=ON -DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Ubuntu 22.04 (Jammy Jellyfish) (arm64)" - }, - { - "distribution": "Kinetic", - "architecture": "arm64", - "build-depends": "git, cmake, build-essential, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, libqt5x11extras5-dev, libusb-1.0-0-dev, python3-dev, libcec-dev, libxcb-image0-dev, libxcb-util0-dev, libxcb-shm0-dev, libxcb-render0-dev, libxcb-randr0-dev, libxrandr-dev, libxrender-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libssl-dev, libmbedtls-dev", - "package-depends": "libpython3.10, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls14, libasound2, libturbojpeg, libcec6", - "cmake-environment": "-DENABLE_DISPMANX=OFF -DENABLE_X11=ON -DENABLE_XCB=ON -DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Ubuntu 22.10 (Kinetic Kudu) (arm64)" - }, - { - "distribution": "Buster", - "architecture": "arm64", - "build-depends": "git, cmake, python3-dev, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, build-essential, libusb-1.0-0-dev, libcec-dev, libssl-dev, libraspberrypi-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libmbedtls-dev", - "package-depends": "libpython3.7, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls12, libasound2, libturbojpeg0, libcec4", - "cmake-environment": "-DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Debian 10.x (Buster) (arm64)" - }, - { - "distribution": "Bullseye", - "architecture": "arm64", - "build-depends": "git, cmake, python3-dev, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, build-essential, libusb-1.0-0-dev, libcec-dev, libssl-dev, libraspberrypi-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libmbedtls-dev", - "package-depends": "libpython3.9, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls12, libasound2, libturbojpeg0, libcec6", - "cmake-environment": "-DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Debian 11.x (Bullseye) (arm64)" - }, - { - "distribution": "Bookworm", - "architecture": "arm64", - "build-depends": "git, cmake, python3-dev, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, build-essential, libusb-1.0-0-dev, libcec-dev, libssl-dev, libraspberrypi-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libmbedtls-dev", - "package-depends": "libpython3.11, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls14, libasound2, libturbojpeg0, libcec6", - "cmake-environment": "-DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Debian 12.x (Bookworm) (arm64)", - "exclude" : true - } -] diff --git a/.github/workflows/apt/armhf.json b/.github/workflows/apt/armhf.json deleted file mode 100644 index ed4b9b4de..000000000 --- a/.github/workflows/apt/armhf.json +++ /dev/null @@ -1,51 +0,0 @@ -[ - { - "distribution": "Focal", - "architecture": "armhf", - "build-depends": "git, cmake, build-essential, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, libqt5x11extras5-dev, libusb-1.0-0-dev, python3-dev, libcec-dev, libxcb-image0-dev, libxcb-util0-dev, libxcb-shm0-dev, libxcb-render0-dev, libxcb-randr0-dev, libxrandr-dev, libxrender-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libssl-dev, libmbedtls-dev", - "package-depends": "libpython3.8, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls12, libasound2, libturbojpeg, libcec4", - "cmake-environment": "-DENABLE_DISPMANX=OFF -DENABLE_X11=ON -DENABLE_XCB=ON -DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Ubuntu 20.04 (Focal Fossa) (armhf)" - }, - { - "distribution": "Jammy", - "architecture": "armhf", - "build-depends": "git, cmake, build-essential, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, libqt5x11extras5-dev, libusb-1.0-0-dev, python3-dev, libcec-dev, libxcb-image0-dev, libxcb-util0-dev, libxcb-shm0-dev, libxcb-render0-dev, libxcb-randr0-dev, libxrandr-dev, libxrender-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libssl-dev, libmbedtls-dev", - "package-depends": "libpython3.10, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls14, libasound2, libturbojpeg, libcec6", - "cmake-environment": "-DENABLE_DISPMANX=OFF -DENABLE_X11=ON -DENABLE_XCB=ON -DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Ubuntu 22.04 (Jammy Jellyfish) (armhf)" - }, - { - "distribution": "Kinetic", - "architecture": "armhf", - "build-depends": "git, cmake, build-essential, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, libqt5x11extras5-dev, libusb-1.0-0-dev, python3-dev, libcec-dev, libxcb-image0-dev, libxcb-util0-dev, libxcb-shm0-dev, libxcb-render0-dev, libxcb-randr0-dev, libxrandr-dev, libxrender-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libssl-dev, libmbedtls-dev", - "package-depends": "libpython3.10, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls14, libasound2, libturbojpeg, libcec6", - "cmake-environment": "-DENABLE_DISPMANX=OFF -DENABLE_X11=ON -DENABLE_XCB=ON -DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Ubuntu 22.10 (Kinetic Kudu) (armhf)" - }, - { - "distribution": "Buster", - "architecture": "armhf", - "build-depends": "git, cmake, python3-dev, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, build-essential, libusb-1.0-0-dev, libcec-dev, libssl1.0-dev, libraspberrypi-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libmbedtls-dev", - "package-depends": "libpython3.7, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls12, libasound2, libturbojpeg0, libcec4", - "cmake-environment": "-DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Debian 10.x (Buster) (armhf)" - }, - { - "distribution": "Bullseye", - "architecture": "armhf", - "build-depends": "git, cmake, python3-dev, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, build-essential, libusb-1.0-0-dev, libcec-dev, libssl-dev, libraspberrypi-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libmbedtls-dev", - "package-depends": "libpython3.9, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls12, libasound2, libturbojpeg0, libcec6", - "cmake-environment": "-DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Debian 11.x (Bullseye) (armhf)" - }, - { - "distribution": "Bookworm", - "architecture": "armhf", - "build-depends": "git, cmake, python3-dev, qtbase5-dev, libqt5serialport5-dev, libqt5sql5-sqlite, libqt5svg5-dev, build-essential, libusb-1.0-0-dev, libcec-dev, libssl-dev, libraspberrypi-dev, libasound2-dev, libturbojpeg0-dev, libjpeg-dev, libmbedtls-dev", - "package-depends": "libpython3.11, libusb-1.0-0, libqt5widgets5, libqt5x11extras5, libqt5sql5, libqt5sql5-sqlite, libqt5serialport5, libmbedtls14, libasound2, libturbojpeg0, libcec6", - "cmake-environment": "-DUSE_SYSTEM_MBEDTLS_LIBS=ON -DENABLE_DEPLOY_DEPENDENCIES=OFF -DCMAKE_BUILD_TYPE=Release", - "description": "Debian 12.x (Bookworm) (armhf)", - "exclude" : true - } -] diff --git a/.github/workflows/cleanup.yml b/.github/workflows/cleanup.yml index 95ab9fd70..48c42fb04 100644 --- a/.github/workflows/cleanup.yml +++ b/.github/workflows/cleanup.yml @@ -1,4 +1,4 @@ -name: Clean artifacts +name: ๐Ÿงน Cleanup old artifacts # Run cleanup workflow at the end of every day on: @@ -9,7 +9,7 @@ jobs: clean: runs-on: ubuntu-latest steps: - - name: cleanup + - name: ๐Ÿงน Cleanup old workflow artifacts uses: kolpav/purge-artifacts-action@v1 with: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d39190cc7..9ed683698 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,4 +1,8 @@ -name: "CodeQL" +name: ๐Ÿ“Š CodeQL +run-name: | + ${{ github.event_name == 'schedule' && 'โฐ Scheduled CodeQL run' || '' }} + ${{ github.event_name == 'push' && format('๐Ÿ“Š Pushed CodeQL run - {0}', github.event.head_commit.message) || '' }} + ${{ github.event_name == 'pull_request' && format('๐Ÿ“Š CodeQL run for PR {0} - {1}', github.event.pull_request.number, github.event.pull_request.title) || github.event.head_commit.message }} on: push: @@ -10,7 +14,7 @@ on: jobs: analyze: - name: Analyze + name: ๐Ÿ“Š Analyze runs-on: ubuntu-latest permissions: actions: read @@ -23,35 +27,35 @@ jobs: language: [ python, javascript, cpp ] steps: - - name: Checkout + - name: โฌ‡ Checkout uses: actions/checkout@v4 with: submodules: recursive - - name: Install Packages (cpp) + - name: ๐Ÿ“ฅ Install Packages (cpp) if: ${{ matrix.language == 'cpp' }} run: | sudo apt-get update sudo apt-get install --yes git cmake build-essential qtbase5-dev libqt5serialport5-dev libqt5sql5-sqlite libqt5svg5-dev libqt5x11extras5-dev libusb-1.0-0-dev python3-dev libcec-dev libxcb-image0-dev libxcb-util0-dev libxcb-shm0-dev libxcb-render0-dev libxcb-randr0-dev libxrandr-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libasound2-dev libturbojpeg0-dev libjpeg-dev libssl-dev - - name: Initialize CodeQL + - name: ๐Ÿ” Initialize CodeQL uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} queries: +security-and-quality config-file: ./.github/config/codeql.yml - - name: Autobuild + - name: ๐Ÿ‘ท Autobuild uses: github/codeql-action/autobuild@v2 - - name: Perform CodeQL Analysis + - name: ๐Ÿƒ Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: category: "/language:${{ matrix.language }}" upload: False output: sarif-results - - name: Filter SARIF + - name: ๐Ÿ†” Filter SARIF uses: advanced-security/filter-sarif@v1 with: patterns: | @@ -63,11 +67,12 @@ jobs: input: sarif-results/${{ matrix.language }}.sarif output: sarif-results/${{ matrix.language }}.sarif - - name: Upload SARIF + - name: ๐Ÿ“ฆ Upload SARIF uses: github/codeql-action/upload-sarif@v2 with: sarif_file: sarif-results/${{ matrix.language }}.sarif - - name: Upload loc as a Build Artifact + + - name: ๐Ÿ“ฆ Upload loc as a Build Artifact uses: actions/upload-artifact@v3 with: name: sarif-results diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml deleted file mode 100644 index 2046ba07a..000000000 --- a/.github/workflows/nightly.yml +++ /dev/null @@ -1,187 +0,0 @@ -name: Nightly build - -# Create nightly builds at the end of every day -on: - schedule: - - cron: '0 0 * * *' - repository_dispatch: - types: [hyperion_nightly_push] - -jobs: - update: - name: Update Submodule rpi_ws281x - if: github.repository_owner == 'hyperion-project' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - fetch-depth: 0 - submodules: recursive - - - name: Update Submodule rpi_ws281x - id: update - run: git submodule update --remote --recursive dependencies/external/rpi_ws281x - - - name: Check git status - id: status - run: echo "status=$(git status -s)" >> $GITHUB_OUTPUT - - - name: Add and commit changes - if: ${{ steps.status.outputs.status }} - run: | - git config --local user.email "20935312+Hyperion-Bot@users.noreply.github.com" - git config --local user.name "Hyperion-Bot" - git config --local diff.ignoreSubmodules dirty - git commit -am "Update submodule rpi_ws281x" - - - name: Push changes - if: ${{ steps.status.outputs.status }} - uses: ad-m/github-push-action@master - with: - github_token: ${{ secrets.HYPERION_BOT_TOKEN }} - branch: ${{ github.ref }} - - check: - name: Compare local <-> nightly - needs: [update] - if: github.repository_owner == 'hyperion-project' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Check if commit has changed - id: build-necessary - run: | - if wget --spider "https://nightly.apt.hyperion-project.org/$(git rev-parse --short HEAD)" 2>/dev/null; then - echo "commit-has-changed=false" >> $GITHUB_OUTPUT - else - echo "commit-has-changed=true" >> $GITHUB_OUTPUT - fi - outputs: - build-nightly: ${{ steps.build-necessary.outputs.commit-has-changed }} - - setup: - name: Setup nightly build - needs: [check] - if: ${{ needs.check.outputs.build-nightly == 'true' }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set nightly matrix - id: nightly-ppa - run: | - NIGHTLY=$(jq -n '.include |= [ inputs[] | select(.["exclude"] != true)]' .github/workflows/apt/*.json --compact-output) - echo "nightly=$NIGHTLY" >> $GITHUB_OUTPUT - - outputs: - nightly-matrix: ${{ steps.nightly-ppa.outputs.nightly }} - - build: - name: ${{ matrix.description }} - needs: [setup] - runs-on: ubuntu-latest - strategy: - matrix: ${{ fromJson(needs.setup.outputs.nightly-matrix) }} - - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Generate environment variables - run: | - echo "$(tr -d '\n' < .version)+nightly$(date '+%Y%m%d')$(git rev-parse --short HEAD)" > .version - VERSION=$(cat .version) - echo VERSION=${VERSION} >> $GITHUB_ENV - if [[ $VERSION == *"-"* ]]; then - echo STANDARDS_VERSION=$(echo ${VERSION%-*}) >> $GITHUB_ENV - echo TARBALL_VERSION=$(echo ${VERSION%-*}) >> $GITHUB_ENV - echo DEBIAN_FORMAT='3.0 (quilt)' >> $GITHUB_ENV - else - echo STANDARDS_VERSION=$(echo ${VERSION%+*}) >> $GITHUB_ENV - echo TARBALL_VERSION=${VERSION}~$(echo ${{ matrix.distribution }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV - echo DEBIAN_FORMAT='3.0 (native)' >> $GITHUB_ENV - fi - echo DISTRIBUTION=$(echo ${{ matrix.distribution }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV - - - name: Build package - shell: bash - run: | - mkdir -p "${GITHUB_WORKSPACE}/deploy" - docker run --rm \ - -v "${GITHUB_WORKSPACE}/deploy:/deploy" \ - -v "${GITHUB_WORKSPACE}:/source:rw" \ - ghcr.io/hyperion-project/${{ matrix.architecture }}:${{ env.DISTRIBUTION }} \ - /bin/bash -c "cd /source && \ - mkdir -p debian/source && echo '${{ env.DEBIAN_FORMAT }}' > debian/source/format && \ - dch --create --distribution ${{ env.DISTRIBUTION }} --package 'hyperion' -v '${{ env.VERSION }}~${{ env.DISTRIBUTION }}' '${{ github.event.commits[0].message }}' && \ - cp -fr LICENSE debian/copyright && \ - sed 's/@BUILD_DEPENDS@/${{ matrix.build-depends }}/g; s/@DEPENDS@/${{ matrix.package-depends }}/g; s/@ARCHITECTURE@/${{ matrix.architecture }}/g; s/@STANDARDS_VERSION@/${{ env.STANDARDS_VERSION }}/g' debian/control.in > debian/control && \ - sed 's/@CMAKE_ENVIRONMENT@/${{ matrix.cmake-environment }}/g' debian/rules.in > debian/rules && \ - tar -cJf ../hyperion_${{ env.TARBALL_VERSION }}.orig.tar.xz . && \ - debuild --no-lintian -uc -us && \ - cp ../hyperion_*.deb /deploy" - - - name: Upload package artifact - uses: actions/upload-artifact@v3 - with: - path: deploy - retention-days: 1 - - publish: - name: Publish nightly packages - needs: [setup, build] - if: github.repository_owner == 'hyperion-project' - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Import GPG key - uses: crazy-max/ghaction-import-gpg@v6.0.0 - with: - gpg_private_key: ${{ secrets.APT_GPG }} - - - name: Install reprepro - run: sudo apt -y install reprepro - - - name: Make build folders, export public GPG key, copy distributions file and create short sha file for nightly build check - run: | - mkdir -p nightly/{conf,dists,db} - gpg --armor --output nightly/hyperion.pub.key --export 'admin@hyperion-project.org' - cp debian/distributions nightly/conf/distributions - touch "nightly/$(git rev-parse --short HEAD)" - - - name: Create initial structure/packages files and symbolic links - run: | - reprepro -Vb nightly createsymlinks - reprepro -Vb nightly export - - - name: Download artifacts - uses: actions/download-artifact@v3.0.2 - - - name: Include artifacts into the package source - run: | - for file in artifact/*.deb; do - if [ -f "$file" ]; then - dist=${file#*~} - dist=${dist%_*} - reprepro -Vb nightly/ includedeb "$dist" "$file" - fi - done - - - name: Upload packages to nightly server - uses: SamKirkland/FTP-Deploy-Action@v4.3.4 - with: - server: nightly.apt.hyperion-project.org - username: ${{ secrets.NIGHTLY_USER }} - password: ${{ secrets.NIGHTLY_PASSWORD }} - local-dir: "./nightly/" - server-dir: "./" - dangerous-clean-slate: true - - - name: Remove intermediate artifacts - uses: geekyeggo/delete-artifact@v2 - with: - name: artifact - failOnError: false diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml deleted file mode 100644 index eee7c150a..000000000 --- a/.github/workflows/pull-request.yml +++ /dev/null @@ -1,193 +0,0 @@ -name: Hyperion PR Build -on: - pull_request: - branches: - - master - -jobs: - -###################### -###### Linux ######### -###################### - - Linux: - name: ${{ matrix.dockerName }} - runs-on: ubuntu-latest - strategy: - matrix: - dockerImage: [ x86_64, armv6l, armv7l, aarch64 ] - include: - - dockerImage: x86_64 - dockerName: Debian Buster (x86_64) - platform: x11 - - dockerImage: armv6l - dockerName: Debian Buster (Raspberry Pi v1 & ZERO) - platform: rpi - - dockerImage: armv7l - dockerName: Debian Buster (Raspberry Pi 2 & 3) - platform: rpi - - dockerImage: aarch64 - dockerName: Debian Buster (Generic AARCH64) - platform: amlogic - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive - - # Append PR number to .version - - name: Append PR number to version - shell: bash - run: | - tr -d '\n' < .version > temp && mv temp .version - echo -n "+PR${{ github.event.pull_request.number }}" >> .version - - # Build packages - - name: Build packages - env: - DOCKER_IMAGE: ${{ matrix.dockerImage }} - DOCKER_TAG: buster - DOCKER_NAME: ${{ matrix.dockerName }} - PLATFORM: ${{ matrix.platform }} - shell: bash - run: ./.ci/ci_build.sh - - # Collecting deployable artifacts - - name: Collecting deployable artifacts - shell: bash - run: | - mkdir -p ${{ matrix.dockerImage }} - mv deploy/*.tar.gz ${{ matrix.dockerImage }} - - # Upload artifacts - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: ${{ matrix.dockerImage }} - path: ${{ matrix.dockerImage }} - -###################### -###### macOS ######### -###################### - - macOS: - name: macOS - runs-on: macos-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive - - # Append PR number to .version - - name: Append PR number to version - shell: bash - run: | - tr -d '\n' < .version > temp && mv temp .version - echo -n "+PR${{ github.event.pull_request.number }}" >> .version - - # Install dependencies - - name: Install dependencies - shell: bash - run: ./.ci/ci_install.sh - - # Build packages - - name: Build packages - env: - PLATFORM: osx - shell: bash - run: ./.ci/ci_build.sh - - # Collecting deployable artifacts - - name: Collecting deployable artifacts - shell: bash - run: | - mkdir -p macOS - mv build/*.dmg macOS - - # Upload artifacts - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: macOS - path: macOS - -###################### -###### Windows ####### -###################### - - windows: - name: Windows - runs-on: windows-2022 - env: - VCINSTALLDIR: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC' - QT_VERSION: 5.15.2 - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive - - # Append PR number to .version - - name: Append PR number to version - shell: bash - run: | - tr -d '\n' < .version > temp && mv temp .version - echo -n "+PR${{ github.event.pull_request.number }}" >> .version - - - name: Install Qt - uses: jurplel/install-qt-action@v3 - with: - version: ${{env.QT_VERSION}} - target: 'desktop' - arch: 'win64_msvc2019_64' - cache: 'true' - cache-key-prefix: 'cache-qt-windows' - - - name: Cache Chocolatey downloads - uses: actions/cache@v3 - with: - path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey - key: ${{ runner.os }}-chocolatey - -# - name: Install Python -# shell: powershell -# run: | -# choco install --no-progress python -y - - - name: Install OpenSSL, DirectX SDK - shell: powershell - run: | - choco install --no-progress openssl --version=1.1.1.2100 -y - choco install --no-progress directx-sdk -y - - - name: Install libjpeg-turbo - run: | - Invoke-WebRequest https://netcologne.dl.sourceforge.net/project/libjpeg-turbo/2.0.6/libjpeg-turbo-2.0.6-vc64.exe -OutFile libjpeg-turbo.exe -UserAgent NativeHost - .\libjpeg-turbo /S - - - name: Set up x64 build architecture environment - shell: cmd - run: call "${{env.VCINSTALLDIR}}\Auxiliary\Build\vcvars64.bat" - - # Build packages - - name: Build packages - env: - PLATFORM: windows - shell: bash - run: ./.ci/ci_build.sh - - # Collecting deployable artifacts - - name: Collecting deployable artifacts - shell: bash - run: | - mkdir -p windows - mv build/*.exe windows - - # Upload artifacts - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: windows - path: windows diff --git a/.github/workflows/push-master.yml b/.github/workflows/push-master.yml deleted file mode 100644 index b0ee7a1d8..000000000 --- a/.github/workflows/push-master.yml +++ /dev/null @@ -1,201 +0,0 @@ -name: Hyperion CI Build -on: - push: - branches: - - '**' - tags: - - '*' - -jobs: - -################### -###### Linux ###### -################### - - Linux: - name: ${{ matrix.dockerName }} - runs-on: ubuntu-latest - strategy: - matrix: - dockerImage: [ x86_64, armv6l, armv7l, aarch64 ] - include: - - dockerImage: x86_64 - dockerName: Debian Buster (x86_64) - platform: x11 - - dockerImage: armv6l - dockerName: Debian Buster (Raspberry Pi v1 & ZERO) - platform: rpi - - dockerImage: armv7l - dockerName: Debian Buster (Raspberry Pi 2 & 3) - platform: rpi - - dockerImage: aarch64 - dockerName: Debian Buster (Generic AARCH64) - platform: amlogic - - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - # Build process - - name: Build packages - env: - DOCKER_IMAGE: ${{ matrix.dockerImage }} - DOCKER_TAG: buster - DOCKER_NAME: ${{ matrix.dockerName }} - PLATFORM: ${{ matrix.platform }} - shell: bash - run: ./.ci/ci_build.sh - - # Upload artifacts (only on tagged commit) - - name: Upload artifacts - if: startsWith(github.event.ref, 'refs/tags') - uses: actions/upload-artifact@v3 - with: - path: deploy/Hyperion-* - -################### -###### macOS ###### -################### - - macOS: - name: macOS - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - # Install dependencies - - name: Install dependencies - shell: bash - run: ./.ci/ci_install.sh - - # Build process - - name: Build packages - env: - PLATFORM: osx - shell: bash - run: ./.ci/ci_build.sh - - # Upload artifacts (only on tagged commit) - - name: Upload artifacts - if: startsWith(github.event.ref, 'refs/tags') - uses: actions/upload-artifact@v3 - with: - path: build/Hyperion-* - -##################### -###### Windows ###### -##################### - - windows: - name: Windows - runs-on: windows-2022 - env: - VCINSTALLDIR: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC' - QT_VERSION: 5.15.2 - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install Qt - uses: jurplel/install-qt-action@v3 - with: - version: ${{env.QT_VERSION}} - target: 'desktop' - arch: 'win64_msvc2019_64' - cache: 'true' - cache-key-prefix: 'cache-qt-windows' - - - name: Cache Chocolatey downloads - uses: actions/cache@v3 - with: - path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey - key: ${{ runner.os }}-chocolatey - -# - name: Install Python -# shell: powershell -# run: | -# choco install --no-progress python -y - - - name: Install OpenSSL, DirectX SDK - shell: powershell - run: | - choco install --no-progress openssl --version=1.1.1.2100 -y - choco install --no-progress directx-sdk -y - - - name: Install libjpeg-turbo - run: | - Invoke-WebRequest https://netcologne.dl.sourceforge.net/project/libjpeg-turbo/2.0.6/libjpeg-turbo-2.0.6-vc64.exe -OutFile libjpeg-turbo.exe -UserAgent NativeHost - .\libjpeg-turbo /S - - - name: Set up x64 build architecture environment - shell: cmd - run: call "${{env.VCINSTALLDIR}}\Auxiliary\Build\vcvars64.bat" - - # Build packages - - name: Build packages - env: - PLATFORM: windows - shell: bash - run: ./.ci/ci_build.sh - - # Upload artifacts (only on tagged commit) - - name: Upload artifacts - if: startsWith(github.event.ref, 'refs/tags') - uses: actions/upload-artifact@v3 - with: - path: build/Hyperion-* - retention-days: 1 - -##################################### -###### Publish GitHub Releases ###### -##################################### - - github_publish: - name: Publish GitHub Releases - if: startsWith(github.event.ref, 'refs/tags') - needs: [Linux, macOS, windows] - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - # Generate environment variables - - name: Generate environment variables from .version and tag - run: | - echo "TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV - echo "VERSION=$(tr -d '\n' < .version)" >> $GITHUB_ENV - - # Download artifacts from previous build process - - name: Download artifacts - uses: actions/download-artifact@v3.0.2 - with: - path: artifacts - - # Create draft release and upload artifacts - - name: Create draft release - uses: softprops/action-gh-release@v1 - with: - name: Hyperion ${{ env.VERSION }} - tag_name: ${{ env.TAG }} - files: "artifacts/**" - draft: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - -########################## -###### APT workflow ###### -########################## - - apt_build: - name: APT Build GitHub Releases - if: startsWith(github.event.ref, 'refs/tags') - needs: [Linux, macOS, windows] - uses: ./.github/workflows/apt.yml - secrets: inherit - with: - head_sha: master diff --git a/.github/workflows/push_pull.yml b/.github/workflows/push_pull.yml new file mode 100644 index 000000000..add2c9440 --- /dev/null +++ b/.github/workflows/push_pull.yml @@ -0,0 +1,49 @@ +name: Hyperion CI/PR Builds +run-name: | + ${{ github.event_name == 'push' && '๐ŸŒฑ Push build -' || '' }} + ${{ github.event_name == 'pull_request' && format('๐Ÿ“ฆ Artifacts build for PR {0} - {1}', github.event.pull_request.number, github.event.pull_request.title) || github.event.head_commit.message }} + +on: + push: + branches: + - '**' + tags: + - '*' + pull_request: + branches: + - 'master' + +jobs: + + # GitHub Push/Pull Request (Release only on tagged commits) + github_build: + name: Qt ${{ matrix.qt_version }} Build ${{ matrix.qt_version == '6' && '(Testing))' || '' }} + strategy: + fail-fast: false + matrix: + qt_version: ['5', '6'] + uses: ./.github/workflows/qt5_6.yml + secrets: inherit + with: + qt_version: ${{ matrix.qt_version }} + event_name: ${{ github.event_name }} + pull_request_number: ${{ github.event.pull_request.number }} + publish: ${{ startsWith(github.event.ref, 'refs/tags') }} + + # Build DEB/RPM Packages for APT/DNF Repository (runs only on tagged commits) + repo_build: + name: ๐Ÿš€ Let Hyperion build its own repository (APT/DNF) + if: startsWith(github.event.ref, 'refs/tags') + needs: [ github_build ] + runs-on: ubuntu-latest + steps: + - name: ๐Ÿ“ฒ Dispatch APT/DNF build + if: ${{ env.SECRET_HYPERION_BOT_TOKEN != null }} + uses: peter-evans/repository-dispatch@v2.1.2 + with: + repository: hyperion-project/hyperion.releases-ci + token: ${{ secrets.HYPERION_BOT_TOKEN }} + event-type: releases_repo_build + client-payload: '{ "head_sha": "${{ github.sha }}" }' + env: + SECRET_HYPERION_BOT_TOKEN: ${{ secrets.HYPERION_BOT_TOKEN }} diff --git a/.github/workflows/qt5_6.yml b/.github/workflows/qt5_6.yml new file mode 100644 index 000000000..ac4622b34 --- /dev/null +++ b/.github/workflows/qt5_6.yml @@ -0,0 +1,250 @@ +name: GitHub Qt5/6 Builds + +on: + # Reusable from push_pull.yml + workflow_call: + inputs: + qt_version: + type: string + description: Build with this Qt version + default: '5' + required: false + event_name: + type: string + description: The event name + default: '' + required: false + pull_request_number: + type: string + description: The corresponding PR number + default: '' + required: false + publish: + type: boolean + description: Package publishing + default: false + required: false + +env: + ghcr: hyperion-project + +jobs: + +###################### +###### Linux ######### +###################### + + Linux: + name: ๐Ÿง ${{ matrix.os.description }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + os: [ + { distribution: debian, codename: buster, description: Debian Buster (x86_64), architecture: [ amd64, linux/amd64 ] }, + { distribution: debian, codename: bullseye, description: Debian Bullseye (x86_64), architecture: [ amd64, linux/amd64 ] }, + { distribution: debian, codename: buster, description: Debian Buster (Raspberry Pi 1/ZERO), architecture: [ armv6, linux/arm/v5 ] }, + { distribution: debian, codename: buster, description: Debian Buster (Raspberry Pi 2/3/4), architecture: [ armv7, linux/arm/v7 ] }, + { distribution: debian, codename: bullseye, description: Debian Bullseye (Raspberry Pi 2/3/4), architecture: [ armv7, linux/arm/v7 ] }, + { distribution: debian, codename: buster, description: Debian Buster (Generic AARCH64), architecture: [ aarch64, linux/arm64 ] }, + { distribution: debian, codename: bullseye, description: Debian Bullseye (Generic AARCH64), architecture: [ aarch64, linux/arm64 ] } + ] + isQt5: + - ${{ inputs.qt_version == '5' }} + include: + - os.architecture[0]: amd64 + platform: x11 + - os.architecture[0]: armv6 + platform: rpi + - os.architecture[0]: armv7 + platform: rpi + - os.architecture[0]: aarch64 + platform: amlogic + exclude: + - isQt5: true + os: { distribution: debian, codename: bullseye } + - isQt5: false + os: { distribution: debian, codename: buster } + + steps: + - name: โฌ‡ Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: ๐Ÿ”ง Prepare + shell: bash + run: | + echo '::group::Append PR number to version (PR only)' + if [[ "${{ inputs.event_name }}" = "pull_request" ]]; then + tr -d '\n' < .version > temp && mv temp .version + echo -n "+PR${{ inputs.pull_request_number }}" >> .version + fi + echo '::endgroup::' + + - name: ๐Ÿ‘ท Build + shell: bash + run: ./.github/scripts/build.sh + env: + DOCKER_IMAGE: ${{ matrix.os.distribution }} + DOCKER_TAG: ${{ matrix.os.codename }}${{ inputs.qt_version == '6' && '-qt6' || '' }} + PLATFORM: ${{ matrix.platform }} + TARGET_ARCH: ${{ matrix.os.architecture[1] }} + + - name: ๐Ÿ“ฆ Upload + if: ${{ inputs.publish || inputs.event_name == 'pull_request' }} + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.event_name == 'pull_request' && env.NAME || 'artifact' }} + path: ${{ inputs.event_name == 'pull_request' && 'deploy/*.tar.gz' || 'deploy/Hyperion-*' }} + env: + NAME: ${{ format('{0}_{1}_{2}{3}', matrix.os.distribution, matrix.os.codename, matrix.os.architecture[0], inputs.qt_version == '6' && '_qt6' || '') }} + +###################### +###### macOS ######### +###################### + + macOS: + name: ๐Ÿ macOS x64 + runs-on: macos-latest + steps: + - name: โฌ‡ Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: ๐Ÿ”ง Prepare + shell: bash + run: | + echo '::group::Append PR number to version (PR only)' + if [[ "${{ inputs.event_name }}" = "pull_request" ]]; then + tr -d '\n' < .version > temp && mv temp .version + echo -n "+PR${{ inputs.pull_request_number }}" >> .version + fi + echo '::endgroup::' + + echo '::group::Update/Install dependencies' + brew update || true + brew install --overwrite qt${{ inputs.qt_version }} libusb + brew link --overwrite --force qt${{ inputs.qt_version }} + echo '::endgroup::' + + - name: ๐Ÿ‘ท Build + shell: bash + run: ./.github/scripts/build.sh + env: + PLATFORM: osx + + - name: ๐Ÿ“ฆ Upload + if: ${{ inputs.publish || inputs.event_name == 'pull_request' }} + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.event_name == 'pull_request' && env.NAME || 'artifact' }} + path: 'build/Hyperion-*' + env: + NAME: ${{ inputs.qt_version == '6' && 'macOS_x64_qt6' || 'macOS_x64' }} + +###################### +###### Windows ####### +###################### + + windows: + name: ๐ŸชŸ Windows x64 + runs-on: windows-2022 + env: + VCINSTALLDIR: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC' + steps: + - name: โฌ‡ Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: ๐Ÿ”ง Prepare PR + if: ${{ inputs.event_name == 'pull_request' }} + shell: bash + run: | + echo '::group::Append PR number to version' + tr -d '\n' < .version > temp && mv temp .version + echo -n "+PR${{ inputs.pull_request_number }}" >> .version + echo '::endgroup::' + + - name: ๐Ÿ’พ Cache/Restore + uses: actions/cache@v3 + with: + path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey + key: ${{ runner.os }}${{ inputs.qt_version == '6' && '-chocolatey-qt6' || '-chocolatey' }} + + - name: ๐Ÿ“ฅ Install DirectX SDK, OpenSSL, libjpeg-turbo ${{ inputs.qt_version == '6' && 'and Vulkan-SDK' || '' }} + shell: powershell + run: | + choco install --no-progress directx-sdk ${{env.VULKAN_SDK}} -y + choco install --no-progress ${{env.OPENSSL}} -y + Invoke-WebRequest https://netcologne.dl.sourceforge.net/project/libjpeg-turbo/3.0.1/libjpeg-turbo-3.0.1-vc64.exe -OutFile libjpeg-turbo.exe -UserAgent NativeHost + .\libjpeg-turbo /S + env: + VULKAN_SDK: ${{ inputs.qt_version == '6' && 'vulkan-sdk' || '' }} + OPENSSL: ${{ inputs.qt_version == '6' && 'openssl' || 'openssl --version=1.1.1.2100' }} + + - name: ๐Ÿ“ฅ Install Qt + uses: jurplel/install-qt-action@v3 + with: + version: ${{ inputs.qt_version == '6' && '6.5.2' || '5.15.2' }} + target: 'desktop' + modules: ${{ inputs.qt_version == '6' && 'qtserialport' || '' }} + arch: 'win64_msvc2019_64' + cache: 'true' + cache-key-prefix: 'cache-qt-windows' + + - name: ๐Ÿ› ๏ธ Setup MSVC + shell: cmd + run: call "${{env.VCINSTALLDIR}}\Auxiliary\Build\vcvars64.bat" + + - name: ๐Ÿ‘ท Build + shell: bash + run: ./.github/scripts/build.sh + env: + PLATFORM: windows + + - name: ๐Ÿ“ฆ Upload + if: ${{ inputs.publish || inputs.event_name == 'pull_request' }} + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.event_name == 'pull_request' && env.NAME || 'artifact' }} + path: ${{ inputs.event_name == 'pull_request' && 'build/*.exe' || 'build/Hyperion-*' }} + env: + NAME: ${{ inputs.qt_version == '6' && 'windows_x64_qt6' || 'windows_x64' }} + +##################################### +###### Publish GitHub Releases ###### +##################################### + + github_publish: + name: ๐Ÿš€ Publish GitHub Releases + if: ${{ inputs.qt_version == '5' && inputs.publish }} + needs: [Linux, macOS, windows] + runs-on: ubuntu-latest + steps: + - name: โฌ‡ Checkout + uses: actions/checkout@v4 + + - name: ๐Ÿ”ง Prepare + run: | + echo '::group::Generate environment variables from .version and tag' + echo "TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV + echo "VERSION=$(tr -d '\n' < .version)" >> $GITHUB_ENV + echo '::endgroup::' + + - name: ๐Ÿ’พ Artifact download + uses: actions/download-artifact@v3.0.2 + with: + path: artifacts + + - name: ๐Ÿ“ฆ Upload + uses: softprops/action-gh-release@v1 + with: + name: Hyperion ${{ env.VERSION }} + tag_name: ${{ env.TAG }} + files: "artifacts/**" + draft: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 104c2c793..941e07dd9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,15 +1,18 @@ -name: Release Actions +name: ๐Ÿš€ Release Actions +run-name: ๐Ÿš€ Let HyperBian create + on: release: types: [published] jobs: + hyperbian: - name: Let HyperBian create + name: ๐Ÿš€ Let HyperBian create runs-on: ubuntu-latest steps: # Dispatch event to build new HyperBian image - - name: Dispatch HyperBian build + - name: ๐Ÿ“ฒ Dispatch HyperBian build uses: peter-evans/repository-dispatch@v2.1.2 if: ${{ github.repository_owner == 'hyperion-project'}} with: diff --git a/CMakeLists.txt b/CMakeLists.txt index 32bbb7d20..8d88c41e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,17 @@ cmake_minimum_required(VERSION 3.5.0) -message( STATUS "CMake Version: ${CMAKE_VERSION}" ) +message(STATUS "CMake Version: ${CMAKE_VERSION}") macro(addIndent text) -if(${CMAKE_VERSION} VERSION_GREATER "3.16.0") - list(APPEND CMAKE_MESSAGE_INDENT ${text}) -endif() + if(${CMAKE_VERSION} VERSION_GREATER "3.16.0") + list(APPEND CMAKE_MESSAGE_INDENT ${text}) + endif() endmacro() macro(removeIndent) -if(${CMAKE_VERSION} VERSION_GREATER "3.16.0") - list(POP_BACK CMAKE_MESSAGE_INDENT) -endif() + if(${CMAKE_VERSION} VERSION_GREATER "3.16.0") + list(POP_BACK CMAKE_MESSAGE_INDENT) + endif() endmacro() PROJECT(hyperion) @@ -31,9 +31,16 @@ set(CMAKE_AUTOMOC ON) # auto prepare .qrc files set(CMAKE_AUTORCC ON) -# Configure CCache if available +# multicore compiling +include(ProcessorCount) +ProcessorCount(NCORES) +if(NOT NCORES EQUAL 0) + set(CMAKE_BUILD_PARALLEL_LEVEL NCORES) +endif() + +# Configure CCache ifavailable find_program(CCACHE_FOUND ccache) -if ( CCACHE_FOUND ) +if(CCACHE_FOUND) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) endif(CCACHE_FOUND) @@ -58,160 +65,163 @@ set(CMAKE_CXX_EXTENSIONS OFF) # Set build variables # Grabber -SET ( DEFAULT_AMLOGIC OFF ) -SET ( DEFAULT_DISPMANX OFF ) -SET ( DEFAULT_DX OFF ) -SET ( DEFAULT_MF OFF ) -SET ( DEFAULT_OSX OFF ) -SET ( DEFAULT_QT ON ) -SET ( DEFAULT_V4L2 OFF ) -SET ( DEFAULT_AUDIO ON ) -SET ( DEFAULT_X11 OFF ) -SET ( DEFAULT_XCB OFF ) +set(DEFAULT_AMLOGIC OFF) +set(DEFAULT_DISPMANX OFF) +set(DEFAULT_DX OFF) +set(DEFAULT_MF OFF) +set(DEFAULT_OSX OFF) +set(DEFAULT_QT ON ) +set(DEFAULT_V4L2 OFF) +set(DEFAULT_AUDIO ON ) +set(DEFAULT_X11 OFF) +set(DEFAULT_XCB OFF) # Input -SET ( DEFAULT_BOBLIGHT_SERVER ON ) -SET ( DEFAULT_CEC OFF ) -SET ( DEFAULT_FLATBUF_SERVER ON ) -SET ( DEFAULT_PROTOBUF_SERVER ON ) +set(DEFAULT_BOBLIGHT_SERVER ON ) +set(DEFAULT_CEC OFF) +set(DEFAULT_FLATBUF_SERVER ON ) +set(DEFAULT_PROTOBUF_SERVER ON ) # Output -SET ( DEFAULT_FORWARDER ON ) -SET ( DEFAULT_FLATBUF_CONNECT ON ) +set(DEFAULT_FORWARDER ON ) +set(DEFAULT_FLATBUF_CONNECT ON ) # LED-Devices -SET ( DEFAULT_DEV_NETWORK ON ) -SET ( DEFAULT_DEV_SERIAL ON ) -SET ( DEFAULT_DEV_SPI OFF ) -SET ( DEFAULT_DEV_TINKERFORGE OFF ) -SET ( DEFAULT_DEV_USB_HID OFF ) -SET ( DEFAULT_DEV_WS281XPWM OFF ) +set(DEFAULT_DEV_NETWORK ON ) +set(DEFAULT_DEV_SERIAL ON ) +set(DEFAULT_DEV_SPI OFF) +set(DEFAULT_DEV_TINKERFORGE OFF) +set(DEFAULT_DEV_USB_HID OFF) +set(DEFAULT_DEV_WS281XPWM OFF) # Services -SET ( DEFAULT_EFFECTENGINE ON ) -SET ( DEFAULT_EXPERIMENTAL OFF ) -SET ( DEFAULT_MDNS ON ) -SET ( DEFAULT_REMOTE_CTL ON ) +set(DEFAULT_EFFECTENGINE ON ) +set(DEFAULT_EXPERIMENTAL OFF) +set(DEFAULT_MDNS ON ) +set(DEFAULT_REMOTE_CTL ON ) # Build -SET ( DEFAULT_JSONCHECKS ON ) -SET ( DEFAULT_DEPLOY_DEPENDENCIES ON ) -SET ( DEFAULT_USE_SYSTEM_FLATBUFFERS_LIBS OFF ) -SET ( DEFAULT_USE_SYSTEM_PROTO_LIBS OFF ) -SET ( DEFAULT_USE_SYSTEM_MBEDTLS_LIBS OFF ) -SET ( DEFAULT_USE_SYSTEM_QMDNS_LIBS OFF ) -SET ( DEFAULT_TESTS OFF ) +set(DEFAULT_JSONCHECKS ON ) +set(DEFAULT_DEPLOY_DEPENDENCIES ON ) +set(DEFAULT_USE_SYSTEM_FLATBUFFERS_LIBS OFF) +set(DEFAULT_USE_SYSTEM_PROTO_LIBS OFF) +set(DEFAULT_USE_SYSTEM_MBEDTLS_LIBS OFF) +set(DEFAULT_USE_SYSTEM_QMDNS_LIBS OFF) +set(DEFAULT_TESTS OFF) # Build Hyperion with a reduced set of functionality, overwrites other default values -SET ( DEFAULT_HYPERION_LIGHT OFF ) - -IF ( ${CMAKE_SYSTEM} MATCHES "Linux" ) - SET ( DEFAULT_FB ON ) - SET ( DEFAULT_V4L2 ON ) - SET ( DEFAULT_DEV_SPI ON ) - SET ( DEFAULT_DEV_TINKERFORGE ON ) - SET ( DEFAULT_DEV_USB_HID ON ) - SET ( DEFAULT_CEC ON ) -ELSEIF ( WIN32 ) - SET ( DEFAULT_DX ON ) - SET ( DEFAULT_MF ON ) -ELSE() - SET ( DEFAULT_FB OFF ) - SET ( DEFAULT_V4L2 OFF ) - SET ( DEFAULT_DEV_SPI OFF ) - SET ( DEFAULT_DEV_TINKERFORGE OFF ) - SET ( DEFAULT_DEV_USB_HID OFF ) - SET ( DEFAULT_CEC OFF ) -ENDIF() - -if ( NOT DEFINED PLATFORM ) - if ( APPLE ) - SET( PLATFORM "osx") - elseif ( WIN32 ) - SET( PLATFORM "windows") - elseif ( "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "x86" ) - SET( PLATFORM "x11") - elseif ( "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm" OR "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "aarch64") - SET( PLATFORM "rpi") - FILE( READ /proc/cpuinfo SYSTEM_CPUINFO ) - STRING ( TOLOWER "${SYSTEM_CPUINFO}" SYSTEM_CPUINFO ) - if ( "${SYSTEM_CPUINFO}" MATCHES "amlogic" AND ${CMAKE_SIZEOF_VOID_P} EQUAL 4 ) - SET( PLATFORM "amlogic" ) - elseif ( ("${SYSTEM_CPUINFO}" MATCHES "amlogic" OR "${SYSTEM_CPUINFO}" MATCHES "odroid-c2" OR "${SYSTEM_CPUINFO}" MATCHES "vero4k") AND ${CMAKE_SIZEOF_VOID_P} EQUAL 8 ) - SET( PLATFORM "amlogic64" ) +set(DEFAULT_HYPERION_LIGHT OFF) + +if(${CMAKE_SYSTEM} MATCHES "Linux") + set(DEFAULT_FB ON) + set(DEFAULT_V4L2 ON) + set(DEFAULT_DEV_SPI ON) + set(DEFAULT_DEV_TINKERFORGE ON) + set(DEFAULT_DEV_USB_HID ON) + set(DEFAULT_CEC ON) +elseif (WIN32) + set(DEFAULT_DX ON) + set(DEFAULT_MF ON) +else() + set(DEFAULT_FB OFF) + set(DEFAULT_V4L2 OFF) + set(DEFAULT_DEV_SPI OFF) + set(DEFAULT_DEV_TINKERFORGE OFF) + set(DEFAULT_DEV_USB_HID OFF) + set(DEFAULT_CEC OFF) +endif() + +if(NOT DEFINED PLATFORM) + if(APPLE) + set(PLATFORM "osx") + elseif (WIN32) + set(PLATFORM "windows") + elseif ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "x86") + set(PLATFORM "x11") + elseif ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm" OR "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "aarch64") + set(PLATFORM "rpi") + file(READ /proc/cpuinfo SYSTEM_CPUINFO) + STRING (TOLOWER "${SYSTEM_CPUINFO}" SYSTEM_CPUINFO) + if("${SYSTEM_CPUINFO}" MATCHES "amlogic" AND ${CMAKE_SIZEOF_VOID_P} EQUAL 4) + set(PLATFORM "amlogic") + elseif (("${SYSTEM_CPUINFO}" MATCHES "amlogic" OR "${SYSTEM_CPUINFO}" MATCHES "odroid-c2" OR "${SYSTEM_CPUINFO}" MATCHES "vero4k") AND ${CMAKE_SIZEOF_VOID_P} EQUAL 8) + set(PLATFORM "amlogic64") endif() endif() - if ( PLATFORM ) - message( STATUS "PLATFORM is not defined, evaluated platform: ${PLATFORM}") + if(PLATFORM) + message(STATUS "PLATFORM is not defined, evaluated platform: ${PLATFORM}") else() - message( FATAL_ERROR "PLATFORM is not defined and could not be evaluated. Set -DPLATFORM=") + message(FATAL_ERROR "PLATFORM is not defined and could not be evaluated. Set -DPLATFORM=") endif() endif() -message( STATUS "PLATFORM: ${PLATFORM}") +message(STATUS "PLATFORM: ${PLATFORM}") # Macro to get path of first sub dir of a dir, used for MAC OSX lib/header searching -MACRO(FIRSTSUBDIR result curdir) - FILE(GLOB children RELATIVE ${curdir} ${curdir}/*) - SET(dirlist "") - FOREACH(child ${children}) - IF(IS_DIRECTORY ${curdir}/${child}) - LIST(APPEND dirlist "${curdir}/${child}") - BREAK() - ENDIF() - ENDFOREACH() - SET(${result} ${dirlist}) -ENDMACRO() - -if ( "${PLATFORM}" MATCHES "osx" ) - # specify the min version of the target platform - SET ( CMAKE_OSX_DEPLOYMENT_TARGET "10.15" ) +macro(FIRSTSUBDIR result curdir) + file(GLOB children RELATIVE ${curdir} ${curdir}/*) + set(dirlist "") + foreach(child ${children}) + if(IS_DIRECTORY ${curdir}/${child}) + list(APPEND dirlist "${curdir}/${child}") + break() + endif() + endforeach() + set(${result} ${dirlist}) +endmacro() + +if("${PLATFORM}" MATCHES "osx") + # specify the min version of the target platform (only GitHub Actions) + if(DEFINED ENV{GITHUB_WORKSPACE}) + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15") + endif() + # add specific prefix paths FIRSTSUBDIR(SUBDIRPY "/usr/local/opt/python3/Frameworks/Python.framework/Versions") set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${SUBDIRPY}) include_directories("/opt/X11/include/") - SET ( DEFAULT_OSX ON ) - SET ( DEFAULT_AUDIO OFF ) - SET ( DEFAULT_DEV_USB_HID ON ) - -elseif ( "${PLATFORM}" MATCHES "rpi" ) - SET ( DEFAULT_DISPMANX ON ) - SET ( DEFAULT_DEV_WS281XPWM ON ) -elseif ( "${PLATFORM}" MATCHES "^amlogic" ) - SET ( DEFAULT_AMLOGIC ON ) - if ( "${PLATFORM}" MATCHES "-dev$" ) - SET ( DEFAULT_AMLOGIC ON ) - SET ( DEFAULT_DISPMANX OFF ) - SET ( DEFAULT_QT OFF ) - SET ( DEFAULT_CEC OFF ) + set(DEFAULT_OSX ON ) + set(DEFAULT_AUDIO OFF) + set(DEFAULT_DEV_USB_HID ON ) + +elseif ("${PLATFORM}" MATCHES "rpi") + set(DEFAULT_DISPMANX ON) + set(DEFAULT_DEV_WS281XPWM ON) +elseif ("${PLATFORM}" MATCHES "^amlogic") + set(DEFAULT_AMLOGIC ON) + if("${PLATFORM}" MATCHES "-dev$") + set(DEFAULT_AMLOGIC ON) + set(DEFAULT_DISPMANX OFF) + set(DEFAULT_QT OFF) + set(DEFAULT_CEC OFF) endif() -elseif ( "${PLATFORM}" MATCHES "^x11" ) - SET ( DEFAULT_X11 ON ) - SET ( DEFAULT_XCB ON ) - if ( "${PLATFORM}" MATCHES "-dev$" ) - SET ( DEFAULT_AMLOGIC ON) - SET ( DEFAULT_DEV_WS281XPWM ON ) +elseif ("${PLATFORM}" MATCHES "^x11") + set(DEFAULT_X11 ON) + set(DEFAULT_XCB ON) + if("${PLATFORM}" MATCHES "-dev$") + set(DEFAULT_AMLOGIC ON) + set(DEFAULT_DEV_WS281XPWM ON) endif() -elseif ( "${PLATFORM}" STREQUAL "imx6" ) - SET ( DEFAULT_FB ON ) +elseif ("${PLATFORM}" STREQUAL "imx6") + set(DEFAULT_FB ON) endif() # enable tests for -dev builds -if ( "${PLATFORM}" MATCHES "-dev$" ) - SET ( DEFAULT_TESTS ON ) +if("${PLATFORM}" MATCHES "-dev$") + set(DEFAULT_TESTS ON) endif() -STRING( TOUPPER "-DPLATFORM_${PLATFORM}" PLATFORM_DEFINE) -STRING( REPLACE "-DEV" "" PLATFORM_DEFINE "${PLATFORM_DEFINE}" ) -ADD_DEFINITIONS( ${PLATFORM_DEFINE} ) +string(TOUPPER "-DPLATFORM_${PLATFORM}" PLATFORM_DEFINE) +string(REPLACE "-DEV" "" PLATFORM_DEFINE "${PLATFORM_DEFINE}") +ADD_DEFINITIONS(${PLATFORM_DEFINE}) # set the build options -option(HYPERION_LIGHT "Build Hyperion with a reduced set of functionality" ${DEFAULT_HYPERION_LIGHT} ) +option(HYPERION_LIGHT "Build Hyperion with a reduced set of functionality" ${DEFAULT_HYPERION_LIGHT}) message(STATUS "HYPERION_LIGHT = ${HYPERION_LIGHT}") -if (HYPERION_LIGHT) +if(HYPERION_LIGHT) message(STATUS "HYPERION_LIGHT: Hyperion is build with a reduced set of functionality.") # Disable Grabbers SET ( DEFAULT_AMLOGIC OFF ) @@ -228,43 +238,43 @@ if (HYPERION_LIGHT) SET ( DEFAULT_AUDIO OFF ) # Disable Input Servers - SET ( DEFAULT_BOBLIGHT_SERVER OFF ) - SET ( DEFAULT_CEC OFF ) - SET ( DEFAULT_FLATBUF_SERVER OFF ) - SET ( DEFAULT_PROTOBUF_SERVER OFF ) + set(DEFAULT_BOBLIGHT_SERVER OFF) + set(DEFAULT_CEC OFF) + set(DEFAULT_FLATBUF_SERVER OFF) + set(DEFAULT_PROTOBUF_SERVER OFF) # Disable Output Connectors - SET ( DEFAULT_FORWARDER OFF ) - SET ( DEFAULT_FLATBUF_CONNECT OFF ) + set(DEFAULT_FORWARDER OFF) + set(DEFAULT_FLATBUF_CONNECT OFF) # Disable Services - SET ( DEFAULT_EFFECTENGINE OFF ) + set(DEFAULT_EFFECTENGINE OFF) endif() message(STATUS "Grabber options:") addIndent(" - ") -option(ENABLE_AMLOGIC "Enable the AMLOGIC video grabber" ${DEFAULT_AMLOGIC} ) +option(ENABLE_AMLOGIC "Enable the AMLOGIC video grabber" ${DEFAULT_AMLOGIC}) message(STATUS "ENABLE_AMLOGIC = ${ENABLE_AMLOGIC}") -option(ENABLE_DISPMANX "Enable the RPi dispmanx grabber" ${DEFAULT_DISPMANX} ) +option(ENABLE_DISPMANX "Enable the RPi dispmanx grabber" ${DEFAULT_DISPMANX}) message(STATUS "ENABLE_DISPMANX = ${ENABLE_DISPMANX}") option(ENABLE_DX "Enable the DirectX grabber" ${DEFAULT_DX}) message(STATUS "ENABLE_DX = ${ENABLE_DX}") -if (ENABLE_AMLOGIC) - SET(ENABLE_FB ON) +if(ENABLE_AMLOGIC) + set(ENABLE_FB ON) else() - option(ENABLE_FB " Enable the framebuffer grabber" ${DEFAULT_FB} ) + option(ENABLE_FB " Enable the framebuffer grabber" ${DEFAULT_FB}) endif() message(STATUS "ENABLE_FB = ${ENABLE_FB}") option(ENABLE_MF "Enable the Media Foundation grabber" ${DEFAULT_MF}) message(STATUS "ENABLE_MF = ${ENABLE_MF}") -option(ENABLE_OSX "Enable the OSX grabber" ${DEFAULT_OSX} ) +option(ENABLE_OSX "Enable the OSX grabber" ${DEFAULT_OSX}) message(STATUS "ENABLE_OSX = ${ENABLE_OSX}") option(ENABLE_QT "Enable the Qt grabber" ${DEFAULT_QT}) @@ -287,16 +297,16 @@ removeIndent() message(STATUS "Input options:") addIndent(" - ") -option(ENABLE_BOBLIGHT_SERVER "Enable BOBLIGHT server" ${DEFAULT_BOBLIGHT_SERVER} ) +option(ENABLE_BOBLIGHT_SERVER "Enable BOBLIGHT server" ${DEFAULT_BOBLIGHT_SERVER}) message(STATUS "ENABLE_BOBLIGHT_SERVER = ${ENABLE_BOBLIGHT_SERVER}") -option(ENABLE_CEC "Enable the libcec and CEC control" ${DEFAULT_CEC} ) +option(ENABLE_CEC "Enable the libcec and CEC control" ${DEFAULT_CEC}) message(STATUS "ENABLE_CEC = ${ENABLE_CEC}") -option(ENABLE_FLATBUF_SERVER "Enable Flatbuffers server" ${DEFAULT_FLATBUF_SERVER} ) +option(ENABLE_FLATBUF_SERVER "Enable Flatbuffers server" ${DEFAULT_FLATBUF_SERVER}) message(STATUS "ENABLE_FLATBUF_SERVER = ${ENABLE_FLATBUF_SERVER}") -option(ENABLE_PROTOBUF_SERVER "Enable Protocol Buffers server" ${DEFAULT_PROTOBUF_SERVER} ) +option(ENABLE_PROTOBUF_SERVER "Enable Protocol Buffers server" ${DEFAULT_PROTOBUF_SERVER}) message(STATUS "ENABLE_PROTOBUF_SERVER = ${ENABLE_PROTOBUF_SERVER}") removeIndent() @@ -304,13 +314,13 @@ removeIndent() message(STATUS "Output options:") addIndent(" - ") -option(ENABLE_FORWARDER "Enable Hyperion forwarding" ${DEFAULT_FORWARDER} ) +option(ENABLE_FORWARDER "Enable Hyperion forwarding" ${DEFAULT_FORWARDER}) message(STATUS "ENABLE_FORWARDER = ${ENABLE_FORWARDER}") -if (ENABLE_FORWARDER) - SET(ENABLE_FLATBUF_CONNECT ON) +if(ENABLE_FORWARDER) + set(ENABLE_FLATBUF_CONNECT ON) else() - option(ENABLE_FLATBUF_CONNECT "Enable Flatbuffers connecting remotely" ${DEFAULT_FLATBUF_CONNECT} ) + option(ENABLE_FLATBUF_CONNECT "Enable Flatbuffers connecting remotely" ${DEFAULT_FLATBUF_CONNECT}) endif() message(STATUS "ENABLE_FLATBUF_CONNECT = ${ENABLE_FLATBUF_CONNECT}") @@ -319,22 +329,22 @@ removeIndent() message(STATUS "LED-Device options:") addIndent(" - ") -option(ENABLE_DEV_NETWORK "Enable the Network devices" ${DEFAULT_DEV_NETWORK} ) +option(ENABLE_DEV_NETWORK "Enable the Network devices" ${DEFAULT_DEV_NETWORK}) message(STATUS "ENABLE_DEV_NETWORK = ${ENABLE_DEV_NETWORK}") -option(ENABLE_DEV_SERIAL "Enable the Serial devices" ${DEFAULT_DEV_SERIAL} ) +option(ENABLE_DEV_SERIAL "Enable the Serial devices" ${DEFAULT_DEV_SERIAL}) message(STATUS "ENABLE_DEV_SERIAL = ${ENABLE_DEV_SERIAL}") -option(ENABLE_DEV_SPI "Enable the SPI device" ${DEFAULT_DEV_SPI} ) +option(ENABLE_DEV_SPI "Enable the SPI device" ${DEFAULT_DEV_SPI}) message(STATUS "ENABLE_DEV_SPI = ${ENABLE_DEV_SPI}") option(ENABLE_DEV_TINKERFORGE "Enable the TINKERFORGE device" ${DEFAULT_DEV_TINKERFORGE}) message(STATUS "ENABLE_DEV_TINKERFORGE = ${ENABLE_DEV_TINKERFORGE}") -option(ENABLE_DEV_USB_HID "Enable the libusb and hid devices" ${DEFAULT_DEV_USB_HID} ) +option(ENABLE_DEV_USB_HID "Enable the libusb and hid devices" ${DEFAULT_DEV_USB_HID}) message(STATUS "ENABLE_DEV_USB_HID = ${ENABLE_DEV_USB_HID}") -option(ENABLE_DEV_WS281XPWM "Enable the WS281x-PWM device" ${DEFAULT_DEV_WS281XPWM} ) +option(ENABLE_DEV_WS281XPWM "Enable the WS281x-PWM device" ${DEFAULT_DEV_WS281XPWM}) message(STATUS "ENABLE_DEV_WS281XPWM = ${ENABLE_DEV_WS281XPWM}") removeIndent() @@ -375,7 +385,7 @@ endif() message(STATUS "DEFAULT_USE_SYSTEM_MBEDTLS_LIBS = ${DEFAULT_USE_SYSTEM_MBEDTLS_LIBS}") -if (ENABLE_MDNS) +if(ENABLE_MDNS) message(STATUS "DEFAULT_USE_SYSTEM_QMDNS_LIBS = ${DEFAULT_USE_SYSTEM_QMDNS_LIBS}") endif() @@ -388,14 +398,14 @@ message(STATUS "ENABLE_TESTS = ${ENABLE_TESTS}") removeIndent() -SET ( FLATBUFFERS_INSTALL_BIN_DIR ${CMAKE_BINARY_DIR}/flatbuf ) -SET ( FLATBUFFERS_INSTALL_LIB_DIR ${CMAKE_BINARY_DIR}/flatbuf ) +set(FLATBUFFERS_INSTALL_BIN_DIR ${CMAKE_BINARY_DIR}/flatbuf) +set(FLATBUFFERS_INSTALL_LIB_DIR ${CMAKE_BINARY_DIR}/flatbuf) -SET ( PROTOBUF_INSTALL_BIN_DIR ${CMAKE_BINARY_DIR}/proto ) -SET ( PROTOBUF_INSTALL_LIB_DIR ${CMAKE_BINARY_DIR}/proto ) +set(PROTOBUF_INSTALL_BIN_DIR ${CMAKE_BINARY_DIR}/proto) +set(PROTOBUF_INSTALL_LIB_DIR ${CMAKE_BINARY_DIR}/proto) if(ENABLE_JSONCHECKS OR ENABLE_EFFECTENGINE) - if ("${CMAKE_VERSION}" VERSION_LESS "3.12.0") + if("${CMAKE_VERSION}" VERSION_LESS "3.12.0") set(Python_ADDITIONAL_VERSIONS 3.5) find_package(PythonInterp 3.5 REQUIRED) else() @@ -408,38 +418,38 @@ endif() if(ENABLE_JSONCHECKS) # check all json files - FILE ( GLOB_RECURSE HYPERION_SCHEMAS RELATIVE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/libsrc/*schema*.json ) - SET( JSON_FILES ${CMAKE_BINARY_DIR}/config/hyperion.config.json.default ${HYPERION_SCHEMAS}) + file (GLOB_RECURSE HYPERION_SCHEMAS RELATIVE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/libsrc/*schema*.json) + set(JSON_FILES ${CMAKE_BINARY_DIR}/config/hyperion.config.json.default ${HYPERION_SCHEMAS}) - EXECUTE_PROCESS ( + execute_process ( COMMAND ${PYTHON_EXECUTABLE} test/jsonchecks/checkjson.py ${JSON_FILES} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} RESULT_VARIABLE CHECK_JSON_FAILED ) - IF ( ${CHECK_JSON_FAILED} ) - MESSAGE (FATAL_ERROR "check of json files failed" ) - ENDIF () + if(${CHECK_JSON_FAILED}) + message (FATAL_ERROR "check of json files failed") + endif() if(ENABLE_EFFECTENGINE) - EXECUTE_PROCESS ( + execute_process ( COMMAND ${PYTHON_EXECUTABLE} test/jsonchecks/checkeffects.py effects effects/schema WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} RESULT_VARIABLE CHECK_EFFECTS_FAILED ) - IF ( ${CHECK_EFFECTS_FAILED} ) - MESSAGE (FATAL_ERROR "check of json effect files failed" ) - ENDIF () + if(${CHECK_EFFECTS_FAILED}) + message (FATAL_ERROR "check of json effect files failed") + endif() endif() - EXECUTE_PROCESS ( + execute_process ( COMMAND ${PYTHON_EXECUTABLE} test/jsonchecks/checkschema.py ${CMAKE_BINARY_DIR}/config/hyperion.config.json.default libsrc/hyperion/hyperion.schema.json WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} RESULT_VARIABLE CHECK_CONFIG_FAILED ) - IF ( ${CHECK_CONFIG_FAILED} ) - MESSAGE (FATAL_ERROR "check of json default config failed" ) - ENDIF () + if(${CHECK_CONFIG_FAILED}) + message (FATAL_ERROR "check of json default config failed") + endif() endif(ENABLE_JSONCHECKS) # Add project specific cmake modules (find, etc) @@ -453,8 +463,8 @@ configure_file("${PROJECT_SOURCE_DIR}/HyperionConfig.h.in" "${PROJECT_BINARY_DIR include_directories("${PROJECT_BINARY_DIR}") # Define the global output path of binaries -SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) -SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) +set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) file(MAKE_DIRECTORY ${LIBRARY_OUTPUT_PATH}) file(MAKE_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) @@ -467,32 +477,21 @@ include_directories(${CMAKE_SOURCE_DIR}/include) #set(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.so") # MSVC options -if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") +if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") # Search for Windows SDK find_package(WindowsSDK REQUIRED) message(STATUS "WINDOWS SDK: ${WINDOWSSDK_LATEST_DIR} ${WINDOWSSDK_LATEST_NAME}") message(STATUS "MSVC VERSION: ${MSVC_VERSION}") - - # Search for DirectX9 - if (ENABLE_DX) - find_package(DirectX9 REQUIRED) - endif(ENABLE_DX) - -endif() - -# Use GNU gold linker if available -if (NOT WIN32 AND NOT APPLE) - include (${CMAKE_CURRENT_SOURCE_DIR}/cmake/LDGold.cmake) endif() # Don't create new dynamic tags (RUNPATH) and setup -rpath to search for shared libs in BINARY/../lib folder (only for Unix) -if (ENABLE_DEPLOY_DEPENDENCIES AND UNIX AND NOT APPLE) +if(ENABLE_DEPLOY_DEPENDENCIES AND UNIX AND NOT APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--disable-new-dtags") - SET(CMAKE_SKIP_BUILD_RPATH FALSE) - SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) - SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:$ORIGIN/../lib") - SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) -endif () + set(CMAKE_SKIP_BUILD_RPATH FALSE) + set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib") + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +endif() if(APPLE) set(CMAKE_EXE_LINKER_FLAGS "-framework CoreGraphics") @@ -503,18 +502,18 @@ find_package(Threads REQUIRED) # Allow to overwrite QT base directory # Either supply QTDIR as -DQTDIR= to cmake or set and environment variable QTDIR pointing to the Qt installation # For Windows and OSX, the default Qt installation path are tried to resolved automatically -if (NOT DEFINED QTDIR) - if (DEFINED ENV{QTDIR}) +if(NOT DEFINED QTDIR) + if(DEFINED ENV{QTDIR}) set(QTDIR $ENV{QTDIR}) else() - if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") FIRSTSUBDIR(SUBDIRQT "C:/Qt") - if (NOT ${SUBDIRQT} STREQUAL "") + if(NOT ${SUBDIRQT} STREQUAL "") set(QTDIR "${SUBDIRQT}/msvc2019_64") endif() - elseif ( "${PLATFORM}" MATCHES "osx" ) + elseif ("${PLATFORM}" MATCHES "osx") # QT6 x86_64 location - if (EXISTS /usr/local/opt/qt6) + if(EXISTS /usr/local/opt/qt6) set(QTDIR "/usr/local/opt/qt6") # QT6 arm64 location elseif (EXISTS /opt/homebrew/opt/qt@6) @@ -530,34 +529,34 @@ if (NOT DEFINED QTDIR) endif() endif() -if (DEFINED QTDIR) +if(DEFINED QTDIR) message(STATUS "Add QTDIR: ${QTDIR} to CMAKE_PREFIX_PATH") list(PREPEND CMAKE_PREFIX_PATH ${QTDIR} "${QTDIR}/lib") endif() -if (CMAKE_PREFIX_PATH) - message( STATUS "CMAKE_PREFIX_PATH used: ${CMAKE_PREFIX_PATH}" ) +if(CMAKE_PREFIX_PATH) + message(STATUS "CMAKE_PREFIX_PATH used: ${CMAKE_PREFIX_PATH}") endif() # find QT libs find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Network Sql Widgets REQUIRED) -message( STATUS "Found Qt Version: ${QT_VERSION}" ) +message(STATUS "Found Qt Version: ${QT_VERSION}") -if (${QT_VERSION_MAJOR} GREATER_EQUAL 6 ) - SET(QT_MIN_VERSION "6.2.2") +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + set(QT_MIN_VERSION "6.2.2") else() - SET(QT_MIN_VERSION "5.5.0") + set(QT_MIN_VERSION "5.5.0") endif() -if ( "${QT_VERSION}" VERSION_LESS "${QT_MIN_VERSION}" ) - message( FATAL_ERROR "Your Qt version is to old! Minimum required ${QT_MIN_VERSION}" ) +if("${QT_VERSION}" VERSION_LESS "${QT_MIN_VERSION}") + message(FATAL_ERROR "Your Qt version is to old! Minimum required ${QT_MIN_VERSION}") endif() find_package(Qt${QT_VERSION_MAJOR} ${QT_VERSION} COMPONENTS Core Gui Network Sql Widgets REQUIRED) -message( STATUS "Qt version used: ${QT_VERSION}" ) +message(STATUS "Qt version used: ${QT_VERSION}") -if (APPLE AND (${QT_VERSION_MAJOR} GREATER_EQUAL 6) ) +if(APPLE AND (${QT_VERSION_MAJOR} GREATER_EQUAL 6)) set(OPENSSL_ROOT_DIR /usr/local/opt/openssl) endif() @@ -569,29 +568,29 @@ add_definitions(${QT_DEFINITIONS}) add_subdirectory(dependencies) add_subdirectory(libsrc) add_subdirectory(src) -if (ENABLE_TESTS) +if(ENABLE_TESTS) add_subdirectory(test) -endif () +endif() # Add resources directory add_subdirectory(resources) # remove generated files on make cleaan too -LIST( APPEND GENERATED_QRC +list(APPEND GENERATED_QRC ${CMAKE_BINARY_DIR}/WebConfig.qrc ${CMAKE_BINARY_DIR}/HyperionConfig.h ) if(ENABLE_EFFECTENGINE) -LIST( APPEND GENERATED_QRC +list(APPEND GENERATED_QRC ${CMAKE_BINARY_DIR}/EffectEngine.qrc ) -endif () +endif() -set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${GENERATED_QRC}" ) +set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${GENERATED_QRC}") # uninstall target -configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) # enable make package - no code after this line ! diff --git a/bin/scripts/docker-compile.sh b/bin/scripts/docker-compile.sh index ce298b965..bafde87fb 100755 --- a/bin/scripts/docker-compile.sh +++ b/bin/scripts/docker-compile.sh @@ -1,4 +1,4 @@ -#!/bin/bash -e +#!/bin/bash DOCKER="docker" # Git repo url of Hyperion @@ -7,20 +7,21 @@ GIT_REPO_URL="https://github.com/hyperion-project/hyperion.ng.git" REGISTRY_URL="ghcr.io/hyperion-project" # cmake build type BUILD_TYPE="Release" -# the docker image at GitHub Container Registry -BUILD_IMAGE="x86_64" -# the docker tag at GitHub Container Registry -BUILD_TAG="bullseye" +DISTRIBUTION="debian" +CODENAME="bullseye" +ARCHITECTURE="amd64" # build packages (.deb .zip ...) BUILD_PACKAGES=true # packages string inserted to cmake cmd PACKAGES="" # platform string inserted to cmake cmd BUILD_PLATFORM="" +#Run build with Qt6 or Qt5 +BUILD_WITH_QT5=false #Run build using GitHub code files -BUILD_LOCAL=0 +BUILD_LOCAL=false #Build from scratch -BUILD_INCREMENTAL=0 +BUILD_INCREMENTAL=false #Verbose output _VERBOSE=0 #Additional args @@ -37,11 +38,7 @@ cd `dirname ${BASE_PATH}` > /dev/null BASE_PATH=`pwd`; popd > /dev/null -BASE_PATH=`pwd`;function log () { - if [[ $_V -eq 1 ]]; then - echo "$@" - fi -} +BASE_PATH=`pwd`; set +e ${DOCKER} ps >/dev/null 2>&1 @@ -62,7 +59,7 @@ function printHelp { echo "######################################################## ## A script to compile Hyperion inside a docker container ## Requires installed Docker: https://www.docker.com/ -## Without arguments it will compile Hyperion for Debian Bullseye (x86_64) and uses Hyperion code from GitHub repository. +## Without arguments it will compile Hyperion for ${DISTRIBUTION}:${CODENAME}, ${ARCHITECTURE} architecture and uses Hyperion code from GitHub repository. ## For all images and tags currently available, see https://github.com/orgs/hyperion-project/packages ## ## Homepage: https://www.hyperion-project.org @@ -71,16 +68,17 @@ echo "######################################################## # These are possible arguments to modify the script behaviour with their default values # # docker-compile.sh -h, --help # Show this help message -# docker-compile.sh -i, --image # The docker image, e.g., x86_64, armv6l, armv7l, aarch64 -# docker-compile.sh -t, --tag # The docker tag, e.g., buster, bullseye, bookworm +# docker-compile.sh -n, --name # The distribution's codename, e.g., buster, bullseye, bookworm, jammy, trixie, lunar, mantic; Note: for Fedora it is the version number +# docker-compile.sh -a, --architecture # The output architecture, e.g., amd64, arm64, arm/v7 # docker-compile.sh -b, --type # Release or Debug build # docker-compile.sh -p, --packages # If true, build packages with CPack +# docker-compile.sh --qt5 # Build with Qt5, otherwise build with Qt6 +# docker-compile.sh -f, --platform # cmake PLATFORM parameter, e.g. x11, amlogic-dev # docker-compile.sh -l, --local # Run build using local code files # docker-compile.sh -c, --incremental # Run incremental build, i.e. do not delete files created during previous build -# docker-compile.sh -f, --platform # cmake PLATFORM parameter, e.g. x11, amlogic-dev # docker-compile.sh -v, --verbose # Run the script in verbose mode # docker-compile.sh -- args # Additonal cmake arguments, e.g., -DHYPERION_LIGHT=ON -# More informations to docker tags at: https://github.com/Hyperion-Project/hyperion.docker-ci" +# More informations to docker containers available at: https://github.com/Hyperion-Project/hyperion.docker-ci" } function log () { @@ -89,48 +87,63 @@ function log () { fi } +function check_distribution () { + url=${REGISTRY_URL}/$1:${CODENAME} + + log "Check for distribution at: $url" + if $($DOCKER buildx imagetools inspect "$url" 2>&1 | grep -q $2) ; then + rc=0 + else + rc=1 + fi + return $rc +} + echo "Compile Hyperion using a Docker container" -options=$(getopt -l "image:,tag:,type:,packages:,platform:,local,incremental,verbose,help" -o "i:t:b:p:f:lcvh" -a -- "$@") +options=$(getopt -l "architecture:,name:,type:,packages:,platform:,qt5,local,incremental,verbose,help" -o "a:n:b:p:f:lcvh" -a -- "$@") eval set -- "$options" while true do case $1 in - -i|--image) + -a|--architecture) shift - BUILD_IMAGE=$1 + ARCHITECTURE=`echo $1 | tr '[:upper:]' '[:lower:]'` ;; - -t|--tag) + -n|--name) shift - BUILD_TAG=$1 + CODENAME=`echo $1 | tr '[:upper:]' '[:lower:]'` ;; - -b|--type) + -b|--type) shift BUILD_TYPE=$1 ;; - -p|--packages) + -p|--packages) shift BUILD_PACKAGES=$1 ;; - -f|--platform) + -f|--platform) shift BUILD_PLATFORM=$1 ;; - -l|--local) - BUILD_LOCAL=1 + --qt5) + BUILD_WITH_QT5=true + ;; + -l|--local) + BUILD_LOCAL=true ;; - -c|--incremental) - BUILD_INCREMENTAL=1 + -i|--incremental) + BUILD_INCREMENTAL=true ;; - -v|--verbose) + -v|--verbose) _VERBOSE=1 ;; - -h|--help) + -h|--help) printHelp exit 0 ;; --) - shift + shift break;; esac shift @@ -148,7 +161,66 @@ if [[ ! -z ${BUILD_PLATFORM} ]]; then PLATFORM="-DPLATFORM=${BUILD_PLATFORM}" fi -echo "---> Initialize with IMAGE:TAG=${BUILD_IMAGE}:${BUILD_TAG}, BUILD_TYPE=${BUILD_TYPE}, BUILD_PACKAGES=${BUILD_PACKAGES}, PLATFORM=${BUILD_PLATFORM}, BUILD_LOCAL=${BUILD_LOCAL}, BUILD_INCREMENTAL=${BUILD_INCREMENTAL}" +PLATFORM_ARCHITECTURE="linux/"${ARCHITECTURE} + +QTVERSION="5" +if [ ${BUILD_WITH_QT5} == false ]; then + QTVERSION="6" + CODENAME="${CODENAME}-qt6" +fi + +echo "---> Evaluate distribution for codename:${CODENAME} on platform architecture ${PLATFORM_ARCHITECTURE}" +DISTRIBUTION="debian" +if ! check_distribution ${DISTRIBUTION} ${PLATFORM_ARCHITECTURE} ; then + DISTRIBUTION="ubuntu" + if ! check_distribution ${DISTRIBUTION} ${PLATFORM_ARCHITECTURE} ; then + DISTRIBUTION="fedora" + if ! check_distribution ${DISTRIBUTION} ${PLATFORM_ARCHITECTURE} ; then + echo "No docker image found for a distribution with codename: ${CODENAME} to be build on platform architecture ${PLATFORM_ARCHITECTURE}" + exit 1 + fi + fi +fi + +echo "---> Build with -> Distribution: ${DISTRIBUTION}, Codename: ${CODENAME}, Architecture: ${ARCHITECTURE}, Type: ${BUILD_TYPE}, Platform: ${BUILD_PLATFORM}, QT Version: ${QTVERSION}, Build Packages: ${BUILD_PACKAGES}, Build local: ${BUILD_LOCAL}, Build incremental: ${BUILD_INCREMENTAL}" + +# Determine the current architecture +CURRENT_ARCHITECTURE=`uname -m` + +#Test if multiarchitecture setup, i.e. user-space is 32bit +if [ ${CURRENT_ARCHITECTURE} == "aarch64" ]; then + CURRENT_ARCHITECTURE="arm64" + USER_ARCHITECTURE=$CURRENT_ARCHITECTURE + IS_V7L=`cat /proc/$$/maps |grep -m1 -c v7l` + if [ $IS_V7L -ne 0 ]; then + USER_ARCHITECTURE="arm/v7" + else + IS_V6L=`cat /proc/$$/maps |grep -m1 -c v6l` + if [ $IS_V6L -ne 0 ]; then + USER_ARCHITECTURE="arm/v6" + fi + fi + if [ $ARCHITECTURE != $USER_ARCHITECTURE ]; then + log "Identified user space current architecture: $USER_ARCHITECTURE" + CURRENT_ARCHITECTURE=$USER_ARCHITECTURE + fi +else + CURRENT_ARCHITECTURE=${CURRENT_ARCHITECTURE//x86_/amd} +fi + +log "Identified kernel current architecture: $CURRENT_ARCHITECTURE" +if [ $ARCHITECTURE != $CURRENT_ARCHITECTURE ]; then + echo "---> Build is not for the same architecturem, enable emulation for ${PLATFORM_ARCHITECTURE}" + ENTRYPOINT_OPTION= + + if [ $CURRENT_ARCHITECTURE != "amd64" ]; then + echo "---> Emulation builds can only be executed on linux/amd64, linux/x86_64 platforms, current architecture is ${CURRENT_ARCHITECTURE}" + exit 1 + fi +else + log "Build natively for platform architecture: ${PLATFORM_ARCHITECTURE}" + ENTRYPOINT_OPTION="--entrypoint=""" +fi log "---> BASE_PATH = ${BASE_PATH}" CODE_PATH=${BASE_PATH}; @@ -163,9 +235,11 @@ git clone --recursive --depth 1 -q ${GIT_REPO_URL} ${CODE_PATH} || { echo "---> fi log "---> CODE_PATH = ${CODE_PATH}" -BUILD_DIR="build-${BUILD_IMAGE}-${BUILD_TAG}" +ARCHITECTURE_PATH=${ARCHITECTURE//\//_} + +BUILD_DIR="build-${CODENAME}-${ARCHITECTURE_PATH}" BUILD_PATH="${CODE_PATH}/${BUILD_DIR}" -DEPLOY_DIR="deploy/${BUILD_IMAGE}/${BUILD_TAG}" +DEPLOY_DIR="deploy/${CODENAME}/${ARCHITECTURE}" DEPLOY_PATH="${CODE_PATH}/${DEPLOY_DIR}" log "---> BUILD_DIR = ${BUILD_DIR}" @@ -178,7 +252,7 @@ sudo rm -fr "${DEPLOY_PATH}" >/dev/null 2>&1 mkdir -p "${DEPLOY_PATH}" >/dev/null 2>&1 #Remove previous build area, if no incremental build -if [ ${BUILD_INCREMENTAL} != 1 ]; then +if [ ${BUILD_INCREMENTAL} != true ]; then sudo rm -fr "${BUILD_PATH}" >/dev/null 2>&1 fi mkdir -p "${BUILD_PATH}" >/dev/null 2>&1 @@ -194,10 +268,11 @@ echo "---> Compiling Hyperion from source code at ${CODE_PATH}" # execute inside container all commands on bash echo "---> Startup docker..." -$DOCKER run --rm \ +$DOCKER run --rm --platform=${PLATFORM_ARCHITECTURE} \ + ${ENTRYPOINT_OPTION} \ -v "${DEPLOY_PATH}:/deploy" \ -v "${CODE_PATH}/:/source:rw" \ - ${REGISTRY_URL}/${BUILD_IMAGE}:${BUILD_TAG} \ + ${REGISTRY_URL}/${DISTRIBUTION}:${CODENAME} \ /bin/bash -c "mkdir -p /source/${BUILD_DIR} && cd /source/${BUILD_DIR} && cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${PLATFORM} ${BUILD_ARGS} .. || exit 2 && make -j $(nproc) ${PACKAGES} || exit 3 || : && @@ -210,7 +285,7 @@ DOCKERRC=${?} sudo chown -fR $(stat -c "%U:%G" ${BASE_PATH}) ${BUILD_PATH} if [ ${DOCKERRC} == 0 ]; then - if [ ${BUILD_LOCAL} == 1 ]; then + if [ ${BUILD_LOCAL} == true ]; then echo "---> Find compiled binaries in: ${BUILD_PATH}/bin" fi diff --git a/bin/scripts/install_pr.sh b/bin/scripts/install_pr.sh index 1f654f23c..cd023504b 100755 --- a/bin/scripts/install_pr.sh +++ b/bin/scripts/install_pr.sh @@ -73,13 +73,13 @@ if [ ${ARCHITECTURE} == "aarch64" ]; then IS_V7L=`cat /proc/$$/maps |grep -m1 -c v7l` if [ $IS_V7L -ne 0 ]; then USER_ARCHITECTURE="armv7l" - else + else IS_V6L=`cat /proc/$$/maps |grep -m1 -c v6l` if [ $IS_V6L -ne 0 ]; then USER_ARCHITECTURE="armv6l" fi fi - if [ $ARCHITECTURE != $USER_ARCHITECTURE ]; then + if [ $ARCHITECTURE != $USER_ARCHITECTURE ]; then echo "---> Identified kernel target architecture: $ARCHITECTURE" echo "---> Identified user space target architecture: $USER_ARCHITECTURE" ARCHITECTURE=$USER_ARCHITECTURE @@ -134,11 +134,11 @@ if [ -z "$run_id" ]; then # Determine run_id from head_sha runs=$(request_call "$api_url/actions/runs?head_sha=$head_sha") run_id=$(echo "$runs" | tr '\r\n' ' ' | ${pythonCmd} -c """ -import json,sys +import json,sys,os data = json.load(sys.stdin) for i in data['workflow_runs']: - if i['name'] == 'Hyperion PR Build': + if os.path.basename(i['path']) == 'push_pull.yml': print(i['id']) break """ 2>/dev/null) @@ -198,11 +198,11 @@ if [[ ! -z ${CURRENT_SERVICE} ]]; then echo "---> Stop current service: ${CURRENT_SERVICE}" STOPCMD="systemctl stop --quiet ${CURRENT_SERVICE} --now" - USERNAME=${SUDO_USER:-$(whoami)} + USERNAME=${SUDO_USER:-$(whoami)} if [ ${USERNAME} != "root" ]; then STOPCMD="sudo ${STOPCMD}" fi - + ${STOPCMD} >/dev/null 2>&1 if [ $? -ne 0 ]; then echo "---> Critical Error: Failed to stop service: ${CURRENT_SERVICE}, Hyperion may not be started. Stop Hyperion manually." diff --git a/bin/service/hyperion.systemd b/bin/service/hyperion.systemd index adee0eedf..7087d6b00 100644 --- a/bin/service/hyperion.systemd +++ b/bin/service/hyperion.systemd @@ -1,5 +1,5 @@ [Unit] -Description=Hyperion ambient light systemd service for user %i +Description=Hyperion ambient light systemd service for user %i Documentation=https://docs.hyperion-project.org Requisite=network.target Wants=network-online.target diff --git a/bin/service/hyperion.xml b/bin/service/hyperion.xml new file mode 100644 index 000000000..1ecc4e7e2 --- /dev/null +++ b/bin/service/hyperion.xml @@ -0,0 +1,22 @@ + + + Hyperion + Hyperion.NG firewall rules + + + + + + + + + + + + + + + + + + diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index 40ada3e15..847c4c40b 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -14,7 +14,7 @@ macro(DeployMacOS TARGET) install(CODE "set(PLUGIN_DIR \"${QT_PLUGIN_DIR}\")" COMPONENT "Hyperion") install(CODE "set(BUILD_DIR \"${CMAKE_BINARY_DIR}\")" COMPONENT "Hyperion") install(CODE "set(ENABLE_EFFECTENGINE \"${ENABLE_EFFECTENGINE}\")" COMPONENT "Hyperion") - + install(CODE [[ file(GET_RUNTIME_DEPENDENCIES @@ -36,6 +36,7 @@ macro(DeployMacOS TARGET) FILES "${dependency}" DESTINATION "${CMAKE_INSTALL_PREFIX}/${TARGET_BUNDLE_NAME}/Contents/lib" TYPE SHARED_LIBRARY + FOLLOW_SYMLINK_CHAIN ) endif() endforeach() @@ -48,7 +49,6 @@ macro(DeployMacOS TARGET) foreach(PLUGIN "platforms" "sqldrivers" "imageformats") if(EXISTS ${PLUGIN_DIR}/${PLUGIN}) file(GLOB files "${PLUGIN_DIR}/${PLUGIN}/*") - list(FILTER files EXCLUDE REGEX ".*libqwebp\\.dylib$") foreach(file ${files}) file(GET_RUNTIME_DEPENDENCIES EXECUTABLES ${file} @@ -61,6 +61,7 @@ macro(DeployMacOS TARGET) DESTINATION "${CMAKE_INSTALL_PREFIX}/${TARGET_BUNDLE_NAME}/Contents/lib" TYPE SHARED_LIBRARY FILES ${DEPENDENCY} + FOLLOW_SYMLINK_CHAIN ) endforeach() @@ -76,25 +77,27 @@ macro(DeployMacOS TARGET) endif() endforeach() - include(BundleUtilities) + include(BundleUtilities) fixup_bundle("${CMAKE_INSTALL_PREFIX}/${TARGET_BUNDLE_NAME}" "${QT_PLUGINS}" "${CMAKE_INSTALL_PREFIX}/${TARGET_BUNDLE_NAME}/Contents/lib" IGNORE_ITEM "python;python3;Python;Python3;.Python;.Python3") if(ENABLE_EFFECTENGINE) # Detect the Python version and modules directory - find_package(Python3 3.5 REQUIRED) - execute_process( - COMMAND ${Python3_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(standard_lib=True))" - OUTPUT_VARIABLE PYTHON_MODULES_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE - ) + if(NOT CMAKE_VERSION VERSION_LESS "3.12") + find_package(Python3 COMPONENTS Interpreter Development REQUIRED) + set(PYTHON_VERSION_MAJOR_MINOR "${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}") + set(PYTHON_MODULES_DIR ${Python3_STDLIB}) + else() + find_package (PythonLibs ${PYTHON_VERSION_STRING} EXACT) + set(PYTHON_VERSION_MAJOR_MINOR "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") + set(PYTHON_MODULES_DIR ${Python_STDLIB}) + endif() MESSAGE("Add Python ${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR} to bundle") MESSAGE("PYTHON_MODULES_DIR: ${PYTHON_MODULES_DIR}") # Copy Python modules to '/../Frameworks/Python.framework/Versions/Current/lib/PythonMAJOR.MINOR' and ignore the unnecessary stuff listed below if (PYTHON_MODULES_DIR) - set(PYTHON_VERSION_MAJOR_MINOR "${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}") file( COPY ${PYTHON_MODULES_DIR}/ DESTINATION "${CMAKE_INSTALL_PREFIX}/${TARGET_BUNDLE_NAME}/Contents/Frameworks/Python.framework/Versions/Current/lib/python${PYTHON_VERSION_MAJOR_MINOR}" @@ -167,9 +170,9 @@ macro(DeployLinux TARGET) # Extract dependencies ignoring the system ones get_prerequisites(${TARGET_FILE} DEPENDENCIES 0 1 "" "") - + message(STATUS "Dependencies for target file: ${DEPENDENCIES}") - + # Append symlink and non-symlink dependencies to the list set(PREREQUISITE_LIBS "") foreach(DEPENDENCY ${DEPENDENCIES}) @@ -276,15 +279,13 @@ macro(DeployLinux TARGET) if(ENABLE_EFFECTENGINE) # Detect the Python version and modules directory if (NOT CMAKE_VERSION VERSION_LESS "3.12") + find_package(Python3 COMPONENTS Interpreter Development REQUIRED) set(PYTHON_VERSION_MAJOR_MINOR "${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}") - set(PYTHON_MODULES_DIR "${Python3_STDLIB}") + set(PYTHON_MODULES_DIR ${Python3_STDLIB}) else() + find_package (PythonLibs ${PYTHON_VERSION_STRING} EXACT) set(PYTHON_VERSION_MAJOR_MINOR "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") - execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(standard_lib=True))" - OUTPUT_VARIABLE PYTHON_MODULES_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE - ) + set(PYTHON_MODULES_DIR ${Python_STDLIB}) endif() # Copy Python modules to 'share/hyperion/lib/pythonMAJOR.MINOR' and ignore the unnecessary stuff listed below @@ -381,19 +382,25 @@ macro(DeployWindows TARGET) list(GET openssl_versions 0 openssl_version_major) list(GET openssl_versions 1 openssl_version_minor) - set(library_suffix "-${openssl_version_major}_${openssl_version_minor}") + set(open_ssl_version_suffix) + if (openssl_version_major VERSION_EQUAL 1 AND openssl_version_minor VERSION_EQUAL 1) + set(open_ssl_version_suffix "-1_1") + else() + set(open_ssl_version_suffix "-3") + endif() + if (CMAKE_SIZEOF_VOID_P EQUAL 8) - string(APPEND library_suffix "-x64") + string(APPEND open_ssl_version_suffix "-x64") endif() find_file(OPENSSL_SSL - NAMES "libssl${library_suffix}.dll" + NAMES "libssl${open_ssl_version_suffix}.dll" PATHS ${OPENSSL_INCLUDE_DIR}/.. ${OPENSSL_INCLUDE_DIR}/../bin NO_DEFAULT_PATH ) find_file(OPENSSL_CRYPTO - NAMES "libcrypto${library_suffix}.dll" + NAMES "libcrypto${open_ssl_version_suffix}.dll" PATHS ${OPENSSL_INCLUDE_DIR}/.. ${OPENSSL_INCLUDE_DIR}/../bin NO_DEFAULT_PATH ) diff --git a/cmake/Findqmdnsengine.cmake b/cmake/Findqmdnsengine.cmake index ceb7a6b8d..dac675336 100644 --- a/cmake/Findqmdnsengine.cmake +++ b/cmake/Findqmdnsengine.cmake @@ -19,4 +19,10 @@ find_package_handle_standard_args(qmdnsengine REQUIRED_VARS QMDNS_INCLUDE_DIR QMDNS_LIBRARIES ) -mark_as_advanced(QMDNS_INCLUDE_DIR QMDNS_LIBRARIES) +if(QMDNSENGINE_FOUND) + add_library(qmdnsengine STATIC IMPORTED GLOBAL) + set_target_properties(qmdnsengine PROPERTIES + IMPORTED_LOCATION ${QMDNS_LIBRARIES} + INTERFACE_INCLUDE_DIRECTORIES ${QMDNS_INCLUDE_DIR} + ) +endif() diff --git a/cmake/LDGold.cmake b/cmake/LDGold.cmake deleted file mode 100644 index 92e596940..000000000 --- a/cmake/LDGold.cmake +++ /dev/null @@ -1,17 +0,0 @@ -option(ENABLE_LDGOLD "Use GNU gold linker" ON) - -set(LDGOLD_FOUND FALSE) -if(ENABLE_LDGOLD) - execute_process(COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION) - if(LD_VERSION MATCHES "GNU gold") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold") - set(LDGOLD_FOUND TRUE) - message(STATUS "Linker: GNU gold") - else() - message(STATUS "GNU gold linker is not available, falling back to default system linker") - endif() -else() - message(STATUS "Linker: Default system linker") -endif() diff --git a/cmake/desktop/hyperiond.desktop b/cmake/desktop/hyperion.desktop similarity index 61% rename from cmake/desktop/hyperiond.desktop rename to cmake/desktop/hyperion.desktop index d47a38d33..67d02cbd1 100644 --- a/cmake/desktop/hyperiond.desktop +++ b/cmake/desktop/hyperion.desktop @@ -1,8 +1,8 @@ [Desktop Entry] Name=Hyperion GenericName=Hyperion Ambient Lighting -Comment=Hyperion mimics the well known Ambilight from Philips -Icon=/usr/share/pixmaps/hyperion/hyperiond_128.png +Comment=Hyperion is an opensource Bias or Ambient Lighting implementation +Icon=hyperion Terminal=false TryExec=hyperiond Exec=hyperiond diff --git a/cmake/desktop/hyperion.metainfo.xml b/cmake/desktop/hyperion.metainfo.xml new file mode 100644 index 000000000..bc1ac7e60 --- /dev/null +++ b/cmake/desktop/hyperion.metainfo.xml @@ -0,0 +1,48 @@ + + + + com.hyperion-project.hyperion + MIT + MIT + Hyperion + The successor to Hyperion aka Hyperion Next Generation. + + +

+ Hyperion is an opensource Bias or Ambient Lighting implementation which you might know from TV manufacturers. + It supports many LED devices and video grabbers. +

+
+ + https://hyperion-project.org + https://github.com/hyperion-project/hyperion.ng/issues + https://hyperion-project.org + https://docs.hyperion-project.org/ + https://www.paypal.me/HyperionAmbi + https://poeditor.com/join/project/Y4F6vHRFjA + + + + + + + + + + + The multi language web interface + https://raw.githubusercontent.com/hyperion-project/hyperion.ng/master/doc/screenshot.png + + + + + Application + + + com.hyperion-project.hyperion.desktop + + Hyperion Project + admin@hyperion-project.org + + +
diff --git a/cmake/desktop/hyperiond_128.png b/cmake/desktop/hyperiond_128.png deleted file mode 100644 index dc400fc7043854e980d540f9bff4f13ebff772ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16979 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 B0#N_} diff --git a/cmake/package-scripts/postinst b/cmake/package-scripts/postinst index 7bc633227..54cd3901c 100644 --- a/cmake/package-scripts/postinst +++ b/cmake/package-scripts/postinst @@ -105,9 +105,9 @@ ln -fs $BINSP/scripts/updateHyperionUser.sh $BINTP/updateHyperionUser 2>/dev/nul if [ "$IS_UPGRADE" = false ]; then if hash desktop-file-install 2>/dev/null; then echo "---> Install Hyperion desktop icons" - mkdir /usr/share/pixmaps/hyperion 2>/dev/null - cp /usr/share/hyperion/desktop/*.png /usr/share/pixmaps/hyperion 2>/dev/null - desktop-file-install /usr/share/hyperion/desktop/hyperiond.desktop 2>/dev/null + cp -R /usr/share/hyperion/icons /usr/share/icons/hicolor 2>/dev/null + cp /usr/share/hyperion/desktop/hyperion.metainfo.xml /usr/share/metainfo/hyperion.metainfo.xml 2>/dev/null + desktop-file-install /usr/share/hyperion/desktop/hyperion.desktop 2>/dev/null fi fi @@ -149,7 +149,7 @@ $REBOOTMESSAGE echo "-----------------------------------------------------------------------------" echo "Webpage: www.hyperion-project.org" echo "Forum: www.hyperion-project.org" -echo "Documenation: docs.hyperion-project.org" +echo "Documentation: docs.hyperion-project.org" echo "-----------------------------------------------------------------------------" diff --git a/cmake/package-scripts/prerm b/cmake/package-scripts/prerm index 648c9a2db..ea2b9d666 100644 --- a/cmake/package-scripts/prerm +++ b/cmake/package-scripts/prerm @@ -59,11 +59,29 @@ fi # In case we don't use a service kill all instances killall hyperiond 2> /dev/null -# delete desktop icons; desktop-file-edit is a workaround to hide the entry and delete it afterwards manual. -# TODO Better way for deletion and keep the desktop in sync without logout/login or desktop dependend cmds? -echo "---> Delete Hyperion desktop icons" -desktop-file-edit --set-key=NoDisplay --set-value=true /usr/share/applications/hyperiond.desktop 2> /dev/null +# remove desktop/appstream file rm -v /usr/share/applications/hyperion* 2> /dev/null -rm -rv /usr/share/pixmaps/hyperion 2> /dev/null +rm -v /usr/share/metainfo/hyperion* 2> /dev/null + +# update desktop-database (if exists) +if [ -x /usr/bin/update-desktop-database ]; then + update-desktop-database -q /usr/share/applications +fi + +# remove Hyperion icons +for i in 16x16 22x22 24x24 32x32 36x36 48x48 64x64 72x72 96x96 128x128 192x192 256x256 512x512 + rm -v usr/share/icons/hicolor/$i/apps/hyperion.png 2> /dev/null +done + +# update icon-cache +if [ -e /usr/share/icons/hicolor/icon-theme.cache ] ; then + # touch it, just in case we cannot find the binary... + touch --no-create /usr/share/icons/hicolor + if hash gtk-update-icon-cache 2>/dev/null; then + gtk-update-icon-cache /usr/share/icons/hicolor + fi + # ignore errors + true +fi exit 0 diff --git a/cmake/packages.cmake b/cmake/packages.cmake index 046cefe7d..a6701545e 100644 --- a/cmake/packages.cmake +++ b/cmake/packages.cmake @@ -52,7 +52,7 @@ SET ( CPACK_PACKAGE_CONTACT "packages@hyperion-project.org") SET ( CPACK_PACKAGE_VENDOR "hyperion-project") SET ( CPACK_PACKAGE_EXECUTABLES "hyperiond;Hyperion" ) SET ( CPACK_PACKAGE_INSTALL_DIRECTORY "Hyperion" ) -SET ( CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources/icons/hyperion-icon-32px.png" ) +SET ( CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources/icons/hyperion-32px.png" ) SET ( CPACK_PACKAGE_VERSION_MAJOR "${HYPERION_VERSION_MAJOR}") SET ( CPACK_PACKAGE_VERSION_MINOR "${HYPERION_VERSION_MINOR}") diff --git a/cmake/win/win_rc.cmake b/cmake/win/win_rc.cmake deleted file mode 100644 index 203e37942..000000000 --- a/cmake/win/win_rc.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# process a .rc file for windows -# Provides (BINARY_NAME)_WIN_RC_PATH with path to generated file -function(generate_win_rc_file BINARY_NAME) - # target path to store generated files - set(TARGET_PATH ${CMAKE_BINARY_DIR}/win_rc_file/${BINARY_NAME}) - # assets - string(REPLACE "/" "\\\\" WIN_RC_ICON_PATH ${CMAKE_SOURCE_DIR}/cmake/nsis/installer.ico) - # configure the rc file - configure_file( - ${CMAKE_SOURCE_DIR}/cmake/win/win.rc.in - ${TARGET_PATH}/win.rc - ) - # provide var for parent scope - set(${BINARY_NAME}_WIN_RC_PATH ${TARGET_PATH}/win.rc PARENT_SCOPE) -endfunction() diff --git a/debian/control.in b/debian/control.in deleted file mode 100644 index e52b69354..000000000 --- a/debian/control.in +++ /dev/null @@ -1,12 +0,0 @@ -Source: hyperion -Section: devel -Priority: optional -Build-Depends: @BUILD_DEPENDS@ -Standards-Version: @STANDARDS_VERSION@ -Maintainer: Hyperion Project -Homepage: https://hyperion-project.org/ - -Package: hyperion -Architecture: @ARCHITECTURE@ -Depends: @DEPENDS@ -Description: Hyperion is an opensource Bias or Ambient Lighting implementation which you might know from TV manufactures. It supports many LED devices and video grabbers. diff --git a/debian/distributions b/debian/distributions deleted file mode 100644 index 12da7848c..000000000 --- a/debian/distributions +++ /dev/null @@ -1,58 +0,0 @@ -Origin: Hyperion-Project -Label: apt.hyperion-project.org -Codename: focal -Architectures: amd64 armhf arm64 -Components: main -Description: Official APT Repository by Hyperion Project -SignWith: yes - -Origin: Hyperion-Project -Label: apt.hyperion-project.org -Codename: jammy -Architectures: amd64 armhf arm64 -Components: main -Description: Official APT Repository by Hyperion Project -SignWith: yes - -Origin: Hyperion-Project -Label: apt.hyperion-project.org -Codename: kinetic -Architectures: amd64 armhf arm64 -Components: main -Description: Official APT Repository by Hyperion Project -SignWith: yes - -Origin: Hyperion-Project -Label: apt.hyperion-project.org -Codename: lunar -Architectures: amd64 -Components: main -Description: Official APT Repository by Hyperion Project -SignWith: yes - -Origin: Hyperion-Project -Label: apt.hyperion-project.org -Suite: oldstable -Codename: buster -Architectures: amd64 armhf arm64 -Components: main -Description: Official APT Repository by Hyperion Project -SignWith: yes - -Origin: Hyperion-Project -Label: apt.hyperion-project.org -Suite: stable -Codename: bullseye -Architectures: amd64 armhf arm64 -Components: main -Description: Official APT Repository by Hyperion Project -SignWith: yes - -Origin: Hyperion-Project -Label: apt.hyperion-project.org -Suite: unstable -Codename: bookworm -Architectures: amd64 -Components: main -Description: Official APT Repository by Hyperion Project -SignWith: yes diff --git a/debian/rules.in b/debian/rules.in deleted file mode 100644 index a8d28d845..000000000 --- a/debian/rules.in +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/make -f -export DH_VERBOSE = 1 - -BUILDDIR = build - -build: - mkdir $(BUILDDIR); - cd $(BUILDDIR); cmake @CMAKE_ENVIRONMENT@ -DCMAKE_INSTALL_PREFIX=../debian/tmp/usr .. - make -j4 -C $(BUILDDIR) - -binary: binary-indep binary-arch - -binary-indep: - -binary-arch: - cd $(BUILDDIR); cmake -P cmake_install.cmake - rm -rf debian/tmp/usr/include debian/tmp/usr/lib debian/tmp/usr/bin/flatc - mkdir debian/tmp/DEBIAN - cp cmake/package-scripts/postinst debian/tmp/DEBIAN - chmod 0775 debian/tmp/DEBIAN/postinst - cp cmake/package-scripts/preinst debian/tmp/DEBIAN - chmod 0775 debian/tmp/DEBIAN/preinst - cp cmake/package-scripts/prerm debian/tmp/DEBIAN - chmod 0775 debian/tmp/DEBIAN/prerm - dpkg-gencontrol -phyperion - dpkg --build debian/tmp .. - rm -rf debian/tmp $(BUILDDIR) - -clean: - rm -rf $(BUILDDIR) - -.PHONY: build binary binary-arch binary-indep clean diff --git a/dependencies/CMakeLists-qmdnsengine.txt.in b/dependencies/CMakeLists-qmdnsengine.txt.in deleted file mode 100644 index b3f0812a2..000000000 --- a/dependencies/CMakeLists-qmdnsengine.txt.in +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required(VERSION 3.5) - -project(qmdnsengine) - -set(WORK_DIR "@QMDNS_WORK_DIR@") -set(SOURCE_DIR "@QMDNS_SOURCE_DIR@") -set(INSTALL_DIR "@QMDNS_INSTALL_DIR@") -set(CMAKE_ARGS "@QMDNS_CMAKE_ARGS@") -set(QMDNS_LOGGING "@QMDNS_LOGGING@") - -include(ExternalProject) - -ExternalProject_Add(qmdnsengine - PREFIX ${WORK_DIR} - BUILD_ALWAYS OFF - DOWNLOAD_COMMAND "" - SOURCE_DIR ${SOURCE_DIR} - INSTALL_DIR ${INSTALL_DIR} - CMAKE_ARGS ${CMAKE_ARGS} - LOG_DOWNLOAD ${QMDNS_LOGGING} - LOG_UPDATE ${QMDNS_LOGGING} - LOG_CONFIGURE ${QMDNS_LOGGING} - LOG_BUILD ${QMDNS_LOGGING} - LOG_INSTALL ${QMDNS_LOGGING} - LOG_TEST ${QMDNS_LOGGING} -) diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index bc5044beb..28ba5d049 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -24,46 +24,46 @@ if (ENABLE_MDNS) if (USE_SYSTEM_QMDNS_LIBS) find_package(qmdnsengine REQUIRED) else () - if (NOT DEFINED BUILD_QMDNS_ONCE) - set(BUILD_QMDNS_ONCE CACHE INTERNAL "Done") - set(QMDNS_WORK_DIR "${CMAKE_BINARY_DIR}/dependencies/external/qmdnsengine") - set(QMDNS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/qmdnsengine") - set(QMDNS_INSTALL_DIR ${CMAKE_BINARY_DIR}) - set(QMDNS_CMAKE_ARGS - -DBUILD_SHARED_LIBS:BOOL=OFF - -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR} - -DBIN_INSTALL_DIR:STRING=lib - -DLIB_INSTALL_DIR:STRING=lib - -DINCLUDE_INSTALL_DIR:STRING=include - -DCMAKE_PREFIX_PATH:PATH=${CMAKE_PREFIX_PATH} - -Wno-dev - ) - - if(${CMAKE_BUILD_TYPE} AND ${CMAKE_BUILD_TYPE} EQUAL "Debug") - set(QMDNS_LOGGING 1) - else () - set(QMDNS_LOGGING 0) - endif () - - configure_file(${CMAKE_SOURCE_DIR}/dependencies/CMakeLists-qmdnsengine.txt.in ${QMDNS_WORK_DIR}/CMakeLists.txt @ONLY) - execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${QMDNS_WORK_DIR}) - execute_process(COMMAND ${CMAKE_COMMAND} --build . --config "${CMAKE_BUILD_TYPE}" WORKING_DIRECTORY ${QMDNS_WORK_DIR}) - endif() - - set(QMDNS_INCLUDE_DIR "${CMAKE_BINARY_DIR}/include") - if(WIN32) set(QMDNS_LIBRARIES ${CMAKE_BINARY_DIR}/lib/qmdnsengine${CMAKE_STATIC_LIBRARY_SUFFIX}) else() set(QMDNS_LIBRARIES ${CMAKE_BINARY_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}qmdnsengine${CMAKE_STATIC_LIBRARY_SUFFIX}) endif() - mark_as_advanced (QMDNS_INCLUDE_DIR QMDNS_LIBRARIES) + get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + set(QMDNS_CMAKE_ARGS + -DBUILD_SHARED_LIBS:BOOL=OFF + -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR} + -DBIN_INSTALL_DIR:STRING=lib + -DLIB_INSTALL_DIR:STRING=lib + -DINCLUDE_INSTALL_DIR:STRING=include + -DCMAKE_PREFIX_PATH:PATH=${CMAKE_PREFIX_PATH} + $<$>:-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}> + -Wno-dev + ) + + include(ExternalProject) + ExternalProject_Add(qmdns + PREFIX ${CMAKE_BINARY_DIR}/dependencies/external/qmdnsengine + BUILD_ALWAYS OFF + DOWNLOAD_COMMAND "" + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/qmdnsengine + BINARY_DIR ${CMAKE_BINARY_DIR}/dependencies/external/qmdnsengine/build + CMAKE_ARGS ${QMDNS_CMAKE_ARGS} + CONFIGURE_COMMAND ${CMAKE_COMMAND} -S -B ${QMDNS_CMAKE_ARGS} -G ${CMAKE_GENERATOR} + BUILD_COMMAND ${CMAKE_COMMAND} --build --config $ + INSTALL_DIR ${CMAKE_BINARY_DIR} + BUILD_BYPRODUCTS ${QMDNS_LIBRARIES} + ) + + add_library(qmdnsengine STATIC IMPORTED GLOBAL) + set_target_properties(qmdnsengine PROPERTIES + IMPORTED_LOCATION ${QMDNS_LIBRARIES} + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_BINARY_DIR}/include + ) + + add_dependencies(qmdnsengine qmdns) endif () - - set(QMDNS_INCLUDE_DIR ${QMDNS_INCLUDE_DIR} PARENT_SCOPE) - set(QMDNS_LIBRARIES ${QMDNS_LIBRARIES} PARENT_SCOPE) - include_directories(${QMDNS_INCLUDE_DIR}) endif() #============================================================================= @@ -75,8 +75,18 @@ if(ENABLE_FLATBUF_SERVER OR ENABLE_FLATBUF_CONNECT) if (USE_SYSTEM_FLATBUFFERS_LIBS) find_program(FLATBUFFERS_FLATC_EXECUTABLE NAMES flatc REQUIRED) - find_package(Flatbuffers REQUIRED) - else () + find_package(Flatbuffers QUIET) + if (NOT Flatbuffers_FOUND) + find_package(FlatBuffers QUIET) + if (NOT FlatBuffers_FOUND) + message(STATUS "Could not find Flatbuffers system library, build static Flatbuffers library") + set(DEFAULT_USE_SYSTEM_FLATBUFFERS_LIBS OFF PARENT_SCOPE) + set(USE_SYSTEM_FLATBUFFERS_LIBS OFF) + endif() + endif() + endif() + + if (NOT USE_SYSTEM_FLATBUFFERS_LIBS) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared flatbuffers library") set(FLATBUFFERS_BUILD_TESTS OFF CACHE BOOL "Build Flatbuffers with tests") add_subdirectory(external/flatbuffers) @@ -133,9 +143,9 @@ endif() if(ENABLE_PROTOBUF_SERVER) set(USE_SYSTEM_PROTO_LIBS ${DEFAULT_USE_SYSTEM_PROTO_LIBS} CACHE BOOL "use protobuf library from system") - + # defines for 3rd party sub-modules - set(ABSL_PROPAGATE_CXX_STD ON CACHE BOOL "Build abseil-cpp with C++ version requirements propagated") + set(ABSL_PROPAGATE_CXX_STD ON CACHE BOOL "Build abseil-cpp with C++ version requirements propagated") if (USE_SYSTEM_PROTO_LIBS) find_package(Protobuf REQUIRED) @@ -163,7 +173,7 @@ if(ENABLE_PROTOBUF_SERVER) # define the protobuf library set(PROTOBUF_LIBRARIES protobuf::libprotobuf) - + endif() # redefine at parent scope diff --git a/dependencies/external/mbedtls b/dependencies/external/mbedtls index 1873d3bfc..edb8fec98 160000 --- a/dependencies/external/mbedtls +++ b/dependencies/external/mbedtls @@ -1 +1 @@ -Subproject commit 1873d3bfc2da771672bd8e7e8f41f57e0af77f33 +Subproject commit edb8fec9882084344a314368ac7fd957a187519c diff --git a/include/grabber/OsxFrameGrabberMock.h b/include/grabber/OsxFrameGrabberMock.h deleted file mode 100644 index bdc622c4a..000000000 --- a/include/grabber/OsxFrameGrabberMock.h +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once -#ifndef __APPLE__ - -/* - * this is a mock up for compiling and testing osx wrapper on no osx platform. - * this will show a test image and rotate the colors. - * - * see https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.8.sdk/System/Library/Frameworks/CoreGraphics.framework/Versions/A/Headers - * - */ - -#include -#include - -enum _CGError { - kCGErrorSuccess = 0, - kCGErrorFailure = 1000, - kCGErrorIllegalArgument = 1001, - kCGErrorInvalidConnection = 1002, - kCGErrorInvalidContext = 1003, - kCGErrorCannotComplete = 1004, - kCGErrorNotImplemented = 1006, - kCGErrorRangeCheck = 1007, - kCGErrorTypeCheck = 1008, - kCGErrorInvalidOperation = 1010, - kCGErrorNoneAvailable = 1011, - - /* Obsolete errors. */ - kCGErrorNameTooLong = 1005, - kCGErrorNoCurrentPoint = 1009, - kCGErrorApplicationRequiresNewerSystem = 1015, - kCGErrorApplicationNotPermittedToExecute = 1016, - kCGErrorApplicationIncorrectExecutableFormatFound = 1023, - kCGErrorApplicationIsLaunching = 1024, - kCGErrorApplicationAlreadyRunning = 1025, - kCGErrorApplicationCanOnlyBeRunInOneSessionAtATime = 1026, - kCGErrorClassicApplicationsMustBeLaunchedByClassic = 1027, - kCGErrorForkFailed = 1028, - kCGErrorRetryRegistration = 1029, - kCGErrorFirst = 1000, - kCGErrorLast = 1029 -}; -typedef int32_t CGError; -typedef double CGFloat; - -struct CGSize { - CGFloat width; - CGFloat height; -}; -typedef struct CGSize CGSize; - -struct CGPoint { - float x; - float y; -}; -typedef struct CGPoint CGPoint; - -struct CGRect { - CGPoint origin; - CGSize size; -}; -typedef struct CGRect CGRect; - -typedef CGError CGDisplayErr; -typedef uint32_t CGDirectDisplayID; -typedef uint32_t CGDisplayCount;; -typedef struct CGDisplayMode *CGDisplayModeRef; - -typedef Image CGImage; -typedef CGImage* CGImageRef; -typedef unsigned char CFData; -typedef CFData* CFDataRef; - -const int kCGDirectMainDisplay = 0; - -CGError CGGetActiveDisplayList(uint32_t maxDisplays, CGDirectDisplayID *activeDisplays, uint32_t *displayCount); -CGDisplayModeRef CGDisplayCopyDisplayMode(CGDirectDisplayID display); -CGRect CGDisplayBounds(CGDirectDisplayID display); -void CGDisplayModeRelease(CGDisplayModeRef mode); - -CGImageRef CGDisplayCreateImage(CGDirectDisplayID display); -void CGImageRelease(CGImageRef image); -CGImageRef CGImageGetDataProvider(CGImageRef image); -CFDataRef CGDataProviderCopyData(CGImageRef image); -unsigned char* CFDataGetBytePtr(CFDataRef imgData); -unsigned CGImageGetWidth(CGImageRef image); -unsigned CGImageGetHeight(CGImageRef image); -unsigned CGImageGetBitsPerPixel(CGImageRef image); -unsigned CGImageGetBytesPerRow(CGImageRef image); -void CFRelease(CFDataRef imgData); - - -#endif diff --git a/include/grabber/AmlogicGrabber.h b/include/grabber/amlogic/AmlogicGrabber.h similarity index 97% rename from include/grabber/AmlogicGrabber.h rename to include/grabber/amlogic/AmlogicGrabber.h index 972313544..f61742aa8 100644 --- a/include/grabber/AmlogicGrabber.h +++ b/include/grabber/amlogic/AmlogicGrabber.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include /// /// diff --git a/include/grabber/AmlogicWrapper.h b/include/grabber/amlogic/AmlogicWrapper.h similarity index 95% rename from include/grabber/AmlogicWrapper.h rename to include/grabber/amlogic/AmlogicWrapper.h index 87796bcd9..d97c45c10 100644 --- a/include/grabber/AmlogicWrapper.h +++ b/include/grabber/amlogic/AmlogicWrapper.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include /// /// The Amlogic uses an instance of the AmlogicGrabber to obtain ImageRgb's from the diff --git a/include/grabber/AudioGrabber.h b/include/grabber/audio/AudioGrabber.h similarity index 100% rename from include/grabber/AudioGrabber.h rename to include/grabber/audio/AudioGrabber.h diff --git a/include/grabber/AudioGrabberLinux.h b/include/grabber/audio/AudioGrabberLinux.h similarity index 86% rename from include/grabber/AudioGrabberLinux.h rename to include/grabber/audio/AudioGrabberLinux.h index 0f19ae6c1..272ab2f53 100644 --- a/include/grabber/AudioGrabberLinux.h +++ b/include/grabber/audio/AudioGrabberLinux.h @@ -6,7 +6,7 @@ #include // Hyperion-utils includes -#include +#include /// /// @brief The Linux Audio capture implementation @@ -18,74 +18,69 @@ class AudioGrabberLinux : public AudioGrabber AudioGrabberLinux(); ~AudioGrabberLinux() override; - /// + /// /// Process audio buffer /// void processAudioBuffer(snd_pcm_sframes_t frames); - /// + /// /// Is Running Flag /// std::atomic _isRunning; - /// + /// /// Current capture device /// snd_pcm_t * _captureDevice; public slots: - /// + /// /// Start audio capturing session /// /// @returns true if successful bool start() override; - /// + /// /// Stop audio capturing session /// void stop() override; - /// + /// /// Discovery audio devices /// QJsonArray discover(const QJsonObject& params) override; private: - /// + /// /// Refresh audio devices /// void refreshDevices(); - /// + /// /// Configure current audio capture interface /// bool configureCaptureInterface(); - /// + /// /// Get device name from path /// QString getDeviceName(const QString& devicePath) const; - /// + /// /// Current sample rate /// unsigned int _sampleRate; - /// + /// /// Audio capture thread /// pthread_t _audioThread; - /// + /// /// ALSA device configuration parameters /// snd_pcm_hw_params_t * _captureDeviceConfig; }; -/// -/// Audio processing thread function -/// -static void* AudioThreadRunner(void* params); - #endif // AUDIOGRABBERLINUX_H diff --git a/include/grabber/AudioGrabberWindows.h b/include/grabber/audio/AudioGrabberWindows.h similarity index 98% rename from include/grabber/AudioGrabberWindows.h rename to include/grabber/audio/AudioGrabberWindows.h index 9c3945b6d..ee7f53c42 100644 --- a/include/grabber/AudioGrabberWindows.h +++ b/include/grabber/audio/AudioGrabberWindows.h @@ -2,7 +2,7 @@ #define AUDIOGRABBERWINDOWS_H // Hyperion-utils includes -#include +#include #include /// @@ -14,7 +14,7 @@ class AudioGrabberWindows : public AudioGrabber AudioGrabberWindows(); ~AudioGrabberWindows() override; - + public slots: bool start() override; void stop() override; diff --git a/include/grabber/AudioWrapper.h b/include/grabber/audio/AudioWrapper.h similarity index 90% rename from include/grabber/AudioWrapper.h rename to include/grabber/audio/AudioWrapper.h index 9e13c933d..4f3017908 100644 --- a/include/grabber/AudioWrapper.h +++ b/include/grabber/audio/AudioWrapper.h @@ -3,14 +3,14 @@ #include #ifdef WIN32 - #include + #include #endif #ifdef __linux__ - #include + #include #endif -/// +/// /// Audio Grabber wrapper /// class AudioWrapper : public GrabberWrapper @@ -32,7 +32,7 @@ class AudioWrapper : public GrabberWrapper /// ~AudioWrapper() override; - /// + /// /// Settings update handler /// void handleSettingsUpdate(settings::type type, const QJsonDocument& config) override; @@ -43,13 +43,13 @@ class AudioWrapper : public GrabberWrapper /// void action() override; - /// + /// /// Start audio capturing session /// /// @returns true if successful bool start() override; - /// + /// /// Stop audio capturing session /// void stop() override; diff --git a/include/grabber/DirectXGrabber.h b/include/grabber/directx/DirectXGrabber.h similarity index 100% rename from include/grabber/DirectXGrabber.h rename to include/grabber/directx/DirectXGrabber.h diff --git a/include/grabber/DirectXWrapper.h b/include/grabber/directx/DirectXWrapper.h similarity index 96% rename from include/grabber/DirectXWrapper.h rename to include/grabber/directx/DirectXWrapper.h index d063497da..56ec68798 100644 --- a/include/grabber/DirectXWrapper.h +++ b/include/grabber/directx/DirectXWrapper.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include class DirectXWrapper: public GrabberWrapper { diff --git a/include/grabber/DispmanxFrameGrabber.h b/include/grabber/dispmanx/DispmanxFrameGrabber.h similarity index 100% rename from include/grabber/DispmanxFrameGrabber.h rename to include/grabber/dispmanx/DispmanxFrameGrabber.h diff --git a/include/grabber/DispmanxWrapper.h b/include/grabber/dispmanx/DispmanxWrapper.h similarity index 95% rename from include/grabber/DispmanxWrapper.h rename to include/grabber/dispmanx/DispmanxWrapper.h index 303391fa9..499316fc4 100644 --- a/include/grabber/DispmanxWrapper.h +++ b/include/grabber/dispmanx/DispmanxWrapper.h @@ -3,7 +3,7 @@ // Utils includes #include #include -#include +#include /// /// The DispmanxWrapper uses an instance of the DispmanxFrameGrabber to obtain ImageRgb's from the diff --git a/include/grabber/FramebufferFrameGrabber.h b/include/grabber/framebuffer/FramebufferFrameGrabber.h similarity index 100% rename from include/grabber/FramebufferFrameGrabber.h rename to include/grabber/framebuffer/FramebufferFrameGrabber.h diff --git a/include/grabber/FramebufferWrapper.h b/include/grabber/framebuffer/FramebufferWrapper.h similarity index 94% rename from include/grabber/FramebufferWrapper.h rename to include/grabber/framebuffer/FramebufferWrapper.h index 2098d362a..084eb96cb 100644 --- a/include/grabber/FramebufferWrapper.h +++ b/include/grabber/framebuffer/FramebufferWrapper.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include /// /// The FramebufferWrapper uses an instance of the FramebufferFrameGrabber to obtain ImageRgb's from the diff --git a/include/grabber/OsxFrameGrabber.h b/include/grabber/osx/OsxFrameGrabber.h similarity index 95% rename from include/grabber/OsxFrameGrabber.h rename to include/grabber/osx/OsxFrameGrabber.h index 175308887..afb430fc5 100644 --- a/include/grabber/OsxFrameGrabber.h +++ b/include/grabber/osx/OsxFrameGrabber.h @@ -1,11 +1,7 @@ #pragma once // OSX includes -#ifdef __APPLE__ #include -#else -#include -#endif // Utils includes #include diff --git a/include/grabber/OsxWrapper.h b/include/grabber/osx/OsxWrapper.h similarity index 95% rename from include/grabber/OsxWrapper.h rename to include/grabber/osx/OsxWrapper.h index c9520f7e9..fd367184b 100644 --- a/include/grabber/OsxWrapper.h +++ b/include/grabber/osx/OsxWrapper.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include /// /// The OsxWrapper uses an instance of the OsxFrameGrabber to obtain ImageRgb's from the displayed content. diff --git a/include/grabber/QtGrabber.h b/include/grabber/qt/QtGrabber.h similarity index 100% rename from include/grabber/QtGrabber.h rename to include/grabber/qt/QtGrabber.h diff --git a/include/grabber/QtWrapper.h b/include/grabber/qt/QtWrapper.h similarity index 97% rename from include/grabber/QtWrapper.h rename to include/grabber/qt/QtWrapper.h index 3bba4a821..3df2a64e6 100644 --- a/include/grabber/QtWrapper.h +++ b/include/grabber/qt/QtWrapper.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include /// /// The QtWrapper uses QtFramework API's to get a picture from system diff --git a/include/grabber/EncoderThread.h b/include/grabber/video/EncoderThread.h similarity index 91% rename from include/grabber/EncoderThread.h rename to include/grabber/video/EncoderThread.h index 93a3ed882..51008d3ed 100644 --- a/include/grabber/EncoderThread.h +++ b/include/grabber/video/EncoderThread.h @@ -136,11 +136,11 @@ class EncoderThreadManager : public QObject public: explicit EncoderThreadManager(QObject *parent = nullptr) : QObject(parent) - , _threadCount(static_cast(qMax(QThread::idealThreadCount(), DEFAULT_THREAD_COUNT))) + , _threadCount(qMax(QThread::idealThreadCount(), DEFAULT_THREAD_COUNT)) , _threads(nullptr) { _threads = new Thread*[_threadCount]; - for (unsigned long i = 0; i < _threadCount; i++) + for (int i = 0; i < _threadCount; i++) { _threads[i] = new Thread(new EncoderThread, this); _threads[i]->setObjectName("Encoder " + QString::number(i)); @@ -151,7 +151,7 @@ class EncoderThreadManager : public QObject { if (_threads != nullptr) { - for(unsigned long i = 0; i < _threadCount; i++) + for(int i = 0; i < _threadCount; i++) { _threads[i]->deleteLater(); _threads[i] = nullptr; @@ -165,18 +165,18 @@ class EncoderThreadManager : public QObject void start() { if (_threads != nullptr) - for (unsigned long i = 0; i < _threadCount; i++) + for (int i = 0; i < _threadCount; i++) connect(_threads[i]->thread(), &EncoderThread::newFrame, this, &EncoderThreadManager::newFrame); } void stop() { if (_threads != nullptr) - for(unsigned long i = 0; i < _threadCount; i++) + for(int i = 0; i < _threadCount; i++) disconnect(_threads[i]->thread(), nullptr, nullptr, nullptr); } - unsigned long _threadCount; + int _threadCount; Thread** _threads; signals: diff --git a/include/grabber/VideoWrapper.h b/include/grabber/video/VideoWrapper.h similarity index 89% rename from include/grabber/VideoWrapper.h rename to include/grabber/video/VideoWrapper.h index 932ff1ab6..19422f251 100644 --- a/include/grabber/VideoWrapper.h +++ b/include/grabber/video/VideoWrapper.h @@ -4,9 +4,9 @@ #include #if defined(ENABLE_MF) - #include + #include #elif defined(ENABLE_V4L2) - #include + #include #endif #if defined(ENABLE_CEC) diff --git a/include/grabber/MFGrabber.h b/include/grabber/video/mediafoundation/MFGrabber.h similarity index 98% rename from include/grabber/MFGrabber.h rename to include/grabber/video/mediafoundation/MFGrabber.h index f778f8e89..301420698 100644 --- a/include/grabber/MFGrabber.h +++ b/include/grabber/video/mediafoundation/MFGrabber.h @@ -21,7 +21,7 @@ #include // decoder thread includes -#include +#include /// Forward class declaration class SourceReaderCB; diff --git a/include/grabber/V4L2Grabber.h b/include/grabber/video/v4l2/V4L2Grabber.h similarity index 99% rename from include/grabber/V4L2Grabber.h rename to include/grabber/video/v4l2/V4L2Grabber.h index 22f8cdba9..6c72be949 100644 --- a/include/grabber/V4L2Grabber.h +++ b/include/grabber/video/v4l2/V4L2Grabber.h @@ -19,7 +19,7 @@ #include // decoder thread includes -#include +#include // Determine the cmake options #include diff --git a/include/grabber/X11Grabber.h b/include/grabber/x11/X11Grabber.h similarity index 100% rename from include/grabber/X11Grabber.h rename to include/grabber/x11/X11Grabber.h diff --git a/include/grabber/X11Wrapper.h b/include/grabber/x11/X11Wrapper.h similarity index 97% rename from include/grabber/X11Wrapper.h rename to include/grabber/x11/X11Wrapper.h index 79b6da925..dae62ad70 100644 --- a/include/grabber/X11Wrapper.h +++ b/include/grabber/x11/X11Wrapper.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include // some include of xorg defines "None" this is also used by QT and has to be undefined to avoid collisions #ifdef None #undef None diff --git a/include/grabber/XcbGrabber.h b/include/grabber/xcb/XcbGrabber.h similarity index 100% rename from include/grabber/XcbGrabber.h rename to include/grabber/xcb/XcbGrabber.h diff --git a/include/grabber/XcbWrapper.h b/include/grabber/xcb/XcbWrapper.h similarity index 94% rename from include/grabber/XcbWrapper.h rename to include/grabber/xcb/XcbWrapper.h index 71bb70ea9..0292937c1 100644 --- a/include/grabber/XcbWrapper.h +++ b/include/grabber/xcb/XcbWrapper.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include // some include of xorg defines "None" this is also used by QT and has to be undefined to avoid collisions #ifdef None diff --git a/include/hyperion/ImageToLedsMap.h b/include/hyperion/ImageToLedsMap.h index 45e7bb5ab..d720581a5 100644 --- a/include/hyperion/ImageToLedsMap.h +++ b/include/hyperion/ImageToLedsMap.h @@ -555,7 +555,7 @@ namespace hyperion if (pixelNum > 0) { // initial cluster with different colors - auto clusters = std::unique_ptr< ColorCluster >(new ColorCluster[_clusterCount]); + std::unique_ptr[]> clusters(new ColorCluster[_clusterCount]); for(int k = 0; k < _clusterCount; ++k) { clusters.get()[k].newColor = DEFAULT_CLUSTER_COLORS[k]; diff --git a/include/utils/Process.h b/include/utils/Process.h index f8da8e65b..07df2fe78 100644 --- a/include/utils/Process.h +++ b/include/utils/Process.h @@ -3,9 +3,8 @@ #include #include -namespace Process { - -void restartHyperion(int exitCode = 0); -QByteArray command_exec(const QString& cmd, const QByteArray& data = {}); - +namespace Process +{ + void restartHyperion(int exitCode = 0); + QByteArray command_exec(const QString& cmd, const QByteArray& data = {}); } diff --git a/libsrc/CMakeLists.txt b/libsrc/CMakeLists.txt index ba5716ba2..7acad42a0 100644 --- a/libsrc/CMakeLists.txt +++ b/libsrc/CMakeLists.txt @@ -1,7 +1,7 @@ # Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc) +set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include) +set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc) add_subdirectory(hyperion) add_subdirectory(commandline) @@ -34,7 +34,7 @@ add_subdirectory(ssdp) if(ENABLE_MDNS) add_subdirectory(mdns) -endif() +endif() if(ENABLE_EFFECTENGINE) add_subdirectory(effectengine) diff --git a/libsrc/api/CMakeLists.txt b/libsrc/api/CMakeLists.txt index 3fd822ffc..ac5cdcfd9 100644 --- a/libsrc/api/CMakeLists.txt +++ b/libsrc/api/CMakeLists.txt @@ -1,26 +1,20 @@ -# Define the current source locations - -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/api) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/api) - -FILE ( GLOB_RECURSE Api_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -set(Api_RESOURCES ${CURRENT_SOURCE_DIR}/JSONRPC_schemas.qrc ) - add_library(hyperion-api - ${Api_SOURCES} - ${Api_RESOURCES} + ${CMAKE_SOURCE_DIR}/include/api/apiStructs.h + ${CMAKE_SOURCE_DIR}/include/api/API.h + ${CMAKE_SOURCE_DIR}/include/api/JsonAPI.h + ${CMAKE_SOURCE_DIR}/include/api/JsonCB.h + ${CMAKE_SOURCE_DIR}/libsrc/api/JsonAPI.cpp + ${CMAKE_SOURCE_DIR}/libsrc/api/API.cpp + ${CMAKE_SOURCE_DIR}/libsrc/api/JsonCB.cpp + ${CMAKE_SOURCE_DIR}/libsrc/api/JSONRPC_schemas.qrc ) -if(ENABLE_DX) - include_directories(${DIRECTX9_INCLUDE_DIRS}) - target_link_libraries(hyperion-api ${DIRECTX9_LIBRARIES}) -endif(ENABLE_DX) - target_link_libraries(hyperion-api hyperion hyperion-utils - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Gui - Qt${QT_VERSION_MAJOR}::Network + ${DIRECTX9_LIBRARIES} +) + +target_include_directories(hyperion-api PRIVATE + ${DIRECTX9_INCLUDE_DIRS} ) diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 75863ca22..abc62a6fe 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -19,54 +19,54 @@ #include // Required to determine the cmake options #include -#include +#include #include #if defined(ENABLE_MF) - #include + #include #elif defined(ENABLE_V4L2) - #include + #include #endif #if defined(ENABLE_AUDIO) - #include + #include #ifdef WIN32 - #include + #include #endif #ifdef __linux__ - #include + #include #endif #endif #if defined(ENABLE_X11) - #include + #include #endif #if defined(ENABLE_XCB) - #include + #include #endif #if defined(ENABLE_DX) - #include + #include #endif #if defined(ENABLE_FB) - #include + #include #endif #if defined(ENABLE_DISPMANX) - #include + #include #endif #if defined(ENABLE_AMLOGIC) - #include + #include #endif #if defined(ENABLE_OSX) - #include + #include #endif #include diff --git a/libsrc/blackborder/CMakeLists.txt b/libsrc/blackborder/CMakeLists.txt index e93c5e472..d49454d82 100644 --- a/libsrc/blackborder/CMakeLists.txt +++ b/libsrc/blackborder/CMakeLists.txt @@ -1,11 +1,9 @@ - -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/blackborder) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/blackborder) - -FILE ( GLOB Blackborder_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -add_library(blackborder ${Blackborder_SOURCES} ) +add_library(blackborder + ${CMAKE_SOURCE_DIR}/include/blackborder/BlackBorderDetector.h + ${CMAKE_SOURCE_DIR}/include/blackborder/BlackBorderProcessor.h + ${CMAKE_SOURCE_DIR}/libsrc/blackborder/BlackBorderDetector.cpp + ${CMAKE_SOURCE_DIR}/libsrc/blackborder/BlackBorderProcessor.cpp +) target_link_libraries(blackborder hyperion-utils diff --git a/libsrc/boblightserver/CMakeLists.txt b/libsrc/boblightserver/CMakeLists.txt index 1587d4df3..44ff51624 100644 --- a/libsrc/boblightserver/CMakeLists.txt +++ b/libsrc/boblightserver/CMakeLists.txt @@ -1,14 +1,11 @@ - -# Define the current source locations -set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/boblightserver) -set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/boblightserver) - -FILE ( GLOB BoblightServer_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -add_library(boblightserver ${BoblightServer_SOURCES} ) +add_library(boblightserver + ${CMAKE_SOURCE_DIR}/include/boblightserver/BoblightServer.h + ${CMAKE_SOURCE_DIR}/libsrc/boblightserver/BoblightServer.cpp + ${CMAKE_SOURCE_DIR}/libsrc/boblightserver/BoblightClientConnection.h + ${CMAKE_SOURCE_DIR}/libsrc/boblightserver/BoblightClientConnection.cpp +) target_link_libraries(boblightserver hyperion hyperion-utils - ${QT_LIBRARIES} ) diff --git a/libsrc/cec/CMakeLists.txt b/libsrc/cec/CMakeLists.txt index dfd80e7d2..711c33d1d 100644 --- a/libsrc/cec/CMakeLists.txt +++ b/libsrc/cec/CMakeLists.txt @@ -1,19 +1,18 @@ -# Define the current source locations find_package(CEC REQUIRED) +if(CEC_FOUND) + list(GET CEC_LIBRARIES 0 CEC_LIBRARIES) + add_definitions(-DCEC_LIBRARY="${CEC_LIBRARIES}") +else() + message(FATAL_ERROR "libCEC not found") +endif() -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/cec) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/cec) - -FILE (GLOB CEC_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp") - -add_library(cechandler ${CEC_SOURCES}) -list(GET CEC_LIBRARIES 0 CEC_LIBRARIES) -add_definitions(-DCEC_LIBRARY="${CEC_LIBRARIES}") - -include_directories(${CEC_INCLUDE_DIRS}) +add_library(cechandler + ${CMAKE_SOURCE_DIR}/include/cec/CECEvent.h + ${CMAKE_SOURCE_DIR}/include/cec/CECHandler.h + ${CMAKE_SOURCE_DIR}/libsrc/cec/CECHandler.cpp +) target_link_libraries(cechandler Qt${QT_VERSION_MAJOR}::Core ${CMAKE_DL_LIBS} ) - diff --git a/libsrc/commandline/CMakeLists.txt b/libsrc/commandline/CMakeLists.txt index 63a403acf..cd7649138 100644 --- a/libsrc/commandline/CMakeLists.txt +++ b/libsrc/commandline/CMakeLists.txt @@ -1,10 +1,27 @@ -# Define the current source locations -set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/commandline) -set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/commandline) - -FILE ( GLOB Parser_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -add_library(commandline ${Parser_SOURCES} ) +add_library(commandline + ${CMAKE_SOURCE_DIR}/include/commandline/BooleanOption.h + ${CMAKE_SOURCE_DIR}/include/commandline/ColorOption.h + ${CMAKE_SOURCE_DIR}/include/commandline/ColorsOption.h + ${CMAKE_SOURCE_DIR}/include/commandline/DoubleOption.h + ${CMAKE_SOURCE_DIR}/include/commandline/ImageOption.h + ${CMAKE_SOURCE_DIR}/include/commandline/IntOption.h + ${CMAKE_SOURCE_DIR}/include/commandline/Option.h + ${CMAKE_SOURCE_DIR}/include/commandline/Parser.h + ${CMAKE_SOURCE_DIR}/include/commandline/RegularExpressionOption.h + ${CMAKE_SOURCE_DIR}/include/commandline/SwitchOption.h + ${CMAKE_SOURCE_DIR}/include/commandline/ValidatorOption.h + ${CMAKE_SOURCE_DIR}/libsrc/commandline/BooleanOption.cpp + ${CMAKE_SOURCE_DIR}/libsrc/commandline/ColorOption.cpp + ${CMAKE_SOURCE_DIR}/libsrc/commandline/ColorsOption.cpp + ${CMAKE_SOURCE_DIR}/libsrc/commandline/DoubleOption.cpp + ${CMAKE_SOURCE_DIR}/libsrc/commandline/ImageOption.cpp + ${CMAKE_SOURCE_DIR}/libsrc/commandline/IntOption.cpp + ${CMAKE_SOURCE_DIR}/libsrc/commandline/Option.cpp + ${CMAKE_SOURCE_DIR}/libsrc/commandline/Parser.cpp + ${CMAKE_SOURCE_DIR}/libsrc/commandline/RegularExpressionOption.cpp + ${CMAKE_SOURCE_DIR}/libsrc/commandline/SwitchOption.cpp + ${CMAKE_SOURCE_DIR}/libsrc/commandline/ValidatorOption.cpp +) target_link_libraries(commandline hyperion diff --git a/libsrc/db/CMakeLists.txt b/libsrc/db/CMakeLists.txt index b81991e6d..1beb3fe5d 100644 --- a/libsrc/db/CMakeLists.txt +++ b/libsrc/db/CMakeLists.txt @@ -1,16 +1,14 @@ -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/db) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/db) - -FILE ( GLOB DB_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - add_library(database - ${DB_SOURCES} + ${CMAKE_SOURCE_DIR}/include/db/AuthTable.h + ${CMAKE_SOURCE_DIR}/include/db/DBManager.h + ${CMAKE_SOURCE_DIR}/include/db/InstanceTable.h + ${CMAKE_SOURCE_DIR}/include/db/MetaTable.h + ${CMAKE_SOURCE_DIR}/include/db/SettingsTable.h + ${CMAKE_SOURCE_DIR}/libsrc/db/DBManager.cpp ) target_link_libraries(database hyperion hyperion-utils - Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Sql ) diff --git a/libsrc/effectengine/CMakeLists.txt b/libsrc/effectengine/CMakeLists.txt index 0059648e4..27ba48c01 100644 --- a/libsrc/effectengine/CMakeLists.txt +++ b/libsrc/effectengine/CMakeLists.txt @@ -1,47 +1,30 @@ -if (NOT CMAKE_VERSION VERSION_LESS "3.12") - find_package(Python3 COMPONENTS Interpreter Development REQUIRED) -else() - find_package (PythonLibs ${PYTHON_VERSION_STRING} EXACT) # Maps PythonLibs to the PythonInterp version of the main cmake -endif() +file(GLOB effectFiles RELATIVE ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/effects/*) +set(HYPERION_EFFECTS_RES "") +foreach(f ${effectFiles}) + get_filename_component(fname ${f} NAME) + set(HYPERION_EFFECTS_RES "${HYPERION_EFFECTS_RES}\n\t\t${f}") +endforeach() -# Include the python directory. Also include the parent (which is for example /usr/include) -# which may be required when it is not includes by the (cross-) compiler by default. -if (NOT CMAKE_VERSION VERSION_LESS "3.12") - include_directories(${Python3_INCLUDE_DIRS} ${Python3_INCLUDE_DIRS}/..) -else() - include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/..) -endif() - -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/effectengine) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/effectengine) - -FILE ( GLOB EffectEngineSOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) -FILE ( GLOB effectFiles RELATIVE ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/effects/* ) - -SET ( HYPERION_EFFECTS_RES "") -FOREACH( f ${effectFiles} ) - GET_FILENAME_COMPONENT(fname ${f} NAME) - SET(HYPERION_EFFECTS_RES "${HYPERION_EFFECTS_RES}\n\t\t${f}") -ENDFOREACH() -CONFIGURE_FILE(${CURRENT_SOURCE_DIR}/EffectEngine.qrc.in ${CMAKE_BINARY_DIR}/EffectEngine.qrc ) - -SET(EffectEngine_RESOURCES ${CMAKE_BINARY_DIR}/EffectEngine.qrc) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/EffectEngine.qrc.in ${CMAKE_BINARY_DIR}/EffectEngine.qrc) add_library(effectengine - ${EffectEngine_RESOURCES} - ${EffectEngineSOURCES} + ${CMAKE_BINARY_DIR}/EffectEngine.qrc + ${CMAKE_SOURCE_DIR}/include/effectengine/ActiveEffectDefinition.h + ${CMAKE_SOURCE_DIR}/include/effectengine/Effect.h + ${CMAKE_SOURCE_DIR}/include/effectengine/EffectDefinition.h + ${CMAKE_SOURCE_DIR}/include/effectengine/EffectEngine.h + ${CMAKE_SOURCE_DIR}/include/effectengine/EffectFileHandler.h + ${CMAKE_SOURCE_DIR}/include/effectengine/EffectModule.h + ${CMAKE_SOURCE_DIR}/include/effectengine/EffectSchema.h + ${CMAKE_SOURCE_DIR}/libsrc/effectengine/Effect.cpp + ${CMAKE_SOURCE_DIR}/libsrc/effectengine/EffectEngine.cpp + ${CMAKE_SOURCE_DIR}/libsrc/effectengine/EffectFileHandler.cpp + ${CMAKE_SOURCE_DIR}/libsrc/effectengine/EffectModule.cpp ) target_link_libraries(effectengine - hyperion python + hyperion Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui ) - -if (NOT CMAKE_VERSION VERSION_LESS "3.12") - target_link_libraries( effectengine ${Python3_LIBRARIES} ) -else() - target_link_libraries( effectengine ${PYTHON_LIBRARIES} ) -endif() diff --git a/libsrc/effectengine/EffectEngine.qrc.in b/libsrc/effectengine/EffectEngine.qrc.in index 2816f96bc..2e43ab6d6 100644 --- a/libsrc/effectengine/EffectEngine.qrc.in +++ b/libsrc/effectengine/EffectEngine.qrc.in @@ -1,6 +1,6 @@ - ${CURRENT_SOURCE_DIR}/EffectDefinition.schema.json + ${CMAKE_CURRENT_SOURCE_DIR}/EffectDefinition.schema.json ${HYPERION_EFFECTS_RES} diff --git a/libsrc/flatbufserver/CMakeLists.txt b/libsrc/flatbufserver/CMakeLists.txt index 836652f8b..5e8795174 100644 --- a/libsrc/flatbufserver/CMakeLists.txt +++ b/libsrc/flatbufserver/CMakeLists.txt @@ -1,69 +1,54 @@ +# set (compiled) Flatbuffer schema names +set(FBS_Request "hyperion_request") +set(FBS_Reply "hyperion_reply") -# Define the current source locations -set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/flatbufserver) -set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/flatbufserver) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ${FLATBUFFERS_INCLUDE_DIRS} -) - -set(Flatbuffer_GENERATED_FBS - hyperion_reply_generated.h - hyperion_request_generated.h -) - -set(Flatbuffer_FBS - ${CURRENT_SOURCE_DIR}/hyperion_reply.fbs - ${CURRENT_SOURCE_DIR}/hyperion_request.fbs -) -FOREACH(FBS_FILE ${Flatbuffer_FBS}) - compile_flattbuffer_schema(${FBS_FILE} ${CMAKE_CURRENT_SOURCE_DIR}) -ENDFOREACH(FBS_FILE) +# define and compile flatbuffer schemas +list(APPEND Compiled_FBS ${FBS_Request}_generated.h) +list(APPEND Compiled_FBS ${FBS_Reply}_generated.h) +compile_flattbuffer_schema(${CMAKE_CURRENT_SOURCE_DIR}/${FBS_Request}.fbs ${CMAKE_CURRENT_SOURCE_DIR}) +compile_flattbuffer_schema(${CMAKE_CURRENT_SOURCE_DIR}/${FBS_Reply}.fbs ${CMAKE_CURRENT_SOURCE_DIR}) # let cmake know about new generated source files -set_source_files_properties( - ${Flatbuffer_GENERATED_FBS} PROPERTIES GENERATED TRUE -) - -### Split flatbufconnect from flatbufserver as flatbufserver relates to HyperionDaemon +set_source_files_properties(${Compiled_FBS} PROPERTIES GENERATED TRUE) +# split flatbufconnect from flatbufserver as flatbufserver relates to HyperionDaemon if(ENABLE_FLATBUF_CONNECT) -add_library(flatbufconnect - ${CURRENT_HEADER_DIR}/FlatBufferConnection.h - ${CURRENT_SOURCE_DIR}/FlatBufferConnection.cpp - ${FLATBUFSERVER_SOURCES} - ${Flatbuffer_GENERATED_FBS} - -) -target_link_libraries(flatbufconnect - hyperion-utils - flatbuffers - Qt${QT_VERSION_MAJOR}::Network - Qt${QT_VERSION_MAJOR}::Core -) + add_library(flatbufconnect + ${CMAKE_SOURCE_DIR}/include/flatbufserver/FlatBufferConnection.h + ${CMAKE_SOURCE_DIR}/libsrc/flatbufserver/FlatBufferConnection.cpp + ${Compiled_FBS} + ) + + target_link_libraries(flatbufconnect + hyperion-utils + flatbuffers + ) + + target_include_directories(flatbufconnect PUBLIC + ${FLATBUFFERS_INCLUDE_DIRS} + ) endif() if(ENABLE_FLATBUF_SERVER) -add_library(flatbufserver - ${CURRENT_HEADER_DIR}/FlatBufferServer.h - ${CURRENT_SOURCE_DIR}/FlatBufferServer.cpp - ${CURRENT_SOURCE_DIR}/FlatBufferClient.h - ${CURRENT_SOURCE_DIR}/FlatBufferClient.cpp - ${FLATBUFSERVER_SOURCES} - ${Flatbuffer_GENERATED_FBS} -) - -target_link_libraries(flatbufserver -hyperion-utils -flatbuffers -Qt${QT_VERSION_MAJOR}::Network -Qt${QT_VERSION_MAJOR}::Core -) - -if(ENABLE_MDNS) - target_link_libraries(flatbufserver mdns) -endif() - + add_library(flatbufserver + ${CMAKE_SOURCE_DIR}/include/flatbufserver/FlatBufferServer.h + ${CMAKE_SOURCE_DIR}/libsrc/flatbufserver/FlatBufferServer.cpp + ${CMAKE_SOURCE_DIR}/libsrc/flatbufserver/FlatBufferClient.h + ${CMAKE_SOURCE_DIR}/libsrc/flatbufserver/FlatBufferClient.cpp + ${Compiled_FBS} + ) + + target_link_libraries(flatbufserver + hyperion-utils + flatbuffers + ) + + target_include_directories(flatbufserver PUBLIC + ${FLATBUFFERS_INCLUDE_DIRS} + ) + + if(ENABLE_MDNS) + target_link_libraries(flatbufserver mdns) + endif() endif() diff --git a/libsrc/forwarder/CMakeLists.txt b/libsrc/forwarder/CMakeLists.txt index 60dc5a6b8..a9ee88c14 100644 --- a/libsrc/forwarder/CMakeLists.txt +++ b/libsrc/forwarder/CMakeLists.txt @@ -1,22 +1,11 @@ - -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/forwarder) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/forwarder) - -if(ENABLE_FLATBUF_CONNECT) -include_directories( - ${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/flatbufserver +add_library(forwarder + ${CMAKE_SOURCE_DIR}/include/forwarder/MessageForwarder.h + ${CMAKE_SOURCE_DIR}/libsrc/forwarder/MessageForwarder.cpp ) -endif() - -FILE ( GLOB Forwarder_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -add_library(forwarder ${Forwarder_SOURCES} ) target_link_libraries(forwarder hyperion hyperion-utils - ${QT_LIBRARIES} ) if(ENABLE_FLATBUF_CONNECT) diff --git a/libsrc/grabber/CMakeLists.txt b/libsrc/grabber/CMakeLists.txt index c729ad0ad..75f8c5291 100644 --- a/libsrc/grabber/CMakeLists.txt +++ b/libsrc/grabber/CMakeLists.txt @@ -1,39 +1,39 @@ -if (ENABLE_AMLOGIC) +if(ENABLE_AMLOGIC) add_subdirectory(amlogic) endif (ENABLE_AMLOGIC) -if (ENABLE_DISPMANX) +if(ENABLE_DISPMANX) add_subdirectory(dispmanx) endif (ENABLE_DISPMANX) -if (ENABLE_FB) +if(ENABLE_FB) add_subdirectory(framebuffer) endif (ENABLE_FB) -if (ENABLE_OSX) +if(ENABLE_OSX) add_subdirectory(osx) endif(ENABLE_OSX) -if (ENABLE_V4L2 OR ENABLE_MF) +if(ENABLE_V4L2 OR ENABLE_MF) add_subdirectory(video) -endif () +endif() -if (ENABLE_X11) +if(ENABLE_X11) add_subdirectory(x11) endif(ENABLE_X11) -if (ENABLE_XCB) +if(ENABLE_XCB) add_subdirectory(xcb) endif(ENABLE_XCB) -if (ENABLE_QT) +if(ENABLE_QT) add_subdirectory(qt) endif(ENABLE_QT) -if (ENABLE_DX) +if(ENABLE_DX) add_subdirectory(directx) endif(ENABLE_DX) -if (ENABLE_AUDIO) +if(ENABLE_AUDIO) add_subdirectory(audio) endif() diff --git a/libsrc/grabber/amlogic/AmlogicGrabber.cpp b/libsrc/grabber/amlogic/AmlogicGrabber.cpp index 4c590d0c3..0f6b05875 100644 --- a/libsrc/grabber/amlogic/AmlogicGrabber.cpp +++ b/libsrc/grabber/amlogic/AmlogicGrabber.cpp @@ -20,7 +20,7 @@ // Local includes #include -#include +#include #include "Amvideocap.h" // Constants diff --git a/libsrc/grabber/amlogic/AmlogicWrapper.cpp b/libsrc/grabber/amlogic/AmlogicWrapper.cpp index 25581b2c3..ac371ba04 100644 --- a/libsrc/grabber/amlogic/AmlogicWrapper.cpp +++ b/libsrc/grabber/amlogic/AmlogicWrapper.cpp @@ -1,4 +1,4 @@ -#include +#include AmlogicWrapper::AmlogicWrapper(int pixelDecimation, int updateRate_Hz) : GrabberWrapper("Amlogic", &_grabber, updateRate_Hz) diff --git a/libsrc/grabber/amlogic/CMakeLists.txt b/libsrc/grabber/amlogic/CMakeLists.txt index 284f8b5f1..d59066d0d 100644 --- a/libsrc/grabber/amlogic/CMakeLists.txt +++ b/libsrc/grabber/amlogic/CMakeLists.txt @@ -1,13 +1,15 @@ -INCLUDE (CheckIncludeFiles) - -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/amlogic) - -FILE ( GLOB AmlogicSOURCES "${CURRENT_HEADER_DIR}/Amlogic*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -add_library(amlogic-grabber ${AmlogicSOURCES} ) +add_library(amlogic-grabber + ${CMAKE_SOURCE_DIR}/include/grabber/amlogic/AmlogicGrabber.h + ${CMAKE_SOURCE_DIR}/include/grabber/amlogic/AmlogicWrapper.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/amlogic/AmlogicGrabber.cpp + ${CMAKE_SOURCE_DIR}/libsrc/grabber/amlogic/AmlogicWrapper.cpp + ${CMAKE_SOURCE_DIR}/libsrc/grabber/amlogic/Amvideocap.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/amlogic/ion.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/amlogic/meson_ion.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/amlogic/IonBuffer.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/amlogic/IonBuffer.cpp +) target_link_libraries(amlogic-grabber hyperion - ${QT_LIBRARIES}) +) diff --git a/libsrc/grabber/audio/AudioGrabber.cpp b/libsrc/grabber/audio/AudioGrabber.cpp index 4f4eccbd8..995a1b7ca 100644 --- a/libsrc/grabber/audio/AudioGrabber.cpp +++ b/libsrc/grabber/audio/AudioGrabber.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/libsrc/grabber/audio/AudioGrabberLinux.cpp b/libsrc/grabber/audio/AudioGrabberLinux.cpp index 8938e043a..944b317db 100644 --- a/libsrc/grabber/audio/AudioGrabberLinux.cpp +++ b/libsrc/grabber/audio/AudioGrabberLinux.cpp @@ -1,11 +1,31 @@ -#include +#include #include #include #include -typedef void* (*THREADFUNCPTR)(void*); +static void * AudioThreadRunner(void* params) +{ + AudioGrabberLinux* This = static_cast(params); + + Debug(This->getLog(), "Audio Thread Started"); + + snd_pcm_sframes_t framesAvailable = 0; + + while (This->_isRunning.load(std::memory_order_acquire)) + { + snd_pcm_wait(This->_captureDevice, 1000); + + if ((framesAvailable = snd_pcm_avail(This->_captureDevice)) > 0) + This->processAudioBuffer(framesAvailable); + + sched_yield(); + } + + Debug(This->getLog(), "Audio Thread Shutting Down"); + return nullptr; +} AudioGrabberLinux::AudioGrabberLinux() : AudioGrabber() @@ -121,7 +141,7 @@ bool AudioGrabberLinux::configureCaptureInterface() snd_pcm_close(_captureDevice); return false; } - + if ((error = snd_pcm_hw_params_set_access(_captureDevice, _captureDeviceConfig, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { Error(_log, "Failed to configure interleaved mode: %s", snd_strerror(error)); @@ -129,7 +149,7 @@ bool AudioGrabberLinux::configureCaptureInterface() snd_pcm_close(_captureDevice); return false; } - + if ((error = snd_pcm_hw_params_set_format(_captureDevice, _captureDeviceConfig, SND_PCM_FORMAT_S16_LE)) < 0) { Error(_log, "Failed to configure capture format: %s", snd_strerror(error)); @@ -169,7 +189,7 @@ bool AudioGrabberLinux::configureCaptureInterface() snd_pcm_close(_captureDevice); return false; } - + return true; } @@ -189,11 +209,6 @@ bool AudioGrabberLinux::start() _isRunning.store(true, std::memory_order_release); pthread_attr_t threadAttributes; - int threadPriority = 1; - - sched_param schedulerParameter; - schedulerParameter.sched_priority = threadPriority; - if (pthread_attr_init(&threadAttributes) != 0) { Debug(_log, "Failed to create thread attributes"); @@ -201,7 +216,7 @@ bool AudioGrabberLinux::start() return false; } - if (pthread_create(&_audioThread, &threadAttributes, static_cast(&AudioThreadRunner), static_cast(this)) != 0) + if (pthread_create(&_audioThread, &threadAttributes, &AudioThreadRunner, static_cast(this)) != 0) { Debug(_log, "Failed to create audio capture thread"); stop(); @@ -239,7 +254,7 @@ void AudioGrabberLinux::processAudioBuffer(snd_pcm_sframes_t frames) ssize_t bytes = snd_pcm_frames_to_bytes(_captureDevice, frames); int16_t * buffer = static_cast(calloc(static_cast(bytes / 2), sizeof(int16_t))); - + if (frames == 0) { buffer[0] = 0; @@ -293,25 +308,3 @@ QString AudioGrabberLinux::getDeviceName(const QString& devicePath) const return _deviceProperties.value(devicePath).name; } - -static void * AudioThreadRunner(void* params) -{ - AudioGrabberLinux* This = static_cast(params); - - Debug(This->getLog(), "Audio Thread Started"); - - snd_pcm_sframes_t framesAvailable = 0; - - while (This->_isRunning.load(std::memory_order_acquire)) - { - snd_pcm_wait(This->_captureDevice, 1000); - - if ((framesAvailable = snd_pcm_avail(This->_captureDevice)) > 0) - This->processAudioBuffer(framesAvailable); - - sched_yield(); - } - - Debug(This->getLog(), "Audio Thread Shutting Down"); - return nullptr; -} diff --git a/libsrc/grabber/audio/AudioGrabberWindows.cpp b/libsrc/grabber/audio/AudioGrabberWindows.cpp index 8a2228c36..d3d37597e 100644 --- a/libsrc/grabber/audio/AudioGrabberWindows.cpp +++ b/libsrc/grabber/audio/AudioGrabberWindows.cpp @@ -1,4 +1,4 @@ -#include +#include #include @@ -71,7 +71,7 @@ bool AudioGrabberWindows::configureCaptureInterface() notificationSize -= notificationSize % audioFormat.nBlockAlign; bufferCaptureSize = notificationSize * AUDIO_NOTIFICATION_COUNT; - + DSCBUFFERDESC bufferDesc; bufferDesc.dwSize = sizeof(DSCBUFFERDESC); bufferDesc.dwFlags = 0; @@ -80,7 +80,7 @@ bool AudioGrabberWindows::configureCaptureInterface() bufferDesc.lpwfxFormat = &audioFormat; bufferDesc.dwFXCount = 0; bufferDesc.lpDSCFXDesc = NULL; - + // Create Capture Device's Buffer LPDIRECTSOUNDCAPTUREBUFFER preBuffer; if (FAILED(recordingDevice->CreateCaptureBuffer(&bufferDesc, &preBuffer, NULL))) @@ -101,7 +101,7 @@ bool AudioGrabberWindows::configureCaptureInterface() } preBuffer->Release(); - + // Create Notifications LPDIRECTSOUNDNOTIFY8 notify; @@ -112,7 +112,7 @@ bool AudioGrabberWindows::configureCaptureInterface() recordingBuffer->Release(); return false; } - + // Create Events notificationEvent = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -133,11 +133,11 @@ bool AudioGrabberWindows::configureCaptureInterface() positionNotify[i].dwOffset = (notificationSize * i) + notificationSize - 1; positionNotify[i].hEventNotify = notificationEvent; } - + // Set Notifications notify->SetNotificationPositions(AUDIO_NOTIFICATION_COUNT, positionNotify); notify->Release(); - + return true; } @@ -162,12 +162,12 @@ bool AudioGrabberWindows::start() } Info(_log, "Capture audio from %s", QSTRING_CSTR(getDeviceName(_device))); - + if (!this->configureCaptureInterface()) { return false; } - + if (FAILED(recordingBuffer->Start(DSCBSTART_LOOPING))) { Error(_log, "Failed starting audio capture from '%s'", QSTRING_CSTR(getDeviceName(_device))); @@ -214,7 +214,7 @@ void AudioGrabberWindows::stop() { Error(_log, "Audio capture failed to stop: '%s'", QSTRING_CSTR(getDeviceName(_device))); } - + if (FAILED(recordingBuffer->Release())) { Error(_log, "Failed to release recording buffer: '%s'", QSTRING_CSTR(getDeviceName(_device))); @@ -306,7 +306,7 @@ void AudioGrabberWindows::processAudioBuffer() // Buffer wrapped around, read second position if (capturedAudio2 != NULL) - { + { bufferCapturePosition += capturedAudio2Length; bufferCapturePosition %= bufferCaptureSize; // Circular Buffer } @@ -318,13 +318,13 @@ void AudioGrabberWindows::processAudioBuffer() { CopyMemory(readBuffer + capturedAudioLength, capturedAudio2, capturedAudio2Length); } - + // Release Buffer Lock recordingBuffer->Unlock(capturedAudio, capturedAudioLength, capturedAudio2, capturedAudio2Length); - + // Process Audio Frame this->processAudioFrame(readBuffer, frameSize); - + delete[] readBuffer; } diff --git a/libsrc/grabber/audio/AudioWrapper.cpp b/libsrc/grabber/audio/AudioWrapper.cpp index 0dd624de0..2c47a3b80 100644 --- a/libsrc/grabber/audio/AudioWrapper.cpp +++ b/libsrc/grabber/audio/AudioWrapper.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/libsrc/grabber/audio/CMakeLists.txt b/libsrc/grabber/audio/CMakeLists.txt index 714c58832..f60ee7758 100644 --- a/libsrc/grabber/audio/CMakeLists.txt +++ b/libsrc/grabber/audio/CMakeLists.txt @@ -1,35 +1,38 @@ -# Define the current source locations -SET( CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber ) -SET( CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/audio ) - -if (WIN32) - add_definitions(-DUNICODE -D_UNICODE) - FILE ( GLOB AUDIO_GRABBER_SOURCES "${CURRENT_HEADER_DIR}/Audio*Windows.h" "${CURRENT_HEADER_DIR}/AudioGrabber.h" "${CURRENT_HEADER_DIR}/AudioWrapper.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*Windows.cpp" "${CURRENT_SOURCE_DIR}/AudioGrabber.cpp" "${CURRENT_SOURCE_DIR}/AudioWrapper.cpp") -elseif(${CMAKE_SYSTEM} MATCHES "Linux") - FILE ( GLOB AUDIO_GRABBER_SOURCES "${CURRENT_HEADER_DIR}/Audio*Linux.h" "${CURRENT_HEADER_DIR}/AudioGrabber.h" "${CURRENT_HEADER_DIR}/AudioWrapper.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*Linux.cpp" "${CURRENT_SOURCE_DIR}/AudioGrabber.cpp" "${CURRENT_SOURCE_DIR}/AudioWrapper.cpp") -elseif (APPLE) - #TODO - #FILE ( GLOB AUDIO_GRABBER_SOURCES "${CURRENT_HEADER_DIR}/Audio*Apple.h" "${CURRENT_HEADER_DIR}/AudioGrabber.h" "${CURRENT_HEADER_DIR}/AudioWrapper.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*Apple.cpp" "${CURRENT_SOURCE_DIR}/AudioGrabber.cpp" "${CURRENT_SOURCE_DIR}/AudioWrapper.cpp") +if(WIN32) + add_definitions(-DUNICODE -D_UNICODE) + set(AUDIO_GRABBER_SOURCES + ${CMAKE_SOURCE_DIR}/include/grabber/audio/AudioGrabberWindows.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/audio/AudioGrabberWindows.cpp + ) +elseif(CMAKE_HOST_UNIX AND NOT APPLE) + set(AUDIO_GRABBER_SOURCES + ${CMAKE_SOURCE_DIR}/include/grabber/audio/AudioGrabberLinux.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/audio/AudioGrabberLinux.cpp + ) endif() -add_library( audio-grabber ${AUDIO_GRABBER_SOURCES} ) - -set(AUDIO_LIBS hyperion) - - -if (WIN32) - set(AUDIO_LIBS ${AUDIO_LIBS} DSound) -elseif(${CMAKE_SYSTEM} MATCHES "Linux") - find_package(ALSA REQUIRED) - if (ALSA_FOUND) - include_directories(${ALSA_INCLUDE_DIRS}) - set(AUDIO_LIBS ${AUDIO_LIBS} ${ALSA_LIBRARIES}) - endif(ALSA_FOUND) - - set(THREADS_PREFER_PTHREAD_FLAG ON) - find_package(Threads REQUIRED) - set(AUDIO_LIBS ${AUDIO_LIBS} Threads::Threads) # PRIVATE +add_library(audio-grabber + ${CMAKE_SOURCE_DIR}/include/grabber/audio/AudioGrabber.h + ${CMAKE_SOURCE_DIR}/include/grabber/audio/AudioWrapper.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/audio/AudioGrabber.cpp + ${CMAKE_SOURCE_DIR}/libsrc/grabber/audio/AudioWrapper.cpp + ${AUDIO_GRABBER_SOURCES} +) + +if(WIN32) + set(AUDIO_LIBS DSound) +elseif(CMAKE_HOST_UNIX AND NOT APPLE) + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(ALSA REQUIRED) + find_package(Threads REQUIRED) + set(AUDIO_LIBS ${ALSA_LIBRARIES} Threads::Threads) endif() +target_link_libraries(audio-grabber + hyperion + ${AUDIO_LIBS} +) -target_link_libraries(audio-grabber ${AUDIO_LIBS} ${QT_LIBRARIES}) +if(CMAKE_HOST_UNIX AND NOT APPLE) + target_include_directories(audio-grabber PUBLIC ${ALSA_INCLUDE_DIRS}) +endif() diff --git a/libsrc/grabber/directx/CMakeLists.txt b/libsrc/grabber/directx/CMakeLists.txt index 16db7dd2a..3d86e8972 100644 --- a/libsrc/grabber/directx/CMakeLists.txt +++ b/libsrc/grabber/directx/CMakeLists.txt @@ -1,14 +1,17 @@ -# Define the current source locations -SET( CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber ) -SET( CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/directx ) +find_package(DirectX9 REQUIRED) -include_directories(${DIRECTX9_INCLUDE_DIRS}) - -FILE ( GLOB DIRECTX_GRAB_SOURCES "${CURRENT_HEADER_DIR}/DirectX*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -add_library( directx-grabber ${DIRECTX_GRAB_SOURCES} ) +add_library(directx-grabber + ${CMAKE_SOURCE_DIR}/include/grabber/directx/DirectXGrabber.h + ${CMAKE_SOURCE_DIR}/include/grabber/directx/DirectXWrapper.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/directx/DirectXGrabber.cpp + ${CMAKE_SOURCE_DIR}/libsrc/grabber/directx/DirectXWrapper.cpp +) target_link_libraries(directx-grabber - hyperion - ${DIRECTX9_LIBRARIES} + hyperion + ${DIRECTX9_LIBRARIES} +) + +target_include_directories(directx-grabber PUBLIC + ${DIRECTX9_INCLUDE_DIRS} ) diff --git a/libsrc/grabber/directx/DirectXGrabber.cpp b/libsrc/grabber/directx/DirectXGrabber.cpp index ae9098888..24db4b4fc 100644 --- a/libsrc/grabber/directx/DirectXGrabber.cpp +++ b/libsrc/grabber/directx/DirectXGrabber.cpp @@ -1,5 +1,5 @@ #include -#include +#include #pragma comment(lib, "d3d9.lib") #pragma comment(lib,"d3dx9.lib") diff --git a/libsrc/grabber/directx/DirectXWrapper.cpp b/libsrc/grabber/directx/DirectXWrapper.cpp index 3c4188e55..cddf19cef 100644 --- a/libsrc/grabber/directx/DirectXWrapper.cpp +++ b/libsrc/grabber/directx/DirectXWrapper.cpp @@ -1,4 +1,4 @@ -#include +#include DirectXWrapper::DirectXWrapper( int updateRate_Hz, int display, diff --git a/libsrc/grabber/dispmanx/CMakeLists.txt b/libsrc/grabber/dispmanx/CMakeLists.txt index 51292da1d..93082b9c3 100644 --- a/libsrc/grabber/dispmanx/CMakeLists.txt +++ b/libsrc/grabber/dispmanx/CMakeLists.txt @@ -1,5 +1,5 @@ # Find the BCM-package (VC control) -if( "${PLATFORM}" MATCHES rpi) +if("${PLATFORM}" MATCHES rpi) find_package(BCM) if(BCM_FOUND) add_definitions(-DBCM_FOUND) @@ -9,21 +9,20 @@ else() set(BCM_LIBRARY "") endif() -# Define the current source locations -set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) -set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/dispmanx) - -FILE ( GLOB DispmanxGrabberSOURCES "${CURRENT_HEADER_DIR}/Dispmanx*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) +add_library(dispmanx-grabber + ${CMAKE_SOURCE_DIR}/include/grabber/dispmanx/DispmanxFrameGrabber.h + ${CMAKE_SOURCE_DIR}/include/grabber/dispmanx/DispmanxWrapper.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/dispmanx/DispmanxFrameGrabber.cpp + ${CMAKE_SOURCE_DIR}/libsrc/grabber/dispmanx/DispmanxWrapper.cpp +) -add_library(dispmanx-grabber ${DispmanxGrabberSOURCES}) add_definitions(-DBCM_LIBRARY="${BCM_LIBRARY}") -target_include_directories(dispmanx-grabber PUBLIC - ${BCM_INCLUDE_DIR} -) - target_link_libraries(dispmanx-grabber hyperion - ${QT_LIBRARIES} ${CMAKE_DL_LIBS} ) + +target_include_directories(dispmanx-grabber PUBLIC + ${BCM_INCLUDE_DIR} +) diff --git a/libsrc/grabber/dispmanx/DispmanxFrameGrabber.cpp b/libsrc/grabber/dispmanx/DispmanxFrameGrabber.cpp index b0a46fe4e..d0486cdfa 100644 --- a/libsrc/grabber/dispmanx/DispmanxFrameGrabber.cpp +++ b/libsrc/grabber/dispmanx/DispmanxFrameGrabber.cpp @@ -16,7 +16,7 @@ namespace { } //End of constants // Local includes -#include "grabber/DispmanxFrameGrabber.h" +#include "grabber/dispmanx/DispmanxFrameGrabber.h" DispmanxFrameGrabber::DispmanxFrameGrabber() : Grabber("DISPMANXGRABBER") diff --git a/libsrc/grabber/dispmanx/DispmanxWrapper.cpp b/libsrc/grabber/dispmanx/DispmanxWrapper.cpp index 6ffe33549..19fb1b028 100644 --- a/libsrc/grabber/dispmanx/DispmanxWrapper.cpp +++ b/libsrc/grabber/dispmanx/DispmanxWrapper.cpp @@ -1,4 +1,4 @@ -#include +#include DispmanxWrapper::DispmanxWrapper( int updateRate_Hz, int pixelDecimation diff --git a/libsrc/grabber/framebuffer/CMakeLists.txt b/libsrc/grabber/framebuffer/CMakeLists.txt index af1368ffb..bcaf4675c 100644 --- a/libsrc/grabber/framebuffer/CMakeLists.txt +++ b/libsrc/grabber/framebuffer/CMakeLists.txt @@ -1,11 +1,10 @@ -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/framebuffer) - -FILE ( GLOB FramebufferGrabberSOURCES "${CURRENT_HEADER_DIR}/Framebuffer*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -add_library(framebuffer-grabber ${FramebufferGrabberSOURCES} ) +add_library(framebuffer-grabber + ${CMAKE_SOURCE_DIR}/include/grabber/framebuffer/FramebufferFrameGrabber.h + ${CMAKE_SOURCE_DIR}/include/grabber/framebuffer/FramebufferWrapper.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/framebuffer/FramebufferFrameGrabber.cpp + ${CMAKE_SOURCE_DIR}/libsrc/grabber/framebuffer/FramebufferWrapper.cpp +) target_link_libraries(framebuffer-grabber hyperion - ${QT_LIBRARIES}) +) diff --git a/libsrc/grabber/framebuffer/FramebufferFrameGrabber.cpp b/libsrc/grabber/framebuffer/FramebufferFrameGrabber.cpp index 554f81661..c4129341f 100644 --- a/libsrc/grabber/framebuffer/FramebufferFrameGrabber.cpp +++ b/libsrc/grabber/framebuffer/FramebufferFrameGrabber.cpp @@ -28,7 +28,7 @@ const char DISCOVERY_FILEPATTERN[] = "fb?"; } //End of constants // Local includes -#include +#include FramebufferFrameGrabber::FramebufferFrameGrabber(const QString & device) : Grabber("FRAMEBUFFERGRABBER") diff --git a/libsrc/grabber/framebuffer/FramebufferWrapper.cpp b/libsrc/grabber/framebuffer/FramebufferWrapper.cpp index 7d99f5278..9cb400462 100644 --- a/libsrc/grabber/framebuffer/FramebufferWrapper.cpp +++ b/libsrc/grabber/framebuffer/FramebufferWrapper.cpp @@ -1,4 +1,4 @@ -#include +#include FramebufferWrapper::FramebufferWrapper( int updateRate_Hz, const QString & device, diff --git a/libsrc/grabber/osx/CMakeLists.txt b/libsrc/grabber/osx/CMakeLists.txt index 3a5690c67..7d18e8d3f 100644 --- a/libsrc/grabber/osx/CMakeLists.txt +++ b/libsrc/grabber/osx/CMakeLists.txt @@ -1,11 +1,10 @@ -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/osx) - -FILE ( GLOB OsxGrabberSOURCES "${CURRENT_HEADER_DIR}/Osx*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -add_library(osx-grabber ${OsxGrabberSOURCES} ) +add_library(osx-grabber + ${CMAKE_SOURCE_DIR}/include/grabber/osx/OsxFrameGrabber.h + ${CMAKE_SOURCE_DIR}/include/grabber/osx/OsxWrapper.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/osx/OsxFrameGrabber.cpp + ${CMAKE_SOURCE_DIR}/libsrc/grabber/osx/OsxWrapper.cpp +) target_link_libraries(osx-grabber hyperion - ${QT_LIBRARIES}) +) diff --git a/libsrc/grabber/osx/OsxFrameGrabber.cpp b/libsrc/grabber/osx/OsxFrameGrabber.cpp index 54ea28f72..0e42e529d 100644 --- a/libsrc/grabber/osx/OsxFrameGrabber.cpp +++ b/libsrc/grabber/osx/OsxFrameGrabber.cpp @@ -3,7 +3,7 @@ #include // Local includes -#include +#include //Qt #include diff --git a/libsrc/grabber/osx/OsxFrameGrabberMock.cpp b/libsrc/grabber/osx/OsxFrameGrabberMock.cpp deleted file mode 100644 index 2bcab4840..000000000 --- a/libsrc/grabber/osx/OsxFrameGrabberMock.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef __APPLE__ -#include - -unsigned __osx_frame_counter = 0; -const int __screenWidth = 800; -const int __screenHeight = 600; - -CGError CGGetActiveDisplayList(uint32_t maxDisplays, CGDirectDisplayID *activeDisplays, uint32_t *displayCount) -{ - if (maxDisplays == 0 || activeDisplays == nullptr) - { - *displayCount = 2; - } - else - { - displayCount = &maxDisplays; - if (activeDisplays != nullptr) - { - for (CGDirectDisplayID i = 0; i < maxDisplays; ++i) - { - activeDisplays[i] = i; - } - } - else - { - return kCGErrorFailure; - } - } - return kCGErrorSuccess; -} - -CGImageRef CGDisplayCreateImage(CGDirectDisplayID display) -{ - CGImageRef image = new CGImage(__screenWidth / (display+1), __screenHeight / (display+1)); - - return image; -} - -void CGImageRelease(CGImageRef image) -{ - delete image; -} - -CGImageRef CGImageGetDataProvider(CGImageRef image) -{ - __osx_frame_counter++; - if (__osx_frame_counter > 100) - { - __osx_frame_counter = 0; - } - - ColorRgb color[4] = {ColorRgb::RED, ColorRgb::BLUE, ColorRgb::GREEN, ColorRgb::WHITE}; - if (__osx_frame_counter < 25) - { - color[0] = ColorRgb::WHITE; - color[1] = ColorRgb::RED; - color[2] = ColorRgb::BLUE; - color[3] = ColorRgb::GREEN; - } - else if(__osx_frame_counter < 50) - { - color[1] = ColorRgb::WHITE; - color[2] = ColorRgb::RED; - color[3] = ColorRgb::BLUE; - color[0] = ColorRgb::GREEN; - } - else if(__osx_frame_counter < 75) - { - color[2] = ColorRgb::WHITE; - color[3] = ColorRgb::RED; - color[0] = ColorRgb::BLUE; - color[1] = ColorRgb::GREEN; - } - unsigned w = image->width(); - unsigned h = image->height(); - - for (unsigned y=0; y= h/2) id = 2; - if (x >= w/2 && y < h/2) id = 3; - - image->memptr()[y*w + x] = color[id]; - } - } - - return image; -} - -CFDataRef CGDataProviderCopyData(CGImageRef image) -{ - const unsigned indexMax = image->width() * image->height() * CGImageGetBitsPerPixel(image); - CFDataRef data = new CFData[indexMax]; - int lineLength = CGImageGetBytesPerRow(image); - - for (unsigned y=0; yheight(); y++) - { - for (unsigned x=0; xwidth(); x++) - { - int index = lineLength * y + x * CGImageGetBitsPerPixel(image); - - data[index ] = (*image)(x,y).blue; - data[index+1] = (*image)(x,y).green; - data[index+2] = (*image)(x,y).red; - data[index+3] = 0; - } - } - return data; -} - -unsigned char* CFDataGetBytePtr(CFDataRef imgData) -{ - return imgData; -} - -unsigned CGImageGetWidth(CGImageRef image) -{ - return image->width(); -} - -unsigned CGImageGetHeight(CGImageRef image) -{ - return image->height(); -} - -unsigned CGImageGetBytesPerRow(CGImageRef image) -{ - return image->width()*CGImageGetBitsPerPixel(image); -} - -unsigned CGImageGetBitsPerPixel(CGImageRef) -{ - return 4; -} - -void CFRelease(CFDataRef imgData) -{ - delete imgData; -} - -CGDisplayModeRef CGDisplayCopyDisplayMode(CGDirectDisplayID display) -{ - return nullptr; -} -CGRect CGDisplayBounds(CGDirectDisplayID display) -{ - CGRect rect; - rect.size.width = __screenWidth / (display+1); - rect.size.height = __screenHeight / (display+1); - return rect; -} -void CGDisplayModeRelease(CGDisplayModeRef mode) -{ -} - -#endif diff --git a/libsrc/grabber/osx/OsxWrapper.cpp b/libsrc/grabber/osx/OsxWrapper.cpp index 724be2fa4..408f7a69c 100644 --- a/libsrc/grabber/osx/OsxWrapper.cpp +++ b/libsrc/grabber/osx/OsxWrapper.cpp @@ -1,4 +1,4 @@ -#include +#include OsxWrapper::OsxWrapper( int updateRate_Hz, int display, diff --git a/libsrc/grabber/qt/CMakeLists.txt b/libsrc/grabber/qt/CMakeLists.txt index 1b0111de9..6ece8bbc1 100644 --- a/libsrc/grabber/qt/CMakeLists.txt +++ b/libsrc/grabber/qt/CMakeLists.txt @@ -1,13 +1,10 @@ -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/qt) - - -FILE ( GLOB QT_GRAB_SOURCES "${CURRENT_HEADER_DIR}/Qt*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -add_library(qt-grabber ${QT_GRAB_SOURCES} ) +add_library(qt-grabber + ${CMAKE_SOURCE_DIR}/include/grabber/qt/QtGrabber.h + ${CMAKE_SOURCE_DIR}/include/grabber/qt/QtWrapper.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/qt/QtGrabber.cpp + ${CMAKE_SOURCE_DIR}/libsrc/grabber/qt/QtWrapper.cpp +) target_link_libraries(qt-grabber hyperion - ${QT_LIBRARIES} ) diff --git a/libsrc/grabber/qt/QtGrabber.cpp b/libsrc/grabber/qt/QtGrabber.cpp index cb6e0c5c0..3d2cd51c6 100644 --- a/libsrc/grabber/qt/QtGrabber.cpp +++ b/libsrc/grabber/qt/QtGrabber.cpp @@ -1,5 +1,5 @@ // proj -#include +#include // qt #include @@ -226,7 +226,7 @@ int QtGrabber::grabFrame(Image& image) QPixmap originalPixmap = grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max); #else QPixmap originalPixmap = _screen->grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max); -#endif +#endif if (originalPixmap.isNull()) { rc = -1; diff --git a/libsrc/grabber/qt/QtWrapper.cpp b/libsrc/grabber/qt/QtWrapper.cpp index 90cb489bb..689f25c55 100644 --- a/libsrc/grabber/qt/QtWrapper.cpp +++ b/libsrc/grabber/qt/QtWrapper.cpp @@ -1,4 +1,4 @@ -#include +#include QtWrapper::QtWrapper( int updateRate_Hz, int display, diff --git a/libsrc/grabber/video/CMakeLists.txt b/libsrc/grabber/video/CMakeLists.txt index 43a0e5807..c4c2f8962 100644 --- a/libsrc/grabber/video/CMakeLists.txt +++ b/libsrc/grabber/video/CMakeLists.txt @@ -1,33 +1,38 @@ # Common cmake definition for external video grabber -# Add Turbo JPEG library -if (ENABLE_V4L2 OR ENABLE_MF) - find_package(TurboJPEG) - if (TURBOJPEG_FOUND) - add_definitions(-DHAVE_TURBO_JPEG) - message( STATUS "Using Turbo JPEG library: ${TurboJPEG_LIBRARY}") - include_directories(${TurboJPEG_INCLUDE_DIRS}) - else () - message( STATUS "Turbo JPEG library not found, MJPEG camera format won't work.") - endif () -endif() +set(MF-grabber mediafoundation) +set(V4L2-grabber v4l2) -# Define the wrapper/header/source locations and collect them -SET(WRAPPER_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/video) -SET(HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) -if (ENABLE_MF) +if(ENABLE_MF) project(mf-grabber) - SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/video/mediafoundation) - FILE (GLOB SOURCES "${WRAPPER_DIR}/*.cpp" "${HEADER_DIR}/Video*.h" "${HEADER_DIR}/MF*.h" "${HEADER_DIR}/Encoder*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp") + set(grabber_project MF) + set(MediaFoundationSourceReaderCallBack ${CMAKE_SOURCE_DIR}/libsrc/grabber/video/mediafoundation/MFSourceReaderCB.h) elseif(ENABLE_V4L2) project(v4l2-grabber) - SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/video/v4l2) - FILE (GLOB SOURCES "${WRAPPER_DIR}/*.cpp" "${HEADER_DIR}/Video*.h" "${HEADER_DIR}/V4L2*.h" "${HEADER_DIR}/Encoder*.h" "${CURRENT_SOURCE_DIR}/*.cpp") + set(grabber_project V4L2) endif() -add_library(${PROJECT_NAME} ${SOURCES}) -target_link_libraries(${PROJECT_NAME} hyperion ${QT_LIBRARIES}) +add_library(${PROJECT_NAME} + ${CMAKE_SOURCE_DIR}/include/grabber/video/EncoderThread.h + ${CMAKE_SOURCE_DIR}/include/grabber/video/VideoWrapper.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/video/EncoderThread.cpp + ${CMAKE_SOURCE_DIR}/libsrc/grabber/video/VideoWrapper.cpp + ${CMAKE_SOURCE_DIR}/include/grabber/video/${${grabber_project}-grabber}/${grabber_project}Grabber.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/video/${${grabber_project}-grabber}/${grabber_project}Grabber.cpp + ${MediaFoundationSourceReaderCallBack} +) -if(TURBOJPEG_FOUND) - target_link_libraries(${PROJECT_NAME} ${TurboJPEG_LIBRARY}) +target_link_libraries(${PROJECT_NAME} hyperion) + +# Add Turbo JPEG library +if(ENABLE_V4L2 OR ENABLE_MF) + find_package(TurboJPEG) + if(TURBOJPEG_FOUND) + add_definitions(-DHAVE_TURBO_JPEG) + message(STATUS "Using Turbo JPEG library: ${TurboJPEG_LIBRARY}") + target_link_libraries(${PROJECT_NAME} ${TurboJPEG_LIBRARY}) + target_include_directories(${PROJECT_NAME} PUBLIC ${TurboJPEG_INCLUDE_DIRS}) + else () + message(STATUS "Turbo JPEG library not found, MJPEG camera format won't work.") + endif() endif() diff --git a/libsrc/grabber/video/EncoderThread.cpp b/libsrc/grabber/video/EncoderThread.cpp index 1de36ff70..3555bb9fd 100644 --- a/libsrc/grabber/video/EncoderThread.cpp +++ b/libsrc/grabber/video/EncoderThread.cpp @@ -1,4 +1,4 @@ -#include "grabber/EncoderThread.h" +#include "grabber/video/EncoderThread.h" #include diff --git a/libsrc/grabber/video/VideoWrapper.cpp b/libsrc/grabber/video/VideoWrapper.cpp index 7a3ed201c..3b95f5616 100644 --- a/libsrc/grabber/video/VideoWrapper.cpp +++ b/libsrc/grabber/video/VideoWrapper.cpp @@ -1,6 +1,6 @@ #include -#include +#include // qt includes #include diff --git a/libsrc/grabber/video/mediafoundation/MFGrabber.cpp b/libsrc/grabber/video/mediafoundation/MFGrabber.cpp index 5e67e6ef5..ca2b6a35a 100644 --- a/libsrc/grabber/video/mediafoundation/MFGrabber.cpp +++ b/libsrc/grabber/video/mediafoundation/MFGrabber.cpp @@ -1,5 +1,5 @@ #include "MFSourceReaderCB.h" -#include "grabber/MFGrabber.h" +#include "grabber/video/mediafoundation/MFGrabber.h" // Constants namespace { const bool verbose = false; } @@ -537,7 +537,7 @@ void MFGrabber::process_image(const void *frameImageBuffer, int size) Error(_log, "Frame too small: %d != %d", size, _frameByteSize); else if (_threadManager != nullptr) { - for (unsigned long i = 0; i < _threadManager->_threadCount; i++) + for (int i = 0; i < _threadManager->_threadCount; i++) { if (!_threadManager->_threads[i]->isBusy()) { diff --git a/libsrc/grabber/video/mediafoundation/MFSourceReaderCB.h b/libsrc/grabber/video/mediafoundation/MFSourceReaderCB.h index 8cb10ba4e..2bcef437b 100644 --- a/libsrc/grabber/video/mediafoundation/MFSourceReaderCB.h +++ b/libsrc/grabber/video/mediafoundation/MFSourceReaderCB.h @@ -19,7 +19,7 @@ #pragma comment (lib, "strmiids.lib") #pragma comment (lib, "wmcodecdspuuid.lib") -#include +#include #define SAFE_RELEASE(x) if(x) { x->Release(); x = nullptr; } diff --git a/libsrc/grabber/video/v4l2/V4L2Grabber.cpp b/libsrc/grabber/video/v4l2/V4L2Grabber.cpp index 8f5044649..cd0d273f0 100644 --- a/libsrc/grabber/video/v4l2/V4L2Grabber.cpp +++ b/libsrc/grabber/video/v4l2/V4L2Grabber.cpp @@ -23,7 +23,7 @@ #include #include -#include "grabber/V4L2Grabber.h" +#include "grabber/video/v4l2/V4L2Grabber.h" #define CLEAR(x) memset(&(x), 0, sizeof(x)) diff --git a/libsrc/grabber/x11/CMakeLists.txt b/libsrc/grabber/x11/CMakeLists.txt index 08183afff..d5cd3831b 100644 --- a/libsrc/grabber/x11/CMakeLists.txt +++ b/libsrc/grabber/x11/CMakeLists.txt @@ -1,24 +1,23 @@ -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/x11) - -# Find X11 find_package(X11 REQUIRED) -include_directories( ${X11_INCLUDES} ) - -if(APPLE) - include_directories("/opt/X11/include") -endif(APPLE) - -FILE ( GLOB X11_SOURCES "${CURRENT_HEADER_DIR}/X11*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -add_library(x11-grabber ${X11_SOURCES} ) +add_library(x11-grabber + ${CMAKE_SOURCE_DIR}/include/grabber/x11/X11Grabber.h + ${CMAKE_SOURCE_DIR}/include/grabber/x11/X11Wrapper.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/x11/X11Grabber.cpp + ${CMAKE_SOURCE_DIR}/libsrc/grabber/x11/X11Wrapper.cpp +) target_link_libraries(x11-grabber hyperion ${X11_LIBRARIES} ${X11_Xrandr_LIB} ${X11_Xrender_LIB} - ${QT_LIBRARIES} +) + +if(APPLE) + list(APPEND X11_INCLUDES "/opt/X11/include") +endif() + +target_include_directories(x11-grabber PUBLIC + ${X11_INCLUDES} ) diff --git a/libsrc/grabber/x11/X11Grabber.cpp b/libsrc/grabber/x11/X11Grabber.cpp index 46c7faa4e..cf24eea29 100644 --- a/libsrc/grabber/x11/X11Grabber.cpp +++ b/libsrc/grabber/x11/X11Grabber.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include diff --git a/libsrc/grabber/x11/X11Wrapper.cpp b/libsrc/grabber/x11/X11Wrapper.cpp index a453fc194..a7e36b714 100644 --- a/libsrc/grabber/x11/X11Wrapper.cpp +++ b/libsrc/grabber/x11/X11Wrapper.cpp @@ -1,4 +1,4 @@ -#include +#include X11Wrapper::X11Wrapper( int updateRate_Hz, int pixelDecimation, diff --git a/libsrc/grabber/xcb/CMakeLists.txt b/libsrc/grabber/xcb/CMakeLists.txt index 97f1ee918..d353f2bde 100644 --- a/libsrc/grabber/xcb/CMakeLists.txt +++ b/libsrc/grabber/xcb/CMakeLists.txt @@ -1,23 +1,19 @@ -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/xcb) - find_package(XCB COMPONENTS SHM IMAGE RENDER RANDR REQUIRED) -include_directories(${XCB_INCLUDE_DIRS}) - -FILE (GLOB XCB_SOURCES "${CURRENT_HEADER_DIR}/Xcb*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -add_library(xcb-grabber ${XCB_SOURCES}) +add_library(xcb-grabber + ${CMAKE_SOURCE_DIR}/include/grabber/xcb/XcbGrabber.h + ${CMAKE_SOURCE_DIR}/include/grabber/xcb/XcbWrapper.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/xcb/XcbCommandExecutor.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/xcb/XcbCommands.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/xcb/XcbGrabber.cpp + ${CMAKE_SOURCE_DIR}/libsrc/grabber/xcb/XcbWrapper.cpp +) target_link_libraries(xcb-grabber hyperion ${XCB_LIBRARIES} - ${QT_LIBRARIES} ) -if (NOT APPLE) - target_link_libraries( - xcb-grabber - ) -endif() +target_include_directories(xcb-grabber PUBLIC + ${XCB_INCLUDE_DIRS} +) diff --git a/libsrc/grabber/xcb/XcbGrabber.cpp b/libsrc/grabber/xcb/XcbGrabber.cpp index a5fc97f97..bf58770d9 100644 --- a/libsrc/grabber/xcb/XcbGrabber.cpp +++ b/libsrc/grabber/xcb/XcbGrabber.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "XcbCommands.h" #include "XcbCommandExecutor.h" diff --git a/libsrc/grabber/xcb/XcbWrapper.cpp b/libsrc/grabber/xcb/XcbWrapper.cpp index 339cb4e87..129217e16 100644 --- a/libsrc/grabber/xcb/XcbWrapper.cpp +++ b/libsrc/grabber/xcb/XcbWrapper.cpp @@ -1,4 +1,4 @@ -#include +#include XcbWrapper::XcbWrapper( int updateRate_Hz, int pixelDecimation, diff --git a/libsrc/hyperion/CMakeLists.txt b/libsrc/hyperion/CMakeLists.txt index 3a880a91b..776000861 100644 --- a/libsrc/hyperion/CMakeLists.txt +++ b/libsrc/hyperion/CMakeLists.txt @@ -1,21 +1,50 @@ - -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/hyperion) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperion) - -if(ENABLE_FLATBUF_SERVER) -include_directories( - ${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/flatbufserver -) -endif() - -FILE ( GLOB Hyperion_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -SET(Hyperion_RESOURCES ${CURRENT_SOURCE_DIR}/resource.qrc) - add_library(hyperion - ${Hyperion_SOURCES} - ${Hyperion_RESOURCES} + # Authorization Manager + ${CMAKE_SOURCE_DIR}/include/hyperion/AuthManager.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/AuthManager.cpp + # Background Effect Handler + ${CMAKE_SOURCE_DIR}/include/hyperion/BGEffectHandler.h + # Capture Control class + ${CMAKE_SOURCE_DIR}/include/hyperion/CaptureCont.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/CaptureCont.cpp + # Color Adjustment + ${CMAKE_SOURCE_DIR}/include/hyperion/ColorAdjustment.h + # Component Register + ${CMAKE_SOURCE_DIR}/include/hyperion/ComponentRegister.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/ComponentRegister.cpp + # Grabber/Wrapper classes + ${CMAKE_SOURCE_DIR}/include/hyperion/Grabber.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/Grabber.cpp + ${CMAKE_SOURCE_DIR}/include/hyperion/GrabberWrapper.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/GrabberWrapper.cpp + # Hyperion + Resources + ${CMAKE_SOURCE_DIR}/include/hyperion/Hyperion.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/Hyperion.cpp + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/resource.qrc + # Instance Manager + ${CMAKE_SOURCE_DIR}/include/hyperion/HyperionIManager.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/HyperionIManager.cpp + # Image Processor + ${CMAKE_SOURCE_DIR}/include/hyperion/ImageProcessor.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/ImageProcessor.cpp + # ImageToLedsMap class + ${CMAKE_SOURCE_DIR}/include/hyperion/ImageToLedsMap.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/ImageToLedsMap.cpp + # Led String + ${CMAKE_SOURCE_DIR}/include/hyperion/LedString.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/LedString.cpp + # Linear Color Smoothing + ${CMAKE_SOURCE_DIR}/include/hyperion/LinearColorSmoothing.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/LinearColorSmoothing.cpp + # Led Color Transform + ${CMAKE_SOURCE_DIR}/include/hyperion/MultiColorAdjustment.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/MultiColorAdjustment.cpp + # Priority Muxer + ${CMAKE_SOURCE_DIR}/include/hyperion/PriorityMuxer.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/PriorityMuxer.cpp + # Settings Manager + ${CMAKE_SOURCE_DIR}/include/hyperion/SettingsManager.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/SettingsManager.cpp ) target_link_libraries(hyperion @@ -23,7 +52,6 @@ target_link_libraries(hyperion hyperion-utils leddevice database - ${QT_LIBRARIES} ) if(ENABLE_BOBLIGHT_SERVER) diff --git a/libsrc/jsonserver/CMakeLists.txt b/libsrc/jsonserver/CMakeLists.txt index 30ca13730..b8b3c5b7f 100644 --- a/libsrc/jsonserver/CMakeLists.txt +++ b/libsrc/jsonserver/CMakeLists.txt @@ -1,20 +1,15 @@ - -# Define the current source locations -set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/jsonserver) -set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/jsonserver) - -FILE ( GLOB JsonServer_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -add_library(jsonserver ${JsonServer_SOURCES} ) +add_library(jsonserver + ${CMAKE_SOURCE_DIR}/include/jsonserver/JsonServer.h + ${CMAKE_SOURCE_DIR}/libsrc/jsonserver/JsonServer.cpp + ${CMAKE_SOURCE_DIR}/libsrc/jsonserver/JsonClientConnection.h + ${CMAKE_SOURCE_DIR}/libsrc/jsonserver/JsonClientConnection.cpp +) target_link_libraries(jsonserver hyperion-api hyperion - Qt${QT_VERSION_MAJOR}::Network - Qt${QT_VERSION_MAJOR}::Gui ) if(ENABLE_MDNS) target_link_libraries(jsonserver mdns) endif() - diff --git a/libsrc/leddevice/CMakeLists.txt b/libsrc/leddevice/CMakeLists.txt index 233bb9fd2..259ebf146 100644 --- a/libsrc/leddevice/CMakeLists.txt +++ b/libsrc/leddevice/CMakeLists.txt @@ -1,13 +1,13 @@ # Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/leddevice) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/leddevice) +set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/leddevice) +set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/leddevice) -if ( ENABLE_DEV_NETWORK ) +if(ENABLE_DEV_NETWORK) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Network REQUIRED) endif() -if ( ENABLE_DEV_SERIAL ) +if(ENABLE_DEV_SERIAL) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS SerialPort REQUIRED) endif() @@ -21,7 +21,7 @@ include_directories( dev_tinker ) -FILE ( GLOB Leddevice_SOURCES +file (GLOB Leddevice_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" @@ -29,49 +29,48 @@ FILE ( GLOB Leddevice_SOURCES "${CURRENT_SOURCE_DIR}/dev_other/*.cpp" ) -if ( ENABLE_OSX OR WIN32 ) +if(ENABLE_OSX OR WIN32) list(REMOVE_ITEM Leddevice_SOURCES "${CURRENT_SOURCE_DIR}/dev_other/LedDevicePiBlaster.h") list(REMOVE_ITEM Leddevice_SOURCES "${CURRENT_SOURCE_DIR}/dev_other/LedDevicePiBlaster.cpp") endif() -if ( ENABLE_DEV_NETWORK ) - FILE ( GLOB Leddevice_NETWORK_SOURCES "${CURRENT_SOURCE_DIR}/dev_net/*.h" "${CURRENT_SOURCE_DIR}/dev_net/*.cpp") +if(ENABLE_DEV_NETWORK) + file (GLOB Leddevice_NETWORK_SOURCES "${CURRENT_SOURCE_DIR}/dev_net/*.h" "${CURRENT_SOURCE_DIR}/dev_net/*.cpp") endif() -if ( ENABLE_DEV_SERIAL ) - FILE ( GLOB Leddevice_SERIAL_SOURCES "${CURRENT_SOURCE_DIR}/dev_serial/*.h" "${CURRENT_SOURCE_DIR}/dev_serial/*.cpp") +if(ENABLE_DEV_SERIAL) + file (GLOB Leddevice_SERIAL_SOURCES "${CURRENT_SOURCE_DIR}/dev_serial/*.h" "${CURRENT_SOURCE_DIR}/dev_serial/*.cpp") endif() -if ( ENABLE_DEV_SPI ) - FILE ( GLOB Leddevice_SPI_SOURCES "${CURRENT_SOURCE_DIR}/dev_spi/*.h" "${CURRENT_SOURCE_DIR}/dev_spi/*.cpp") +if(ENABLE_DEV_SPI) + file (GLOB Leddevice_SPI_SOURCES "${CURRENT_SOURCE_DIR}/dev_spi/*.h" "${CURRENT_SOURCE_DIR}/dev_spi/*.cpp") endif() -if ( ENABLE_DEV_TINKERFORGE ) - FILE ( GLOB Leddevice_TINKER_SOURCES "${CURRENT_SOURCE_DIR}/dev_tinker/*.h" "${CURRENT_SOURCE_DIR}/dev_tinker/*.cpp") +if(ENABLE_DEV_TINKERFORGE) + file (GLOB Leddevice_TINKER_SOURCES "${CURRENT_SOURCE_DIR}/dev_tinker/*.h" "${CURRENT_SOURCE_DIR}/dev_tinker/*.cpp") endif() -if ( ENABLE_DEV_USB_HID ) +if(ENABLE_DEV_USB_HID) find_package(libusb-1.0 REQUIRED) include_directories( ${CMAKE_SOURCE_DIR}/include/hidapi ${LIBUSB_1_INCLUDE_DIRS} ) - FILE ( GLOB Leddevice_USB_HID_SOURCES "${CURRENT_SOURCE_DIR}/dev_hid/*.h" "${CURRENT_SOURCE_DIR}/dev_hid/*.cpp") + file (GLOB Leddevice_USB_HID_SOURCES "${CURRENT_SOURCE_DIR}/dev_hid/*.h" "${CURRENT_SOURCE_DIR}/dev_hid/*.cpp") endif() -if ( ENABLE_DEV_WS281XPWM ) - include_directories(../../dependencies/external/rpi_ws281x) - FILE ( GLOB Leddevice_PWM_SOURCES "${CURRENT_SOURCE_DIR}/dev_rpi_pwm/*.h" "${CURRENT_SOURCE_DIR}/dev_rpi_pwm/*.cpp") +if(ENABLE_DEV_WS281XPWM) + file (GLOB Leddevice_PWM_SOURCES "${CURRENT_SOURCE_DIR}/dev_rpi_pwm/*.h" "${CURRENT_SOURCE_DIR}/dev_rpi_pwm/*.cpp") endif() -set(LedDevice_RESOURCES ${CURRENT_SOURCE_DIR}/LedDeviceSchemas.qrc ) +set(LedDevice_RESOURCES ${CURRENT_SOURCE_DIR}/LedDeviceSchemas.qrc) -SET( Leddevice_SOURCES +set(Leddevice_SOURCES ${Leddevice_SOURCES} ${LedDevice_RESOURCES} ${Leddevice_NETWORK_SOURCES} ${Leddevice_PWM_SOURCES} - ${Leddevice_SERIAL_SOURCES} + ${Leddevice_SERIAL_SOURCES} ${Leddevice_SPI_SOURCES} ${Leddevice_TINKER_SOURCES} ${Leddevice_USB_HID_SOURCES} @@ -79,20 +78,20 @@ SET( Leddevice_SOURCES # auto generate header file that include all available leddevice headers # auto generate cpp file for register() calls -FILE ( WRITE "${CMAKE_BINARY_DIR}/LedDevice_headers.h" "#pragma once\n\n//this file is autogenerated, don't touch it\n\n" ) -FILE ( WRITE "${CMAKE_BINARY_DIR}/LedDevice_register.cpp" "//this file is autogenerated, don't touch it\n\n" ) -FOREACH( f ${Leddevice_SOURCES} ) - # MESSAGE (STATUS "Add led device: ${f}") - if ( "${f}" MATCHES "dev_.*/Led.evice.+h$" ) +file (WRITE "${CMAKE_BINARY_DIR}/LedDevice_headers.h" "#pragma once\n\n//this file is autogenerated, don't touch it\n\n") +file (WRITE "${CMAKE_BINARY_DIR}/LedDevice_register.cpp" "//this file is autogenerated, don't touch it\n\n") +foreach(f ${Leddevice_SOURCES}) + # message (STATUS "Add led device: ${f}") + if("${f}" MATCHES "dev_.*/Led.evice.+h$") GET_FILENAME_COMPONENT(fname ${f} NAME) - FILE ( APPEND "${CMAKE_BINARY_DIR}/LedDevice_headers.h" "#include \"${fname}\"\n" ) - STRING( SUBSTRING ${fname} 9 -1 dname) - STRING( REPLACE ".h" "" dname "${dname}" ) - FILE ( APPEND "${CMAKE_BINARY_DIR}/LedDevice_register.cpp" "REGISTER(${dname});\n" ) + file (APPEND "${CMAKE_BINARY_DIR}/LedDevice_headers.h" "#include \"${fname}\"\n") + string(SUBSTRING ${fname} 9 -1 dname) + string(REPLACE ".h" "" dname "${dname}") + file (APPEND "${CMAKE_BINARY_DIR}/LedDevice_register.cpp" "REGISTER(${dname});\n") endif() -ENDFOREACH() +endforeach() -add_library(leddevice ${CMAKE_BINARY_DIR}/LedDevice_headers.h ${Leddevice_SOURCES} ) +add_library(leddevice ${CMAKE_BINARY_DIR}/LedDevice_headers.h ${Leddevice_SOURCES}) target_link_libraries(leddevice hyperion @@ -106,19 +105,19 @@ endif() if(ENABLE_DEV_NETWORK) target_link_libraries(leddevice Qt${QT_VERSION_MAJOR}::Network ssdp) - - if (NOT DEFAULT_USE_SYSTEM_MBEDTLS_LIBS) - if (MBEDTLS_LIBRARIES) + + if(NOT DEFAULT_USE_SYSTEM_MBEDTLS_LIBS) + if(MBEDTLS_LIBRARIES) include_directories(${MBEDTLS_INCLUDE_DIR}) target_link_libraries(leddevice ${MBEDTLS_LIBRARIES}) target_include_directories(leddevice PRIVATE ${MBEDTLS_INCLUDE_DIR}) endif (MBEDTLS_LIBRARIES) - endif () + endif() string(REGEX MATCH "[0-9]+|-([A-Za-z0-9_.]+)" MBEDTLS_MAJOR ${MBEDTLS_VERSION}) - if (MBEDTLS_MAJOR EQUAL "3") + if(MBEDTLS_MAJOR EQUAL "3") target_compile_definitions(leddevice PRIVATE USE_MBEDTLS3) - if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") target_compile_features(leddevice PRIVATE cxx_std_20) endif() endif() @@ -133,10 +132,11 @@ if(ENABLE_DEV_TINKERFORGE) endif() if(ENABLE_DEV_WS281XPWM) + target_include_directories(leddevice PUBLIC "${CMAKE_SOURCE_DIR}/dependencies/external/rpi_ws281x") target_link_libraries(leddevice ws281x) endif() -if (ENABLE_DEV_USB_HID) +if(ENABLE_DEV_USB_HID) if(APPLE) target_link_libraries(leddevice ${LIBUSB_1_LIBRARIES} hidapi-mac) else() @@ -150,17 +150,18 @@ if (ENABLE_DEV_USB_HID) #include int main() { - struct timespec t; - return clock_gettime(CLOCK_REALTIME, &t); + struct timespec t; + return clock_gettime(CLOCK_REALTIME, &t); } " GLIBC_HAS_CLOCK_GETTIME) - IF(NOT GLIBC_HAS_CLOCK_GETTIME) + if(NOT GLIBC_HAS_CLOCK_GETTIME) target_link_libraries(leddevice rt) endif() endif() endif() if(ENABLE_MDNS) - target_link_libraries(leddevice mdns) + + target_link_libraries(leddevice mdns) endif() diff --git a/libsrc/mdns/CMakeLists.txt b/libsrc/mdns/CMakeLists.txt index 4fdd5ed55..58bd4bcfa 100644 --- a/libsrc/mdns/CMakeLists.txt +++ b/libsrc/mdns/CMakeLists.txt @@ -1,16 +1,13 @@ - -# Define the current source locations -set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/mdns) -set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/mdns) - -FILE ( GLOB MDNS_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) -add_library(mdns ${MDNS_SOURCES}) - -include_directories(${QMDNS_INCLUDE_DIR}) +add_library(mdns + ${CMAKE_SOURCE_DIR}/include/mdns/MdnsServiceRegister.h + ${CMAKE_SOURCE_DIR}/include/mdns/MdnsBrowser.h + ${CMAKE_SOURCE_DIR}/include/mdns/MdnsProvider.h + ${CMAKE_SOURCE_DIR}/libsrc/mdns/MdnsBrowser.cpp + ${CMAKE_SOURCE_DIR}/libsrc/mdns/MdnsProvider.cpp +) target_link_libraries(mdns -hyperion-utils -${QMDNS_LIBRARIES} + hyperion + qmdnsengine + $<$:bcrypt.lib> ) - -target_include_directories(mdns PUBLIC ${QMDNS_INCLUDE_DIR}) diff --git a/libsrc/protoserver/CMakeLists.txt b/libsrc/protoserver/CMakeLists.txt index 5fefa7ef9..a463f53ce 100644 --- a/libsrc/protoserver/CMakeLists.txt +++ b/libsrc/protoserver/CMakeLists.txt @@ -1,37 +1,22 @@ +# set and compile proto schema +set(ProtoServer_PROTOS ${CMAKE_SOURCE_DIR}/libsrc/protoserver/message.proto) +protobuf_generate_cpp(ProtoServer_PROTO_SRCS ProtoServer_PROTO_HDRS ${ProtoServer_PROTOS}) -# Define the current source locations -set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/protoserver) -set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/protoserver) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ${PROTOBUF_INCLUDE_DIRS} -) - -set(ProtoServer_PROTOS ${CURRENT_SOURCE_DIR}/message.proto ) +# disable warnings for auto generated proto files, we can't change the files .... +if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) + set_source_files_properties(${ProtoServer_PROTO_SRCS} ${ProtoServer_PROTO_HDRS} ${ProtoServer_PROTOS} PROPERTIES COMPILE_FLAGS "-w -Wno-return-local-addr") +elseif(MSVC) + set_source_files_properties(${ProtoServer_PROTO_SRCS} ${ProtoServer_PROTO_HDRS} ${ProtoServer_PROTOS} PROPERTIES COMPILE_FLAGS "/W0") +endif() -protobuf_generate_cpp(ProtoServer_PROTO_SRCS ProtoServer_PROTO_HDRS ${ProtoServer_PROTOS} ) ### Split protoclient from protoserver as protoserver relates to HyperionDaemon and standalone capture binarys can't link to it - add_library(protoclient - ${CURRENT_SOURCE_DIR}/ProtoClientConnection.h - ${CURRENT_SOURCE_DIR}/ProtoClientConnection.cpp + ${CMAKE_SOURCE_DIR}/libsrc/protoserver/ProtoClientConnection.h + ${CMAKE_SOURCE_DIR}/libsrc/protoserver/ProtoClientConnection.cpp ${ProtoServer_PROTO_SRCS} ${ProtoServer_PROTO_HDRS} ) -add_library(protoserver - ${CURRENT_HEADER_DIR}/ProtoServer.h - ${CURRENT_SOURCE_DIR}/ProtoServer.cpp -) - -# disable warnings for auto generated proto files, we can't change the files .... -if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) - set_source_files_properties(${ProtoServer_PROTO_SRCS} ${ProtoServer_PROTO_HDRS} ${ProtoServer_PROTOS} PROPERTIES COMPILE_FLAGS "-w -Wno-return-local-addr") -elseif(MSVC) - set_source_files_properties(${ProtoServer_PROTO_SRCS} ${ProtoServer_PROTO_HDRS} ${ProtoServer_PROTOS} PROPERTIES COMPILE_FLAGS "/W0") -endif() - target_link_libraries(protoclient hyperion hyperion-utils @@ -39,6 +24,16 @@ target_link_libraries(protoclient Qt${QT_VERSION_MAJOR}::Gui ) +target_include_directories(protoclient PUBLIC + ${CMAKE_CURRENT_BINARY_DIR} + ${PROTOBUF_INCLUDE_DIRS} +) + +add_library(protoserver + ${CMAKE_SOURCE_DIR}/include/protoserver/ProtoServer.h + ${CMAKE_SOURCE_DIR}/libsrc/protoserver/ProtoServer.cpp +) + target_link_libraries(protoserver hyperion hyperion-utils diff --git a/libsrc/python/CMakeLists.txt b/libsrc/python/CMakeLists.txt index 6b83eb142..d39d34af3 100644 --- a/libsrc/python/CMakeLists.txt +++ b/libsrc/python/CMakeLists.txt @@ -1,34 +1,30 @@ -# Include the python directory. Also include the parent (which is for example /usr/include) -# which may be required when it is not includes by the (cross-) compiler by default. -if (NOT CMAKE_VERSION VERSION_LESS "3.12") +add_library(python + ${CMAKE_SOURCE_DIR}/include/python/PythonInit.h + ${CMAKE_SOURCE_DIR}/include/python/PythonProgram.h + ${CMAKE_SOURCE_DIR}/include/python/PythonUtils.h + ${CMAKE_SOURCE_DIR}/libsrc/python/PythonInit.cpp + ${CMAKE_SOURCE_DIR}/libsrc/python/PythonProgram.cpp +) + +if(NOT CMAKE_VERSION VERSION_LESS "3.12") find_package(Python3 COMPONENTS Interpreter Development REQUIRED) - include_directories(${Python3_INCLUDE_DIRS} ${Python3_INCLUDE_DIRS}/..) - add_compile_definitions(PYTHON_VERSION_MAJOR=${Python3_VERSION_MAJOR}) - add_compile_definitions(PYTHON_VERSION_MINOR=${Python3_VERSION_MINOR}) else() - find_package (PythonLibs ${PYTHON_VERSION_STRING} EXACT) # Maps PythonLibs to the PythonInterp version of the main cmake - include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/..) - add_definitions(-DPYTHON_VERSION_MAJOR=${PYTHON_VERSION_MAJOR}) - add_definitions(-DPYTHON_VERSION_MINOR=${PYTHON_VERSION_MINOR}) + find_package (PythonLibs ${PYTHON_VERSION_STRING} EXACT) endif() -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/python) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/python) - -FILE ( GLOB PYTHON_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -add_library(python - ${PYTHON_SOURCES} -) - target_link_libraries(python effectengine hyperion-utils + ${Python3_LIBRARIES} + ${PYTHON_LIBRARIES} ) -if (NOT CMAKE_VERSION VERSION_LESS "3.12") - target_link_libraries( python ${Python3_LIBRARIES} ) -else() - target_link_libraries( python ${PYTHON_LIBRARIES} ) -endif() +target_include_directories(python PUBLIC + ${Python3_INCLUDE_DIRS} ${Python3_INCLUDE_DIRS}/.. + ${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/.. +) + +target_compile_definitions(python PRIVATE + PYTHON_VERSION_MAJOR=$<$:${Python3_VERSION_MAJOR}>$<$:${PYTHON_VERSION_MAJOR}> + PYTHON_VERSION_MINOR=$<$:${Python3_VERSION_MINOR}>$<$:${PYTHON_VERSION_MINOR}> +) diff --git a/libsrc/ssdp/CMakeLists.txt b/libsrc/ssdp/CMakeLists.txt index 2c007c0c9..b773b6f92 100644 --- a/libsrc/ssdp/CMakeLists.txt +++ b/libsrc/ssdp/CMakeLists.txt @@ -1,14 +1,13 @@ -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/ssdp) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/ssdp) - -FILE ( GLOB SSDP_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - add_library(ssdp - ${SSDP_SOURCES} + ${CMAKE_SOURCE_DIR}/include/ssdp/SSDPDiscover.h + ${CMAKE_SOURCE_DIR}/include/ssdp/SSDPHandler.h + ${CMAKE_SOURCE_DIR}/include/ssdp/SSDPServer.h + ${CMAKE_SOURCE_DIR}/libsrc/ssdp/SSDPDescription.h + ${CMAKE_SOURCE_DIR}/libsrc/ssdp/SSDPDiscover.cpp + ${CMAKE_SOURCE_DIR}/libsrc/ssdp/SSDPHandler.cpp + ${CMAKE_SOURCE_DIR}/libsrc/ssdp/SSDPServer.cpp ) target_link_libraries(ssdp - Qt${QT_VERSION_MAJOR}::Network webserver ) diff --git a/libsrc/utils/CMakeLists.txt b/libsrc/utils/CMakeLists.txt index e51fcb5d0..b7d28eebb 100644 --- a/libsrc/utils/CMakeLists.txt +++ b/libsrc/utils/CMakeLists.txt @@ -1,32 +1,94 @@ -# Define the current source locations - -if(ENABLE_EFFECTENGINE) - # Include the python directory. Also include the parent (which is for example /usr/include) - # which may be required when it is not includes by the (cross-) compiler by default. - if (NOT CMAKE_VERSION VERSION_LESS "3.12") - find_package(Python3 COMPONENTS Interpreter Development REQUIRED) - include_directories(${Python3_INCLUDE_DIRS} ${Python3_INCLUDE_DIRS}/..) - add_compile_definitions(PYTHON_VERSION_MAJOR_MINOR=${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR}) - else() - find_package (PythonLibs ${PYTHON_VERSION_STRING} EXACT) # Maps PythonLibs to the PythonInterp version of the main cmake - include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/..) - add_definitions(-DPYTHON_VERSION_MAJOR_MINOR=${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}) - endif() -endif() - -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/utils) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/utils) - -FILE ( GLOB_RECURSE Utils_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) - -list(APPEND Utils_SOURCES "${CMAKE_SOURCE_DIR}/dependencies/include/oklab/ok_color.h") - -if ( NOT ENABLE_PROFILER ) - LIST ( REMOVE_ITEM Utils_SOURCES ${CURRENT_HEADER_DIR}/Profiler.h ${CURRENT_SOURCE_DIR}/Profiler.cpp ) +if(ENABLE_PROFILER) + set(PROFILER ${CURRENT_HEADER_DIR}/Profiler.h ${CURRENT_SOURCE_DIR}/Profiler.cpp) endif() add_library(hyperion-utils - ${Utils_SOURCES} + # Global defines/signal sharing + ${CMAKE_SOURCE_DIR}/include/utils/global_defines.h + ${CMAKE_SOURCE_DIR}/include/utils/GlobalSignals.h + # JSON Schema Checker + ${CMAKE_SOURCE_DIR}/include/utils/jsonschema/QJsonFactory.h + ${CMAKE_SOURCE_DIR}/include/utils/jsonschema/QJsonUtils.h + ${CMAKE_SOURCE_DIR}/include/utils/jsonschema/QJsonSchemaChecker.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/jsonschema/QJsonSchemaChecker.cpp + # Color ARGB/BGR/RGB/RGBA/RGBW etc. structures + ${CMAKE_SOURCE_DIR}/include/utils/ColorArgb.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/ColorArgb.cpp + ${CMAKE_SOURCE_DIR}/include/utils/ColorBgr.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/ColorBgr.cpp + ${CMAKE_SOURCE_DIR}/include/utils/ColorRgb.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/ColorRgb.cpp + ${CMAKE_SOURCE_DIR}/include/utils/ColorRgba.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/ColorRgba.cpp + ${CMAKE_SOURCE_DIR}/include/utils/ColorRgbScalar.h + ${CMAKE_SOURCE_DIR}/include/utils/ColorRgbw.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/ColorRgbw.cpp + # Image declaration + ${CMAKE_SOURCE_DIR}/include/utils/Image.h + ${CMAKE_SOURCE_DIR}/include/utils/ImageData.h + # Image resampler + ${CMAKE_SOURCE_DIR}/include/utils/ImageResampler.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/ImageResampler.cpp + # Color transformation (saturation/luminance) of RGB colors + ${CMAKE_SOURCE_DIR}/include/utils/ColorSys.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/ColorSys.cpp + # Color transformation (saturation/value) of Okhsv colors + ${CMAKE_SOURCE_DIR}/include/utils/OkhsvTransform.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/OkhsvTransform.cpp + # Signal handler + ${CMAKE_SOURCE_DIR}/include/utils/DefaultSignalHandler.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/DefaultSignalHandler.cpp + # File utilities + ${CMAKE_SOURCE_DIR}/include/utils/FileUtils.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/FileUtils.cpp + # JSON utilities + ${CMAKE_SOURCE_DIR}/include/utils/JsonUtils.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/JsonUtils.cpp + # Logger + ${CMAKE_SOURCE_DIR}/include/utils/Logger.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/Logger.cpp + # IP adress/Port checker + ${CMAKE_SOURCE_DIR}/include/utils/NetOrigin.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/NetOrigin.cpp + ${CMAKE_SOURCE_DIR}/include/utils/NetUtils.h + # Process namespace (Hyperion restart) + ${CMAKE_SOURCE_DIR}/include/utils/Process.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/Process.cpp + # Rgb single color adjustment/correction + ${CMAKE_SOURCE_DIR}/include/utils/RgbChannelAdjustment.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/RgbChannelAdjustment.cpp + # Color conversion/transformation + ${CMAKE_SOURCE_DIR}/include/utils/RgbToRgbw.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/RgbToRgbw.cpp + ${CMAKE_SOURCE_DIR}/include/utils/RgbTransform.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/RgbTransform.cpp + # System info class + ${CMAKE_SOURCE_DIR}/include/utils/SysInfo.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/SysInfo.cpp + # Grabber pixel formats enumeration + ${CMAKE_SOURCE_DIR}/include/utils/PixelFormat.h + # Grabber playing modes enumeration + ${CMAKE_SOURCE_DIR}/include/utils/VideoMode.h + # Grabber video standards enumeration + ${CMAKE_SOURCE_DIR}/include/utils/VideoStandard.h + # SettingsManager utilities + ${CMAKE_SOURCE_DIR}/include/utils/settings.h + # Qt string utilities + ${CMAKE_SOURCE_DIR}/include/utils/QStringUtils.h + # QThread sleep class + ${CMAKE_SOURCE_DIR}/include/utils/Sleep.h + # Wait event loop function + ${CMAKE_SOURCE_DIR}/include/utils/WaitTime.h + # Weak connection + ${CMAKE_SOURCE_DIR}/include/utils/WeakConnect.h + # Semver namespace + ${CMAKE_SOURCE_DIR}/include/utils/version.hpp + # Utility methods for Hyperion class + ${CMAKE_SOURCE_DIR}/include/utils/hyperion.h + # Oklab color space + ${CMAKE_SOURCE_DIR}/dependencies/include/oklab/ok_color.h + # Performance tester + ${PROFILER} ) target_link_libraries(hyperion-utils diff --git a/libsrc/utils/Process.cpp b/libsrc/utils/Process.cpp index 9fdd72642..baa2723af 100644 --- a/libsrc/utils/Process.cpp +++ b/libsrc/utils/Process.cpp @@ -1,93 +1,92 @@ #ifdef _WIN32 -#include -#include -#include -#include -#include -namespace Process { + #include + #include + #include + #include + #include -void restartHyperion(int exitCode) -{ - Logger* log = Logger::getInstance("Process"); - Info(log, "Restarting hyperion ..."); + namespace Process + { + void restartHyperion(int exitCode) + { + Logger* log = Logger::getInstance("Process"); + Info(log, "Restarting hyperion ..."); - auto arguments = QCoreApplication::arguments(); - if (!arguments.contains("--wait-hyperion")) - arguments << "--wait-hyperion"; + auto arguments = QCoreApplication::arguments(); + if (!arguments.contains("--wait-hyperion")) + arguments << "--wait-hyperion"; - QProcess::startDetached(QCoreApplication::applicationFilePath(), arguments); + QProcess::startDetached(QCoreApplication::applicationFilePath(), arguments); - //Exit with non-zero code to ensure service deamon restarts hyperion - QCoreApplication::exit(exitCode); -} + //Exit with non-zero code to ensure service deamon restarts hyperion + QCoreApplication::exit(exitCode); + } -QByteArray command_exec(const QString& /*cmd*/, const QByteArray& /*data*/) -{ - return QSTRING_CSTR(QString()); -} -}; + QByteArray command_exec(const QString& /*cmd*/, const QByteArray& /*data*/) + { + return QSTRING_CSTR(QString()); + } + }; #else -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include + #include + #include -#include + #include + #include + #include -#include -#include + #include + #include + #include + #include + #include -namespace Process { + #include + #include + #include -void restartHyperion(int exitCode) -{ - Logger* log = Logger::getInstance("Process"); - Info(log, "Restarting hyperion ..."); - - std::cout << std::endl - << " *******************************************" << std::endl - << " * hyperion will restart now *" << std::endl - << " *******************************************" << std::endl << std::endl; + namespace Process + { + void restartHyperion(int exitCode) + { + Logger* log = Logger::getInstance("Process"); + Info(log, "Restarting hyperion ..."); - auto arguments = QCoreApplication::arguments(); - if (!arguments.contains("--wait-hyperion")) - arguments << "--wait-hyperion"; + std::cout << std::endl + << " *******************************************" << std::endl + << " * hyperion will restart now *" << std::endl + << " *******************************************" << std::endl << std::endl; - QProcess::startDetached(QCoreApplication::applicationFilePath(), arguments); + auto arguments = QCoreApplication::arguments(); + if (!arguments.contains("--wait-hyperion")) + arguments << "--wait-hyperion"; - //Exit with non-zero code to ensure service deamon restarts hyperion - QCoreApplication::exit(exitCode); -} + QProcess::startDetached(QCoreApplication::applicationFilePath(), arguments); -QByteArray command_exec(const QString& cmd, const QByteArray& /*data*/) -{ - char buffer[128]; - QString result; + //Exit with non-zero code to ensure service deamon restarts hyperion + QCoreApplication::exit(exitCode); + } - std::shared_ptr pipe(popen(cmd.toLocal8Bit().constData(), "r"), pclose); - if (pipe) - { - while (!feof(pipe.get())) + QByteArray command_exec(const QString& cmd, const QByteArray& /*data*/) { - if (fgets(buffer, 128, pipe.get()) != nullptr) - result += buffer; + char buffer[128]; + QString result; + + std::shared_ptr pipe(popen(cmd.toLocal8Bit().constData(), "r"), pclose); + if (pipe) + { + while (!feof(pipe.get())) + { + if (fgets(buffer, 128, pipe.get()) != nullptr) + result += buffer; + } + } + return QSTRING_CSTR(result); } - } - return QSTRING_CSTR(result); -} - -}; + }; #endif diff --git a/libsrc/webserver/CMakeLists.txt b/libsrc/webserver/CMakeLists.txt index 3dcfde153..12e5345f2 100644 --- a/libsrc/webserver/CMakeLists.txt +++ b/libsrc/webserver/CMakeLists.txt @@ -1,29 +1,43 @@ -# Define the current source locations -set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/webserver) -set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/webserver) +file(GLOB_RECURSE webFiles RELATIVE ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/assets/webconfig/*) +file(RELATIVE_PATH webConfigPath ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/assets/webconfig) -FILE ( GLOB WebConfig_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) -FILE ( GLOB_RECURSE webFiles RELATIVE ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/assets/webconfig/* ) -FILE ( RELATIVE_PATH webConfigPath ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/assets/webconfig) +foreach(f ${webFiles}) + string(REPLACE "${webConfigPath}/" "" fname ${f}) + set(HYPERION_WEBCONFIG_RES "${HYPERION_WEBCONFIG_RES}\n\t\t${f}") +endforeach() -FOREACH( f ${webFiles} ) - STRING ( REPLACE "${webConfigPath}/" "" fname ${f}) - SET(HYPERION_WEBCONFIG_RES "${HYPERION_WEBCONFIG_RES}\n\t\t${f}") -ENDFOREACH() -CONFIGURE_FILE(${CURRENT_SOURCE_DIR}/WebConfig.qrc.in ${CMAKE_BINARY_DIR}/WebConfig.qrc ) -SET(WebConfig_RESOURCES ${CMAKE_BINARY_DIR}/WebConfig.qrc) +configure_file(${CMAKE_SOURCE_DIR}/libsrc/webserver/WebConfig.qrc.in ${CMAKE_BINARY_DIR}/WebConfig.qrc) add_library(webserver - ${WebConfig_SOURCES} - ${WebConfig_RESOURCES} + ${CMAKE_SOURCE_DIR}/include/webserver/WebServer.h + ${CMAKE_SOURCE_DIR}/libsrc/webserver/WebServer.cpp + ${CMAKE_SOURCE_DIR}/libsrc/webserver/CgiHandler.h + ${CMAKE_SOURCE_DIR}/libsrc/webserver/CgiHandler.cpp + ${CMAKE_SOURCE_DIR}/libsrc/webserver/QtHttpClientWrapper.h + ${CMAKE_SOURCE_DIR}/libsrc/webserver/QtHttpClientWrapper.cpp + ${CMAKE_SOURCE_DIR}/libsrc/webserver/QtHttpHeader.h + ${CMAKE_SOURCE_DIR}/libsrc/webserver/QtHttpHeader.cpp + ${CMAKE_SOURCE_DIR}/libsrc/webserver/QtHttpReply.h + ${CMAKE_SOURCE_DIR}/libsrc/webserver/QtHttpReply.cpp + ${CMAKE_SOURCE_DIR}/libsrc/webserver/QtHttpRequest.h + ${CMAKE_SOURCE_DIR}/libsrc/webserver/QtHttpRequest.cpp + ${CMAKE_SOURCE_DIR}/libsrc/webserver/QtHttpServer.h + ${CMAKE_SOURCE_DIR}/libsrc/webserver/QtHttpServer.cpp + ${CMAKE_SOURCE_DIR}/libsrc/webserver/StaticFileServing.h + ${CMAKE_SOURCE_DIR}/libsrc/webserver/StaticFileServing.cpp + ${CMAKE_SOURCE_DIR}/libsrc/webserver/WebJsonRpc.h + ${CMAKE_SOURCE_DIR}/libsrc/webserver/WebJsonRpc.cpp + ${CMAKE_SOURCE_DIR}/libsrc/webserver/WebSocketClient.h + ${CMAKE_SOURCE_DIR}/libsrc/webserver/WebSocketClient.cpp + ${CMAKE_SOURCE_DIR}/libsrc/webserver/WebSocketUtils.h + ${CMAKE_BINARY_DIR}/WebConfig.qrc ) target_link_libraries(webserver hyperion hyperion-utils hyperion-api - Qt${QT_VERSION_MAJOR}::Network ) if(ENABLE_MDNS) diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index affe720b4..1fba840c1 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -2,20 +2,20 @@ # All files are available with their file name by calling ":/FILENAME". Probably you need to call Q_INIT_RESOURCE("resources") once # # Define the current source locations -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/resources) +set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/resources) # catch all files -FILE ( GLOB Hyperion_RESFILES "${CURRENT_SOURCE_DIR}/icons/*" "${CURRENT_SOURCE_DIR}/ssl/*" ) +file(GLOB Hyperion_RESFILES "${CURRENT_SOURCE_DIR}/icons/*" "${CURRENT_SOURCE_DIR}/ssl/*") # fill resources.qrc with RESFILES -FOREACH( f ${Hyperion_RESFILES} ) +foreach(f ${Hyperion_RESFILES}) get_filename_component(fname ${f} NAME) - SET(HYPERION_RES "${HYPERION_RES}\n\t\t${f}") -ENDFOREACH() + set(HYPERION_RES "${HYPERION_RES}\n\t\t${f}") +endforeach() # prep file -CONFIGURE_FILE(${CURRENT_SOURCE_DIR}/resources.qrc.in ${CMAKE_BINARY_DIR}/resources.qrc ) -SET(Hyperion_RES ${CMAKE_BINARY_DIR}/resources.qrc) +configure_file(${CURRENT_SOURCE_DIR}/resources.qrc.in ${CMAKE_BINARY_DIR}/resources.qrc) +set(Hyperion_RES ${CMAKE_BINARY_DIR}/resources.qrc) add_library(resources ${Hyperion_RES} diff --git a/resources/icons/hyperion-128px.png b/resources/icons/hyperion-128px.png new file mode 100644 index 0000000000000000000000000000000000000000..b208c95eaaec03ad60536d23c3312cb5164c9cc4 GIT binary patch literal 10834 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 literal 0 HcmV?d00001 diff --git a/resources/icons/hyperion-192px.png b/resources/icons/hyperion-192px.png new file mode 100644 index 0000000000000000000000000000000000000000..1aae38ac19e8f27f5d87005bcc16a9dc40f55d50 GIT binary patch literal 21900 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 literal 0 HcmV?d00001 diff --git a/resources/icons/hyperion-24px.png b/resources/icons/hyperion-24px.png new file mode 100644 index 0000000000000000000000000000000000000000..be90363c8f939945ff297ef74c29ffe4bc4288cf GIT binary patch literal 1894 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVkr05M1pgl1mAh%j*h z6I`{#0%imoq)m`tVjYm;EbxddW?0+>{umUo3Q%e#RDspr3imfVamB1>jfNYSkzLEl1NlCV?QiN}Sf^&XRs)CuG zfu4bq9hZWFf=y9MnpKdC8&o@xXRDM^Qc_^0uU}qXu2*iXmtT~wZ)j<0sc&GUZ)Btk zRH0j3nOBlnp_^B%3^4>|j!SBBa#3bMNoIbY0?6FNr2NtnTO}osMQ{LdXKF@SFQHXy^S0x~O7b0S?bb5rw*fljkCG%zx; z0o#Kig>Wg7)(G5Mk)+VII_Kx)7X=q2Ca2mNLTy75LQ)NKxs`uWW-2gHK|u#njv)qB zZ=(+iSEO);L?T!e7>jmXHu~@sVaMgl@HiEiKX^P{978;KuZDQ%%eV^s+f`jvR$g}V z?v2;iXIU_@vmCN%Vd+~WbBIwu$m_(xK$RUzg*^KYeCv%?u_!zx=orBFupy=Jfj~=3 z&yk~ICye+$W+xwiUt5uuzU*g}S@wEWg>3@tUawZJd$sDqh@RxvgvV$HIvIY0lbSO51(^8P7`)^b&M@^vsuasmQka@D2_BcOG9nI@OsQ z|1ERS^LdkPvhI*!^@X&|tEP1#$9p#jc-sq~%rg9C`8m_V*jV`Pt}YLQ9ZPEU+uF`O z`uBI?jdzVq;pg`7^RGXA^z#LYHlb9G`>i*+60R}LIAwR}Dch{>-5ZRJLzD%;t*hVY+ zKuV*UcYb&VPm^26(z!=>zTW(NnN4I**gUz2tqejFwI=s>T)cSQARz96?lK8w-`F#? zPE&YU4>n0oxO`e5Y=_O$NmooN?oY4Y^Xccosoqod|5#s6K6t#3Rba)+yiax+v-S1` zI>o5l8%ic0dr?wn{(S0#-Y*A!tYS^5nxCNm$w^Igb0|Y^aLUBHQ9lirv^?^6Y5n^d1#kIHYk%qZZOHxj;+)vm{fwhwtF5N0gBy>8 zMco^P{5b-#Y0}G^q=L>WwKrawcQS0RMcr|Q?AuSOL>8>?yumN?QbOHf|H@N2x!kM1 z@v!%cT@%ppP55cJ@~-ynjIt%W`6R<^SvGENn`d#Qs+zaxu(_bogu7SSukOpq-^Tsn z=9ZA-qD+r&pM36Z;ncWJDPsAnEurbIiPA>5UL3D`vL^YiMe9Q^)*1J2<*Z4s`eMqq z|JtYRldC)uUldgdX5W?Ceppz1rBv5RxJ)>H-=cY1A`fbRmj0Rj`k+Vu0++Q+qQ9aB$zDo+yj+2_XQ^u9CU^r^{WSNqD?JFd!4 zIQziC;^DLPHUG^ddMCRV`|wDsztcHu`1jx5oAW=~cD;|_7uE*V9-gj#F6*2UngHUE B*Vh05 literal 0 HcmV?d00001 diff --git a/resources/icons/hyperion-256px.png b/resources/icons/hyperion-256px.png new file mode 100644 index 0000000000000000000000000000000000000000..43121db3f7c3ab2ad87d9405fbfbfd5a9a6a5a76 GIT binary patch literal 31694 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 N002ovPDHLkV1hAknq>e0 literal 0 HcmV?d00001 diff --git a/resources/icons/hyperion-36px.png b/resources/icons/hyperion-36px.png new file mode 100644 index 0000000000000000000000000000000000000000..6d50eff434c11a8d9d8c6e6f9e74a207c44a9df5 GIT binary patch literal 2462 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 F`~~nl0*wFw literal 0 HcmV?d00001 diff --git a/resources/icons/hyperion-48px.png b/resources/icons/hyperion-48px.png new file mode 100644 index 0000000000000000000000000000000000000000..851676be2552a87c88b68f0f0a679ed92723aa4a GIT binary patch literal 2556 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 Hu0mjf1MF1f literal 0 HcmV?d00001 diff --git a/resources/icons/hyperion-72px.png b/resources/icons/hyperion-72px.png new file mode 100644 index 0000000000000000000000000000000000000000..5cb47103e986d49a71c78a1f65ee14635e108df7 GIT binary patch literal 4451 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 F_&-$)U=9EP literal 0 HcmV?d00001 diff --git a/resources/icons/hyperion-icon-32px.png b/resources/icons/hyperion-icon-32px.png deleted file mode 100644 index ee60b83b46e4ddeec406fbbd4fc126b753455062..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1454 zcmV;f1yTBmP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91AfN*P1ONa40RR91AOHXW0IY^$^8f$^7)eAyR9Fe+R!fUqMHK$3>fY|# z@9CN8jARCh0gZ?zzAzvpLD5CB$im0Qm5_xCLH~h^AOs0w+$e(JUUcC~a3dlKStYZI z5GBD8LS8f7b8mOwXI1&t&2*R;GlopYEOMH!t8Ue)I;YO73V7H_Y+!(m<~CTi;gsEQ z_CZVvs-!4bVh7t|L7SxXJ-mjQBsoxIEoe z_H)E$71HV`vMW~D>qNLL%}TD!V0c|;5zOcs3|X~@PN&Vz6o%+R4W`hKo6x$69_ldt z03NESz$d%UR*_F3pu&PbKya7RRo1{pM%px!x=(~Dihio{FhLe&A{nJ(Jj_ibg6T-t zbzeO$uB)b8@vyo&qk&zS#1j{R`TCTcPb;b;A~bA8I0Y({;1{`2h@tEN(p=&3T0l{u z@W3FUKCzKl&6Hgo`zB13i4s+WV_C$x$cBkc#+e)!(ylH?{lD5zHkJ|(=W^hj2h?Vj z#I8#we&(rfzTSs-kL=*doLjbn^ml)r_~Y0QADx`u(@W{SON@cup&a?^XOTYtk{!QH zsZ@$Csa|9gCu;5l>Hq2qE5Q|5u_q z8Do2|B_G}8#qyjTd#%%`(T};b0DHqr}+)r9^n<=5xNVS@% z&$M$X>P`XXl%{F?fb$cRRoHjRxNny(n<2N4RZ2M*I1))^s%mSUhLNgD1!gJCR*jJC z-&DZ)%n2?Rv)v4pdugr97-F^}4m!SVY^!7tK84N^#r`Zd6o|m%eFMNo=0Uo z{>?}M%ag{pFmBaHK?~?$TBNEgw6wy@SOi&!5Mg<%WZu57?9jhmMx=r_LPxV|>OQ>E zN4Im|-;o;?yiMy*GsdLxh6sv8*nGuGXNdoUENqLiIvGund!cNkBbz1HP_Q(Y)y}1! zi~b2VtCZV^)>e}grvi-(ww*wW%R#t5QRpl@w6;;eIn(|8|IBko5jcKf*l?IkP)XviRhXbfnVF)iQ^GGQ-k z-MCDKrwPHDeT?mvkSn+FYL|?vU!id#bx^(6$-PP~EHcRDuD|n8dx|X163%qaCF{Y@ z8{b;PEG`;-l`oq|<|gjF$vau=TDO;ji?QU**q;4O`e#+Q`@4mIL3~+Toae2ykZHYe zF*`rg$F;dJM5jQl;qiTvqE#Ki_s8)3A$&!bsR3_mQHiHdpLub2pUyjQ=+vUFPlf35 zTA48#J!aG_uk)VG(bXBel@V&i2-|`IcFteHj_p^`R7<=Cm&DJoLD5Au%26F|LolEe ztx#DB;r%rFN?*qLDivhG3RH}$$RQOU3QVC-_FEesccal8NMScXj6fD!2+u+ zYI%X@_NC9hwO^Sz6tay}w2)N-B-|t6qbl`Y;pK#Wd0&I?z4g?3?`97sGh)Rzb+icF@+wYH`{^hd+UvSvH3GRx@ zybYScs|?1NC&DjeP1c2!`ofyza_{w8+>D;}gKK?Sh;L)&%D>D_ zh9+|^$nHdLjuBrz^X|m+;KnzyfYa)~=I>VXNrk;z{)dR~Z-TE>*Wdfr-2eap07*qo IM6N<$f}eP^umAu6 diff --git a/resources/icons/hyperion-icon-512px.png b/resources/icons/hyperion-icon-512px.png deleted file mode 100644 index 53ea8fe8feb1093db2049c3f8a8fe5acb24e27e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69597 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 -#include +#include #include class AmlogicWrapper : public QObject diff --git a/src/hyperion-aml/CMakeLists.txt b/src/hyperion-aml/CMakeLists.txt index cdea66fa8..40b04df3f 100644 --- a/src/hyperion-aml/CMakeLists.txt +++ b/src/hyperion-aml/CMakeLists.txt @@ -1,25 +1,10 @@ cmake_minimum_required(VERSION 3.5.0) project(hyperion-aml) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Network Widgets REQUIRED) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/flatbufserver - ${FLATBUFFERS_INCLUDE_DIRS} -) - -set(Hyperion_AML_HEADERS +add_executable(${PROJECT_NAME} AmlogicWrapper.h -) - -set(Hyperion_AML_SOURCES - hyperion-aml.cpp AmlogicWrapper.cpp -) - -add_executable(${PROJECT_NAME} - ${Hyperion_AML_HEADERS} - ${Hyperion_AML_SOURCES} + hyperion-aml.cpp ) target_link_libraries(${PROJECT_NAME} @@ -29,27 +14,23 @@ target_link_libraries(${PROJECT_NAME} flatbuffers amlogic-grabber framebuffer-grabber - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Widgets ) if(ENABLE_MDNS) - target_link_libraries(${PROJECT_NAME} mdns) + target_link_libraries(${PROJECT_NAME} mdns) else() - target_link_libraries(${PROJECT_NAME} ssdp) + target_link_libraries(${PROJECT_NAME} ssdp) endif() -if (ENABLE_AMLOGIC) - target_link_libraries(${PROJECT_NAME} - pcre16 dl z - ) +if(ENABLE_AMLOGIC) + target_link_libraries(${PROJECT_NAME} pcre16 dl z) endif() -install ( TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_aml" ) +install (TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_aml") if(CMAKE_HOST_UNIX) - install(CODE "EXECUTE_PROCESS(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\" )" COMPONENT "hyperion_aml" ) - install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_aml" ) - install(CODE "FILE (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME} )" COMPONENT "hyperion_aml" ) + install(CODE "execute_process(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\")" COMPONENT "hyperion_aml") + install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_aml") + install(CODE "file (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME})" COMPONENT "hyperion_aml") endif(CMAKE_HOST_UNIX) diff --git a/src/hyperion-dispmanx/CMakeLists.txt b/src/hyperion-dispmanx/CMakeLists.txt index 07862bbda..c81d0fdbe 100644 --- a/src/hyperion-dispmanx/CMakeLists.txt +++ b/src/hyperion-dispmanx/CMakeLists.txt @@ -1,48 +1,31 @@ cmake_minimum_required(VERSION 3.5.0) project(hyperion-dispmanx) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Network Widgets REQUIRED) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/flatbufserver - ${FLATBUFFERS_INCLUDE_DIRS} -) - -set(Hyperion_Dispmanx_HEADERS +add_executable(${PROJECT_NAME} DispmanxWrapper.h -) - -set(Hyperion_Dispmanx_SOURCES - hyperion-dispmanx.cpp DispmanxWrapper.cpp + hyperion-dispmanx.cpp ) -add_executable( ${PROJECT_NAME} - ${Hyperion_Dispmanx_HEADERS} - ${Hyperion_Dispmanx_SOURCES} -) - -target_link_libraries( ${PROJECT_NAME} +target_link_libraries(${PROJECT_NAME} commandline hyperion-utils flatbufconnect flatbuffers dispmanx-grabber - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Widgets ) if(ENABLE_MDNS) - target_link_libraries(${PROJECT_NAME} mdns) + target_link_libraries(${PROJECT_NAME} mdns) else() - target_link_libraries(${PROJECT_NAME} ssdp) + target_link_libraries(${PROJECT_NAME} ssdp) endif() -install ( TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_dispmanx" ) +install (TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_dispmanx") if(CMAKE_HOST_UNIX) - install(CODE "EXECUTE_PROCESS(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\" )" COMPONENT "hyperion_dispmanx" ) - install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_dispmanx" ) - install(CODE "FILE (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME} )" COMPONENT "hyperion_dispmanx" ) + install(CODE "execute_process(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\")" COMPONENT "hyperion_dispmanx") + install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_dispmanx") + install(CODE "file (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME})" COMPONENT "hyperion_dispmanx") endif(CMAKE_HOST_UNIX) diff --git a/src/hyperion-dispmanx/DispmanxWrapper.h b/src/hyperion-dispmanx/DispmanxWrapper.h index e02e2c5fa..ddbb8a775 100644 --- a/src/hyperion-dispmanx/DispmanxWrapper.h +++ b/src/hyperion-dispmanx/DispmanxWrapper.h @@ -2,7 +2,7 @@ // QT includes #include -#include +#include #include class DispmanxWrapper : public QObject @@ -16,7 +16,7 @@ class DispmanxWrapper : public QObject ); const Image & getScreenshot(); - + bool open(); /// diff --git a/src/hyperion-framebuffer/CMakeLists.txt b/src/hyperion-framebuffer/CMakeLists.txt index 14ea2ce9b..a9470f5c9 100644 --- a/src/hyperion-framebuffer/CMakeLists.txt +++ b/src/hyperion-framebuffer/CMakeLists.txt @@ -1,55 +1,35 @@ cmake_minimum_required(VERSION 3.5.0) project(hyperion-framebuffer) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Network Widgets REQUIRED) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/flatbufserver - ${FLATBUFFERS_INCLUDE_DIRS} -) - -set(Hyperion_FB_HEADERS +add_executable(${PROJECT_NAME} FramebufferWrapper.h -) - -set(Hyperion_FB_SOURCES - hyperion-framebuffer.cpp FramebufferWrapper.cpp + hyperion-framebuffer.cpp ) -add_executable( ${PROJECT_NAME} - ${Hyperion_FB_HEADERS} - ${Hyperion_FB_SOURCES} -) - -target_link_libraries( ${PROJECT_NAME} +target_link_libraries(${PROJECT_NAME} commandline hyperion-utils flatbufconnect flatbuffers framebuffer-grabber - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Gui - Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Widgets ) if(ENABLE_MDNS) - target_link_libraries(${PROJECT_NAME} mdns) + target_link_libraries(${PROJECT_NAME} mdns) else() - target_link_libraries(${PROJECT_NAME} ssdp) + target_link_libraries(${PROJECT_NAME} ssdp) endif() -if (ENABLE_AMLOGIC) - target_link_libraries( ${PROJECT_NAME} - pcre16 dl z - ) +if(ENABLE_AMLOGIC) + target_link_libraries(${PROJECT_NAME} pcre16 dl z) endif() -install ( TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_framebuffer" ) +install (TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_framebuffer") if(CMAKE_HOST_UNIX) - install(CODE "EXECUTE_PROCESS(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\" )" COMPONENT "hyperion_framebuffer" ) - install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_framebuffer" ) - install(CODE "FILE (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME} )" COMPONENT "hyperion_framebuffer" ) + install(CODE "execute_process(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\")" COMPONENT "hyperion_framebuffer") + install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_framebuffer") + install(CODE "file (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME})" COMPONENT "hyperion_framebuffer") endif(CMAKE_HOST_UNIX) diff --git a/src/hyperion-framebuffer/FramebufferWrapper.h b/src/hyperion-framebuffer/FramebufferWrapper.h index d9bbdfb13..9f1b74f28 100644 --- a/src/hyperion-framebuffer/FramebufferWrapper.h +++ b/src/hyperion-framebuffer/FramebufferWrapper.h @@ -3,7 +3,7 @@ // QT includes #include -#include +#include #include class FramebufferWrapper : public QObject diff --git a/src/hyperion-osx/CMakeLists.txt b/src/hyperion-osx/CMakeLists.txt index efb15cd15..48a127b7c 100644 --- a/src/hyperion-osx/CMakeLists.txt +++ b/src/hyperion-osx/CMakeLists.txt @@ -1,43 +1,25 @@ cmake_minimum_required(VERSION 3.5.0) project(hyperion-osx) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Network Widgets REQUIRED) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/flatbufserver - ${FLATBUFFERS_INCLUDE_DIRS} -) - -set(Hyperion_OSX_HEADERS +add_executable(${PROJECT_NAME} OsxWrapper.h -) - -set(Hyperion_OSX_SOURCES - hyperion-osx.cpp OsxWrapper.cpp + hyperion-osx.cpp ) -add_executable( ${PROJECT_NAME} - ${Hyperion_OSX_HEADERS} - ${Hyperion_OSX_SOURCES} -) - -target_link_libraries( ${PROJECT_NAME} +target_link_libraries(${PROJECT_NAME} commandline hyperion-utils flatbufconnect flatbuffers osx-grabber - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Gui - Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Widgets ) if(ENABLE_MDNS) - target_link_libraries(${PROJECT_NAME} mdns) + target_link_libraries(${PROJECT_NAME} mdns) else() - target_link_libraries(${PROJECT_NAME} ssdp) + target_link_libraries(${PROJECT_NAME} ssdp) endif() -install ( TARGETS ${PROJECT_NAME} DESTINATION "." COMPONENT "hyperion_osx" ) +install (TARGETS ${PROJECT_NAME} DESTINATION "." COMPONENT "hyperion_osx") diff --git a/src/hyperion-osx/OsxWrapper.h b/src/hyperion-osx/OsxWrapper.h index ef352bd0a..335e6519d 100644 --- a/src/hyperion-osx/OsxWrapper.h +++ b/src/hyperion-osx/OsxWrapper.h @@ -2,7 +2,7 @@ // QT includes #include -#include +#include #include class OsxWrapper : public QObject diff --git a/src/hyperion-qt/CMakeLists.txt b/src/hyperion-qt/CMakeLists.txt index f35b8534b..fe87ef8b2 100644 --- a/src/hyperion-qt/CMakeLists.txt +++ b/src/hyperion-qt/CMakeLists.txt @@ -1,32 +1,18 @@ cmake_minimum_required(VERSION 3.5.0) project(hyperion-qt) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Network Widgets REQUIRED) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/flatbufserver - ${FLATBUFFERS_INCLUDE_DIRS} -) +if(WIN32) + # generate windows .rc file for this binary + string(REPLACE "/" "\\\\" WIN_RC_ICON_PATH ${CMAKE_SOURCE_DIR}/cmake/nsis/installer.ico) + configure_file(${CMAKE_SOURCE_DIR}/cmake/win/win.rc.in ${CMAKE_BINARY_DIR}/win.rc) + set(WIN_RC_FILE ${CMAKE_BINARY_DIR}/win.rc) +endif() -set(Hyperion_QT_HEADERS +add_executable(${PROJECT_NAME} QtWrapper.h -) - -set(Hyperion_QT_SOURCES QtWrapper.cpp hyperion-qt.cpp -) - -# generate windows .rc file for this binary -if (WIN32) - include(${CMAKE_SOURCE_DIR}/cmake/win/win_rc.cmake) - generate_win_rc_file(${PROJECT_NAME}) -endif() - -add_executable(${PROJECT_NAME} - ${Hyperion_QT_HEADERS} - ${Hyperion_QT_SOURCES} - ${${PROJECT_NAME}_WIN_RC_PATH} + ${WIN_RC_FILE} ) target_link_libraries(${PROJECT_NAME} @@ -34,28 +20,25 @@ target_link_libraries(${PROJECT_NAME} qt-grabber flatbufconnect flatbuffers - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Gui - Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Widgets ) if(ENABLE_MDNS) - target_link_libraries(${PROJECT_NAME} mdns) + target_link_libraries(${PROJECT_NAME} mdns) else() - target_link_libraries(${PROJECT_NAME} ssdp) + target_link_libraries(${PROJECT_NAME} ssdp) endif() if(APPLE) - install ( TARGETS ${PROJECT_NAME} DESTINATION "." COMPONENT "hyperion_qt" ) + install (TARGETS ${PROJECT_NAME} DESTINATION "." COMPONENT "hyperion_qt") elseif(NOT WIN32) - install ( TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_qt" ) + install (TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_qt") else() - install ( TARGETS ${PROJECT_NAME} DESTINATION "bin" COMPONENT "hyperion_qt" ) + install (TARGETS ${PROJECT_NAME} DESTINATION "bin" COMPONENT "hyperion_qt") endif() if(CMAKE_HOST_UNIX AND NOT APPLE) - install(CODE "EXECUTE_PROCESS(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\" )" COMPONENT "hyperion_qt" ) - install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_qt" ) - install(CODE "FILE (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME} )" COMPONENT "hyperion_qt" ) + install(CODE "execute_process(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\")" COMPONENT "hyperion_qt") + install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_qt") + install(CODE "file (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME})" COMPONENT "hyperion_qt") endif() diff --git a/src/hyperion-qt/QtWrapper.h b/src/hyperion-qt/QtWrapper.h index e4e689a39..979b27aa3 100644 --- a/src/hyperion-qt/QtWrapper.h +++ b/src/hyperion-qt/QtWrapper.h @@ -4,7 +4,7 @@ #include // Hyperion-Qt includes -#include +#include #include class QtWrapper : public QObject diff --git a/src/hyperion-remote/CMakeLists.txt b/src/hyperion-remote/CMakeLists.txt index a2805cadf..ef60a7dc5 100644 --- a/src/hyperion-remote/CMakeLists.txt +++ b/src/hyperion-remote/CMakeLists.txt @@ -1,68 +1,50 @@ cmake_minimum_required(VERSION 3.5.0) project(hyperion-remote) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Network Widgets REQUIRED) - -# The following I do not understand completely... -# libQtCore.so uses some hardcoded library path inside which are incorrect after copying the file RPi file system -# Therefore, an extra path is needed on which to find the required libraries -IF ( EXISTS ${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnueabihf ) - LINK_DIRECTORIES(${LINK_DIRECTORIES} ${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnueabihf) -ENDIF() - -set(hyperion-remote_HEADERS - JsonConnection.h) - -set(hyperion-remote_SOURCES - hyperion-remote.cpp - JsonConnection.cpp) - -# generate windows .rc file for this binary -if (WIN32) - include(${CMAKE_SOURCE_DIR}/cmake/win/win_rc.cmake) - generate_win_rc_file(${PROJECT_NAME}) +if(WIN32) + # generate windows .rc file for this binary + string(REPLACE "/" "\\\\" WIN_RC_ICON_PATH ${CMAKE_SOURCE_DIR}/cmake/nsis/installer.ico) + configure_file(${CMAKE_SOURCE_DIR}/cmake/win/win.rc.in ${CMAKE_BINARY_DIR}/win.rc) + set(WIN_RC_FILE ${CMAKE_BINARY_DIR}/win.rc) endif() add_executable(${PROJECT_NAME} - ${hyperion-remote_HEADERS} - ${hyperion-remote_SOURCES} - ${${PROJECT_NAME}_WIN_RC_PATH} + JsonConnection.h + JsonConnection.cpp + hyperion-remote.cpp + ${WIN_RC_FILE} ) target_link_libraries(${PROJECT_NAME} commandline hyperion-utils - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Widgets ) -if (ENABLE_AMLOGIC) - target_link_libraries(${PROJECT_NAME} - pcre16 dl z - ) +if(ENABLE_AMLOGIC) + target_link_libraries(${PROJECT_NAME} pcre16 dl z) endif() if(ENABLE_MDNS) - target_link_libraries(${PROJECT_NAME} mdns) + target_link_libraries(${PROJECT_NAME} mdns) else() - target_link_libraries(${PROJECT_NAME} ssdp) + target_link_libraries(${PROJECT_NAME} ssdp) endif() if(ENABLE_EFFECTENGINE) - target_link_libraries(${PROJECT_NAME} effectengine) + target_link_libraries(${PROJECT_NAME} effectengine) endif() if(APPLE) - install ( TARGETS ${PROJECT_NAME} DESTINATION "." COMPONENT "hyperion_remote" ) + install (TARGETS ${PROJECT_NAME} DESTINATION "." COMPONENT "hyperion_remote") elseif(NOT WIN32) - install ( TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_remote" ) + install (TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_remote") else() - install ( TARGETS ${PROJECT_NAME} DESTINATION "bin" COMPONENT "hyperion_remote" ) + install (TARGETS ${PROJECT_NAME} DESTINATION "bin" COMPONENT "hyperion_remote") endif() if(CMAKE_HOST_UNIX AND NOT APPLE) - install(CODE "EXECUTE_PROCESS(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\" )" COMPONENT "hyperion_remote" ) - install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_remote" ) - install(CODE "FILE (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME} )" COMPONENT "hyperion_remote" ) + install(CODE "execute_process(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\")" COMPONENT "hyperion_remote") + install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_remote") + install(CODE "file (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME})" COMPONENT "hyperion_remote") endif() diff --git a/src/hyperion-v4l2/CMakeLists.txt b/src/hyperion-v4l2/CMakeLists.txt index 1404d2ad8..37189cdc2 100644 --- a/src/hyperion-v4l2/CMakeLists.txt +++ b/src/hyperion-v4l2/CMakeLists.txt @@ -1,25 +1,10 @@ cmake_minimum_required(VERSION 3.5.0) project(hyperion-v4l2) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Network Widgets REQUIRED) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/flatbufserver - ${FLATBUFFERS_INCLUDE_DIRS} -) - -set(Hyperion_V4L2_HEADERS +add_executable(${PROJECT_NAME} ScreenshotHandler.h -) - -set(Hyperion_V4L2_SOURCES - hyperion-v4l2.cpp ScreenshotHandler.cpp -) - -add_executable(${PROJECT_NAME} - ${Hyperion_V4L2_HEADERS} - ${Hyperion_V4L2_SOURCES} + hyperion-v4l2.cpp ) target_link_libraries(${PROJECT_NAME} @@ -28,27 +13,23 @@ target_link_libraries(${PROJECT_NAME} hyperion-utils flatbufconnect flatbuffers - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Widgets ) if(ENABLE_MDNS) - target_link_libraries(${PROJECT_NAME} mdns) + target_link_libraries(${PROJECT_NAME} mdns) else() - target_link_libraries(${PROJECT_NAME} ssdp) + target_link_libraries(${PROJECT_NAME} ssdp) endif() -if (ENABLE_AMLOGIC) - target_link_libraries(${PROJECT_NAME} - pcre16 dl z - ) +if(ENABLE_AMLOGIC) + target_link_libraries(${PROJECT_NAME} pcre16 dl z) endif() -install ( TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_v4l2" ) +install (TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_v4l2") if(CMAKE_HOST_UNIX) - install(CODE "EXECUTE_PROCESS(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\" )" COMPONENT "hyperion_v4l2" ) - install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_v4l2" ) - install(CODE "FILE (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME} )" COMPONENT "hyperion_v4l2" ) + install(CODE "execute_process(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\")" COMPONENT "hyperion_v4l2") + install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_v4l2") + install(CODE "file (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME})" COMPONENT "hyperion_v4l2") endif(CMAKE_HOST_UNIX) diff --git a/src/hyperion-v4l2/hyperion-v4l2.cpp b/src/hyperion-v4l2/hyperion-v4l2.cpp index 731951777..daef95671 100644 --- a/src/hyperion-v4l2/hyperion-v4l2.cpp +++ b/src/hyperion-v4l2/hyperion-v4l2.cpp @@ -10,7 +10,7 @@ #include // grabber includes -#include "grabber/V4L2Grabber.h" +#include "grabber/video/v4l2/V4L2Grabber.h" // flatbuf includes #include @@ -255,7 +255,7 @@ int main(int argc, char** argv) SSDPDiscover discover; host = discover.getFirstService(searchType::STY_FLATBUFSERVER); #endif - + QHostAddress address; if (!NetUtils::resolveHostToAddress(log, host, address, port)) { diff --git a/src/hyperion-x11/CMakeLists.txt b/src/hyperion-x11/CMakeLists.txt index 88095ae38..20ca0f7ac 100644 --- a/src/hyperion-x11/CMakeLists.txt +++ b/src/hyperion-x11/CMakeLists.txt @@ -1,32 +1,14 @@ cmake_minimum_required(VERSION 3.5.0) project(hyperion-x11) -find_package(X11 REQUIRED) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Network Widgets REQUIRED) - - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/flatbufserver - ${X11_INCLUDES} - ${FLATBUFFERS_INCLUDE_DIRS} -) - if(APPLE) include_directories("/opt/X11/include") endif(APPLE) -set(Hyperion_X11_HEADERS +add_executable(${PROJECT_NAME} X11Wrapper.h -) - -set(Hyperion_X11_SOURCES - hyperion-x11.cpp X11Wrapper.cpp -) - -add_executable(${PROJECT_NAME} - ${Hyperion_X11_HEADERS} - ${Hyperion_X11_SOURCES} + hyperion-x11.cpp ) target_link_libraries(${PROJECT_NAME} @@ -35,25 +17,19 @@ target_link_libraries(${PROJECT_NAME} flatbufconnect flatbuffers x11-grabber - ${X11_LIBRARIES} - ${X11_Xrandr_LIB} - ${X11_Xrender_LIB} - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Gui - Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Widgets ) if(ENABLE_MDNS) - target_link_libraries(${PROJECT_NAME} mdns) + target_link_libraries(${PROJECT_NAME} mdns) else() - target_link_libraries(${PROJECT_NAME} ssdp) + target_link_libraries(${PROJECT_NAME} ssdp) endif() -install ( TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_x11" ) +install (TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_x11") if(CMAKE_HOST_UNIX) - install(CODE "EXECUTE_PROCESS(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\" )" COMPONENT "hyperion_x11" ) - install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_x11" ) - install(CODE "FILE (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME} )" COMPONENT "hyperion_x11" ) + install(CODE "execute_process(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\")" COMPONENT "hyperion_x11") + install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_x11") + install(CODE "file (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME})" COMPONENT "hyperion_x11") endif(CMAKE_HOST_UNIX) diff --git a/src/hyperion-x11/X11Wrapper.h b/src/hyperion-x11/X11Wrapper.h index d0f9f1f22..13dbfdff2 100644 --- a/src/hyperion-x11/X11Wrapper.h +++ b/src/hyperion-x11/X11Wrapper.h @@ -4,7 +4,7 @@ #include // Hyperion-X11 includes -#include +#include #include class X11Wrapper : public QObject diff --git a/src/hyperion-xcb/CMakeLists.txt b/src/hyperion-xcb/CMakeLists.txt index f378aef22..98b2ba323 100644 --- a/src/hyperion-xcb/CMakeLists.txt +++ b/src/hyperion-xcb/CMakeLists.txt @@ -1,48 +1,31 @@ cmake_minimum_required(VERSION 3.5.0) project(hyperion-xcb) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Network Widgets REQUIRED) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/flatbufserver - ${FLATBUFFERS_INCLUDE_DIRS} -) - -set(Hyperion_XCB_HEADERS +add_executable(${PROJECT_NAME} XcbWrapper.h -) - -set(Hyperion_XCB_SOURCES hyperion-xcb.cpp XcbWrapper.cpp ) -add_executable(${PROJECT_NAME} - ${Hyperion_XCB_HEADERS} - ${Hyperion_XCB_SOURCES} -) - target_link_libraries(${PROJECT_NAME} commandline hyperion-utils flatbufconnect flatbuffers xcb-grabber - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Widgets ) if(ENABLE_MDNS) - target_link_libraries(${PROJECT_NAME} mdns) + target_link_libraries(${PROJECT_NAME} mdns) else() - target_link_libraries(${PROJECT_NAME} ssdp) + target_link_libraries(${PROJECT_NAME} ssdp) endif() install (TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "hyperion_xcb") if(CMAKE_HOST_UNIX) - install(CODE "EXECUTE_PROCESS(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\" )" COMPONENT "hyperion_xcb" ) - install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_xcb" ) - install(CODE "FILE (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME} )" COMPONENT "hyperion_xcb" ) + install(CODE "execute_process(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\")" COMPONENT "hyperion_xcb") + install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME "${PROJECT_NAME}" COMPONENT "hyperion_xcb") + install(CODE "file (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME})" COMPONENT "hyperion_xcb") endif(CMAKE_HOST_UNIX) diff --git a/src/hyperion-xcb/XcbWrapper.h b/src/hyperion-xcb/XcbWrapper.h index d75aa63f7..e3806ade5 100644 --- a/src/hyperion-xcb/XcbWrapper.h +++ b/src/hyperion-xcb/XcbWrapper.h @@ -4,7 +4,7 @@ #include // Hyperion-Xcb includes -#include +#include #include //Utils includes diff --git a/src/hyperiond/CMakeLists.txt b/src/hyperiond/CMakeLists.txt index 35326c221..4d227d81e 100644 --- a/src/hyperiond/CMakeLists.txt +++ b/src/hyperiond/CMakeLists.txt @@ -1,41 +1,32 @@ -if (APPLE) +if(APPLE) project(Hyperion) else() project(hyperiond) endif() -if(ENABLE_EFFECTENGINE) - if (NOT CMAKE_VERSION VERSION_LESS "3.12") - find_package(Python3 COMPONENTS Interpreter Development REQUIRED) - include_directories(${Python3_INCLUDE_DIRS} ${Python3_INCLUDE_DIRS}/..) - else() - find_package (PythonLibs ${PYTHON_VERSION_STRING} EXACT) # Maps PythonLibs to the PythonInterp version of the main cmake - include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/..) - endif() -endif () - -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Network Gui Widgets REQUIRED) +##################################### +############ Preparation ############ +##################################### -# generate windows .rc file for this binary -if (WIN32) - include(${CMAKE_SOURCE_DIR}/cmake/win/win_rc.cmake) - generate_win_rc_file(${PROJECT_NAME}) -endif(WIN32) +if(WIN32) + # generate windows .rc file for this binary + string(REPLACE "/" "\\\\" WIN_RC_ICON_PATH ${CMAKE_SOURCE_DIR}/cmake/nsis/installer.ico) + configure_file(${CMAKE_SOURCE_DIR}/cmake/win/win.rc.in ${CMAKE_BINARY_DIR}/win.rc) + set(WIN_RC_FILE ${CMAKE_BINARY_DIR}/win.rc) -# include resource files for macos bundle (copy LICENSE file and correct line breaks) -if (APPLE) + # promote hyperiond as GUI app + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup") +elseif(APPLE) + # include resource files for macos bundle (copy LICENSE file and correct line breaks) configure_file(${CMAKE_SOURCE_DIR}/LICENSE ${CMAKE_BINARY_DIR}/LICENSE COPYONLY) execute_process(COMMAND bash -c "perl -pi -e 's/\n/\r/g' ${CMAKE_BINARY_DIR}/LICENSE") - set(BUNDLE_RESOURCE_FILES ${CMAKE_SOURCE_DIR}/cmake/osxbundle/Hyperion.icns ${CMAKE_BINARY_DIR}/LICENSE) - set_source_files_properties(${BUNDLE_RESOURCE_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) -endif(APPLE) - -if (UNIX) - find_package(Qt${QT_VERSION_MAJOR} COMPONENTS DBus QUIET ) - if (Qt${QT_VERSION_MAJOR}DBus_FOUND) - set(hyperiond_POWER_MNG_DBUS "Qt${QT_VERSION_MAJOR}::DBus") - endif() -endif(UNIX) + set(MACOS_BUNDLE_RESOURCE_FILES ${CMAKE_SOURCE_DIR}/cmake/osxbundle/Hyperion.icns ${CMAKE_BINARY_DIR}/LICENSE) + set_source_files_properties(${MACOS_BUNDLE_RESOURCE_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) +endif() + +##################################### +########### General steps ########### +##################################### add_executable(${PROJECT_NAME} console.h @@ -45,19 +36,10 @@ add_executable(${PROJECT_NAME} systray.cpp SuspendHandler.cpp main.cpp - ${hyperiond_WIN_RC_PATH} - ${BUNDLE_RESOURCE_FILES} + ${WIN_RC_FILE} + ${MACOS_BUNDLE_RESOURCE_FILES} ) -if (UNIX AND NOT APPLE AND Qt${QT_VERSION_MAJOR}DBus_FOUND) - target_compile_definitions(${PROJECT_NAME} PUBLIC HYPERION_HAS_DBUS) -endif() - -# promote hyperiond as GUI app -if (WIN32) - target_link_options(${PROJECT_NAME} PUBLIC /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup) -endif(WIN32) - target_link_libraries(${PROJECT_NAME} commandline hyperion @@ -70,18 +52,16 @@ target_link_libraries(${PROJECT_NAME} Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Widgets - ${hyperiond_POWER_MNG_DBUS} ) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS DBus QUIET) +if(Qt${QT_VERSION_MAJOR}DBus_FOUND) + target_link_libraries(${PROJECT_NAME} "Qt${QT_VERSION_MAJOR}::DBus") +endif() + if(ENABLE_EFFECTENGINE) target_link_libraries(${PROJECT_NAME} effectengine python) - - if (NOT CMAKE_VERSION VERSION_LESS "3.12") - target_link_libraries( ${PROJECT_NAME} ${Python3_LIBRARIES} ) - else() - target_link_libraries( ${PROJECT_NAME} ${PYTHON_LIBRARIES} ) - endif() -endif () +endif() if(ENABLE_FLATBUF_SERVER) target_link_libraries(${PROJECT_NAME} flatbufserver) @@ -91,71 +71,71 @@ if(ENABLE_PROTOBUF_SERVER) target_link_libraries(${PROJECT_NAME} protoserver) endif() -if (ENABLE_AMLOGIC) - target_link_libraries(${PROJECT_NAME} - #Qt${QT_VERSION_MAJOR}::Core - pcre16 dl z - ) +if(ENABLE_AMLOGIC) + target_link_libraries(${PROJECT_NAME} pcre16 dl z) endif(ENABLE_AMLOGIC) -if (ENABLE_DISPMANX) +if(ENABLE_DISPMANX) target_link_libraries(${PROJECT_NAME} dispmanx-grabber) endif (ENABLE_DISPMANX) -if (ENABLE_FB) +if(ENABLE_FB) target_link_libraries(${PROJECT_NAME} framebuffer-grabber) endif (ENABLE_FB) -if (ENABLE_OSX) +if(ENABLE_OSX) target_link_libraries(${PROJECT_NAME} osx-grabber) endif (ENABLE_OSX) -if (ENABLE_V4L2) +if(ENABLE_V4L2) target_link_libraries(${PROJECT_NAME} v4l2-grabber) -endif () +endif() -if (ENABLE_MF) +if(ENABLE_MF) target_link_libraries(${PROJECT_NAME} mf-grabber) endif (ENABLE_MF) -if (ENABLE_AUDIO) +if(ENABLE_AUDIO) target_link_libraries(hyperiond audio-grabber) endif() -if (ENABLE_AMLOGIC) +if(ENABLE_AMLOGIC) target_link_libraries(${PROJECT_NAME} amlogic-grabber) endif (ENABLE_AMLOGIC) -if (ENABLE_X11) +if(ENABLE_X11) if(APPLE) include_directories("/opt/X11/include") endif(APPLE) target_link_libraries(${PROJECT_NAME} x11-grabber) endif (ENABLE_X11) -if (ENABLE_XCB) +if(ENABLE_XCB) target_link_libraries(${PROJECT_NAME} xcb-grabber) endif (ENABLE_XCB) -if (ENABLE_QT) +if(ENABLE_QT) target_link_libraries(${PROJECT_NAME} qt-grabber) endif (ENABLE_QT) -if (ENABLE_DX) - include_directories(${DIRECTX9_INCLUDE_DIRS}) +if(ENABLE_DX) target_link_libraries(${PROJECT_NAME} directx-grabber) endif (ENABLE_DX) -if (ENABLE_CEC) - target_link_libraries(${PROJECT_NAME} cechandler) +if(ENABLE_CEC) + target_link_libraries(${PROJECT_NAME} cechandler) endif (ENABLE_CEC) -if (ENABLE_MDNS) +if(ENABLE_MDNS) target_link_libraries(${PROJECT_NAME} mdns) endif() -if (APPLE) - set_target_properties( ${PROJECT_NAME} PROPERTIES +##################################### +########### Install steps ########### +##################################### + +if(APPLE) + set_target_properties(${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/osxbundle/Info.plist.in MACOSX_BUNDLE_BUNDLE_NAME "Hyperion" @@ -168,69 +148,83 @@ if (APPLE) MACOSX_BUNDLE_LONG_VERSION_STRING ${HYPERION_VERSION} ) - install ( TARGETS ${PROJECT_NAME} DESTINATION . COMPONENT "Hyperion") + install (TARGETS ${PROJECT_NAME} DESTINATION . COMPONENT "Hyperion") elseif(NOT WIN32) - install ( TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "Hyperion" ) - install ( DIRECTORY ${CMAKE_SOURCE_DIR}/bin/service DESTINATION "share/hyperion/" COMPONENT "Hyperion" ) - install ( FILES ${CMAKE_SOURCE_DIR}/effects/readme.txt DESTINATION "share/hyperion/effects" COMPONENT "Hyperion" ) - install ( FILES ${CMAKE_SOURCE_DIR}/resources/icons/hyperion-icon-32px.png DESTINATION "share/hyperion/icons" COMPONENT "Hyperion" ) - - # Desktop file for Hyperion - install ( FILES ${CMAKE_SOURCE_DIR}/cmake/desktop/hyperiond_128.png DESTINATION "share/hyperion/desktop" COMPONENT "Hyperion" ) - install ( FILES ${CMAKE_SOURCE_DIR}/cmake/desktop/hyperiond.desktop DESTINATION "share/hyperion/desktop" COMPONENT "Hyperion" ) + # install Hyperion/service files/effect folder + install (TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "Hyperion") + install (DIRECTORY ${CMAKE_SOURCE_DIR}/bin/service DESTINATION "share/hyperion" COMPONENT "Hyperion") + install (FILES ${CMAKE_SOURCE_DIR}/effects/readme.txt DESTINATION "share/hyperion/effects" COMPONENT "Hyperion") + + # install Hyperion icons + set(ICON_SIZES 16 22 24 32 36 48 64 72 96 128 192 256 512) + foreach(size ${ICON_SIZES}) + set(ICONS_FROM "${CMAKE_SOURCE_DIR}/resources/icons/hyperion-${size}px.png") + set(ICONS_TO "share/hyperion/icons/${size}x${size}/apps/") + install(FILES ${ICONS_FROM} DESTINATION ${ICONS_TO} RENAME "hyperion.png" COMPONENT "Hyperion") + endforeach(size) + + # install desktop/appstream file + install (FILES ${CMAKE_SOURCE_DIR}/cmake/desktop/hyperion.metainfo.xml DESTINATION "share/hyperion/desktop" COMPONENT "Hyperion") + install (FILES ${CMAKE_SOURCE_DIR}/cmake/desktop/hyperion.desktop DESTINATION "share/hyperion/desktop" COMPONENT "Hyperion") else() - install ( TARGETS ${PROJECT_NAME} DESTINATION "bin" COMPONENT "Hyperion" ) - install ( FILES ${CMAKE_SOURCE_DIR}/effects/readme.txt DESTINATION "effects" COMPONENT "Hyperion" ) - - #set( CMAKE_INSTALL_UCRT_LIBRARIES TRUE ) - #set( CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE ) - #include( InstallRequiredSystemLibraries ) + install (TARGETS ${PROJECT_NAME} DESTINATION "bin" COMPONENT "Hyperion") + install (FILES ${CMAKE_SOURCE_DIR}/effects/readme.txt DESTINATION "effects" COMPONENT "Hyperion") endif() -if (CMAKE_HOST_UNIX AND NOT APPLE) - install( CODE "EXECUTE_PROCESS(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\" )" COMPONENT "Hyperion" ) - install( FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME ${PROJECT_NAME} COMPONENT "Hyperion" ) - install( CODE "FILE (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME})" COMPONENT "Hyperion" ) - install( FILES ${CMAKE_SOURCE_DIR}/bin/scripts/updateHyperionUser.sh DESTINATION "share/hyperion/scripts" COMPONENT "Hyperion" ) +if(CMAKE_HOST_UNIX AND NOT APPLE) + install(CODE "execute_process(COMMAND ln -sf \"../share/hyperion/bin/${PROJECT_NAME}\" \"${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}\")" COMPONENT "Hyperion") + install(FILES "${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME}" DESTINATION "bin" RENAME ${PROJECT_NAME} COMPONENT "Hyperion") + install(CODE "file (REMOVE ${CMAKE_BINARY_DIR}/symlink_${PROJECT_NAME})" COMPONENT "Hyperion") + install(FILES ${CMAKE_SOURCE_DIR}/bin/scripts/updateHyperionUser.sh DESTINATION "share/hyperion/scripts" COMPONENT "Hyperion") endif() +###################################### +########## Additional steps ########## +###################################### + # Deploy Qt DLLs into the binary folder. # This is necessary for starting the application from within the IDE -if (WIN32) +if(WIN32) get_target_property(QT_QMAKE_EXECUTABLE Qt${QT_VERSION_MAJOR}::qmake IMPORTED_LOCATION) get_filename_component(QT_BIN_DIR "${QT_QMAKE_EXECUTABLE}" DIRECTORY) find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${QT_BIN_DIR}") - if (NOT WINDEPLOYQT_EXECUTABLE) + if(NOT WINDEPLOYQT_EXECUTABLE) find_program(WINDEPLOYQT_EXECUTABLE windeployqt) endif() - if (WINDEPLOYQT_EXECUTABLE AND NOT CMAKE_GITHUB_ACTION) + if(WINDEPLOYQT_EXECUTABLE AND NOT CMAKE_GITHUB_ACTION) set(WINDEPLOYQT_PARAMS_RUNTIME --verbose 0 --no-compiler-runtime --no-opengl-sw --no-system-d3d-compiler) message(STATUS "Found windeployqt: ${WINDEPLOYQT_EXECUTABLE} PATH_HINT:${QT_BIN_DIR}") add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${WINDEPLOYQT_EXECUTABLE} ${WINDEPLOYQT_PARAMS_RUNTIME} "$") endif() find_package(OpenSSL REQUIRED) - if (OPENSSL_FOUND) + if(OPENSSL_FOUND) string(REGEX MATCHALL "[0-9]+" openssl_versions "${OPENSSL_VERSION}") list(GET openssl_versions 0 openssl_version_major) list(GET openssl_versions 1 openssl_version_minor) - set(library_suffix "-${openssl_version_major}_${openssl_version_minor}") - if (CMAKE_SIZEOF_VOID_P EQUAL 8) - string(APPEND library_suffix "-x64") + set(open_ssl_version_suffix) + if(openssl_version_major VERSION_EQUAL 1 AND openssl_version_minor VERSION_EQUAL 1) + set(open_ssl_version_suffix "-1_1") + else() + set(open_ssl_version_suffix "-3") + endif() + + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + string(APPEND open_ssl_version_suffix "-x64") endif() find_file(OPENSSL_SSL - NAMES "libssl${library_suffix}.dll" + NAMES "libssl${open_ssl_version_suffix}.dll" PATHS ${OPENSSL_INCLUDE_DIR}/.. ${OPENSSL_INCLUDE_DIR}/../bin NO_DEFAULT_PATH ) find_file(OPENSSL_CRYPTO - NAMES "libcrypto${library_suffix}.dll" + NAMES "libcrypto${open_ssl_version_suffix}.dll" PATHS ${OPENSSL_INCLUDE_DIR}/.. ${OPENSSL_INCLUDE_DIR}/../bin NO_DEFAULT_PATH ) @@ -248,11 +242,11 @@ if(ENABLE_DEPLOY_DEPENDENCIES) # Deploy all dependencies for package creation include(${CMAKE_SOURCE_DIR}/cmake/Dependencies.cmake) - if (APPLE) #macOS + if(APPLE) #macOS DeployMacOS(${PROJECT_NAME}) elseif (NOT WIN32) # Linux DeployLinux(${PROJECT_NAME}) elseif(WIN32) # Windows DeployWindows(${PROJECT_NAME}) - endif () + endif() endif(ENABLE_DEPLOY_DEPENDENCIES) diff --git a/src/hyperiond/hyperiond.h b/src/hyperiond/hyperiond.h index 2a2927460..c8b631130 100644 --- a/src/hyperiond/hyperiond.h +++ b/src/hyperiond/hyperiond.h @@ -7,62 +7,62 @@ #include #ifdef ENABLE_DISPMANX - #include + #include #else typedef QObject DispmanxWrapper; #endif #if defined(ENABLE_V4L2) || defined(ENABLE_MF) - #include + #include #else typedef QObject VideoWrapper; #endif #ifdef ENABLE_FB - #include + #include #else typedef QObject FramebufferWrapper; #endif #ifdef ENABLE_AMLOGIC - #include + #include #else typedef QObject AmlogicWrapper; #endif #ifdef ENABLE_OSX - #include + #include #else typedef QObject OsxWrapper; #endif #ifdef ENABLE_X11 - #include + #include #else typedef QObject X11Wrapper; #endif #ifdef ENABLE_XCB - #include + #include #else typedef QObject XcbWrapper; #endif #ifdef ENABLE_QT - #include + #include #else typedef QObject QtWrapper; #endif #ifdef ENABLE_DX - #include + #include #else typedef QObject DirectXWrapper; #endif #include #ifdef ENABLE_AUDIO - #include + #include #else typedef QObject AudioWrapper; #endif @@ -211,8 +211,8 @@ private slots: OsxWrapper* _osxGrabber; QtWrapper* _qtGrabber; DirectXWrapper* _dxGrabber; - AudioWrapper* _audioGrabber; SSDPHandler* _ssdp; + AudioWrapper* _audioGrabber; #ifdef ENABLE_CEC CECHandler* _cecHandler; #endif diff --git a/src/hyperiond/main.cpp b/src/hyperiond/main.cpp index fa9352b95..9bdda136f 100644 --- a/src/hyperiond/main.cpp +++ b/src/hyperiond/main.cpp @@ -115,7 +115,7 @@ QCoreApplication* createApplication(int &argc, char *argv[]) app->addLibraryPath(QApplication::applicationDirPath() + "/../lib"); app->setApplicationDisplayName("Hyperion"); #ifndef __APPLE__ - app->setWindowIcon(QIcon(":/hyperion-icon-32px.png")); + app->setWindowIcon(QIcon(":/hyperion-32px.png")); #endif return app; } diff --git a/src/hyperiond/systray.cpp b/src/hyperiond/systray.cpp index ab7b6c8a4..34f8de0a5 100644 --- a/src/hyperiond/systray.cpp +++ b/src/hyperiond/systray.cpp @@ -33,8 +33,8 @@ SysTray::SysTray(HyperionDaemon *hyperiond) , _hyperiond(hyperiond) , _hyperion(nullptr) , _instanceManager(HyperionIManager::getInstance()) - , _suspendHandler (hyperiond->getSuspendHandlerInstance()) , _webPort(8090) + , _suspendHandler (hyperiond->getSuspendHandlerInstance()) { Q_INIT_RESOURCE(resources); @@ -281,7 +281,7 @@ void SysTray::handleInstanceStateChange(InstanceState state, quint8 instance, co connect(quitAction, &QAction::triggered, _trayIcon, &QSystemTrayIcon::hide, Qt::DirectConnection); connect(&_colorDlg, &QColorDialog::currentColorChanged, this, &SysTray::setColor); - QIcon icon(":/hyperion-icon-32px.png"); + QIcon icon(":/hyperion-32px.png"); _trayIcon->setIcon(icon); _trayIcon->show(); setWindowIcon(icon); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0e447f571..28378df6b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,17 +3,17 @@ include_directories(../libsrc) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED) -MACRO (link_to_hyperion TARGET) - target_link_libraries( ${TARGET} blackborder leddevice jsonserver hyperion-utils hyperion ) +macro (link_to_hyperion TARGET) + target_link_libraries(${TARGET} blackborder leddevice jsonserver hyperion-utils hyperion) if(ENABLE_EFFECTENGINE) - target_link_libraries( ${TARGET} effectengine ) + target_link_libraries(${TARGET} effectengine) endif() -ENDMACRO() +endmacro() if(ENABLE_DEV_SPI) # Add the simple test executable 'TestSpi' add_executable(test_spi TestSpi.cpp) - target_link_libraries( test_spi leddevice hyperion-utils hyperion ) + target_link_libraries(test_spi leddevice hyperion-utils hyperion) add_executable(spidev_test spidev_test.c) add_executable(gpio2spi switchPinCtrl.c) endif(ENABLE_DEV_SPI) @@ -42,12 +42,12 @@ endif(ENABLE_X11) add_executable(test_versions TestVersions.cpp) target_link_libraries(test_versions Qt${QT_VERSION_MAJOR}::Core) -add_executable(test_image2ledsmap TestImage2LedsMap.cpp "${CMAKE_BINARY_DIR}/resources.qrc" ) +add_executable(test_image2ledsmap TestImage2LedsMap.cpp "${CMAKE_BINARY_DIR}/resources.qrc") link_to_hyperion(test_image2ledsmap) ######### These tests are broken. May they fix someone ########## -#if (ENABLE_DISPMANX) +#if(ENABLE_DISPMANX) # add_subdirectory(dispmanx2png) #endif (ENABLE_DISPMANX) diff --git a/test/dispmanx2png/CMakeLists.txt b/test/dispmanx2png/CMakeLists.txt index 7dfdd7593..80037b9bf 100644 --- a/test/dispmanx2png/CMakeLists.txt +++ b/test/dispmanx2png/CMakeLists.txt @@ -1,5 +1,5 @@ # this is only available on real pi -IF ( "${PLATFORM}" MATCHES rpi) +if("${PLATFORM}" MATCHES rpi) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Gui REQUIRED) @@ -16,4 +16,4 @@ IF ( "${PLATFORM}" MATCHES rpi) target_link_libraries(dispmanx2png dispmanx-grabber Qt${QT_VERSION_MAJOR::Gui) -ENDIF() +endif() diff --git a/test/dispmanx2png/dispmanx2png.cpp b/test/dispmanx2png/dispmanx2png.cpp index 2739f4fde..2c2a1748f 100644 --- a/test/dispmanx2png/dispmanx2png.cpp +++ b/test/dispmanx2png/dispmanx2png.cpp @@ -7,7 +7,7 @@ #include // Dispmanx grabber includes -#include +#include static bool running = true;