From 7db7dad988bd7b7c63ba31cd41458d3e79191a0e Mon Sep 17 00:00:00 2001 From: ivaquero Date: Sat, 18 Apr 2026 14:14:49 +0800 Subject: [PATCH] v0.1.0 --- .github/workflows/build.yml | 143 ---------- .github/workflows/ci.yml | 156 +---------- .github/workflows/release.yml | 490 +++++++++++++++++----------------- .vscode/settings.json | 1 + README.md | 17 +- window_helper_linux.cpp | 102 ++++--- 6 files changed, 326 insertions(+), 583 deletions(-) delete mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 9c3d1ee..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,143 +0,0 @@ -name: Build Qt Application - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - workflow_dispatch: - -jobs: - build-macos: - runs-on: macos-latest - steps: - - uses: actions/checkout@v6 - - - name: Install Qt - uses: jurplel/install-qt-action@v4 - with: - version: "6.5.*" - modules: "qt5compat" - cache: true - tools: "tools_ninja" - install-deps: "true" - - - name: Build with qmake - run: | - qmake Clouck.pro CONFIG+=release - make - - - name: Create macOS Bundle - run: | - macdeployqt build/Clouck.app -dmg - - - name: Upload macOS Build - uses: actions/upload-artifact@v7 - with: - name: Clouck-qmake - path: build/Clouck.dmg - - build-windows: - runs-on: windows-latest - steps: - - uses: actions/checkout@v6 - - - name: Setup MSVC Environment - uses: ilammy/msvc-dev-cmd@v1 - - - name: Install Qt - uses: jurplel/install-qt-action@v4 - with: - version: "6.5.*" - modules: "qt5compat" - cache: true - tools: "tools_ninja" - install-deps: "true" - - - name: Build with qmake - shell: cmd - run: | - qmake Clouck.pro CONFIG+=release - nmake - - - name: Deploy Windows Build - run: | - mkdir Clouck-windows-dist - copy build\Clouck.exe Clouck-windows-dist\ - windeployqt --release Clouck-windows-dist\Clouck.exe - - - name: Upload Windows Build - uses: actions/upload-artifact@v7 - with: - name: Clouck-windows-qmake - path: Clouck-windows-dist - - # build-linux: - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v6 - - # - name: Install Dependencies - # run: | - # sudo apt-get update - # sudo apt-get install -y build-essential qt6-base-dev qt6-tools-dev libx11-dev libxfixes-dev - - # - name: Install Qt - # uses: jurplel/install-qt-action@v4 - # with: - # version: "6.5.*" - # modules: "qt5compat" - # cache: true - - # - name: Build with qmake - # run: | - # qmake Clouck.pro CONFIG+=release - # make - - # - name: Create Linux Distribution - # run: | - # mkdir -p Clouck-linux-dist - # cp Clouck Clouck-linux-dist/ - # ldd Clouck | grep -o '/lib[^ ]*' | xargs -I {} cp {} Clouck-linux-dist/ 2>/dev/null || true - - # - name: Upload Linux Build - # uses: actions/upload-artifact@v7 - # with: - # name: Clouck-linux-qmake - # path: Clouck-linux-dist - - build-cmake: - strategy: - matrix: - os: [ windows-latest, macos-latest ] - - runs-on: ${{ matrix.os }} - - steps: - - uses: actions/checkout@v6 - - - name: Install Qt - uses: jurplel/install-qt-action@v4 - with: - version: "6.5.*" - modules: "qt5compat" - cache: true - - - name: Install Linux Dependencies - if: runner.os == 'Linux' - run: | - sudo apt-get update - sudo apt-get install -y build-essential cmake libx11-dev libxfixes-dev - - - name: Configure CMake - run: | - cmake -B build -S . -DCMAKE_BUILD_TYPE=Release - - - name: Build with CMake - run: cmake --build build --config Release - - - name: Upload CMake Build - uses: actions/upload-artifact@v7 - with: - name: Clouck-${{ runner.os }}-cmake - path: build/Clouck* diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4073be9..a32d06f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,161 +40,15 @@ jobs: version: "6.5.*" modules: "qt5compat" cache: true - tools: "tools_ninja" - install-deps: "true" - aqtversion: "==3.1.*" - py7zrversion: ">=0.20.2" - # - name: Install Linux Dependencies - # if: runner.os == 'Linux' - # run: | - # sudo apt-get update - # sudo apt-get install -y build-essential cmake libx11-dev libxfixes-dev - - - name: Configure CMake (Windows) - if: runner.os == 'Windows' - shell: cmd - run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" - echo "Configuring CMake for Windows..." - cmake -B build -S . -DCMAKE_BUILD_TYPE=Release - echo "CMake configuration completed." - echo "Checking if build directory was created:" - dir build 2>nul && echo "Build directory exists" || echo "Build directory NOT found" - echo "Contents of current directory:" - dir - - - name: Configure CMake (macOS) - if: runner.os == 'macOS' + - name: Configure CMake run: cmake -B build -S . -DCMAKE_BUILD_TYPE=Release - - name: Build (Windows) - if: runner.os == 'Windows' - shell: cmd - run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" - echo "Starting Windows build..." - echo "=== Pre-build diagnostics ===" - echo "Current directory: %CD%" - echo "Checking if CMakeLists.txt exists:" - dir CMakeLists.txt 2>nul && echo "✓ CMakeLists.txt found" || echo "✗ CMakeLists.txt NOT found" - echo "Contents before build:" - dir - echo "=== Building with CMake ===" - cmake --build build --config Release - echo "=== Post-build diagnostics ===" - echo "Build completed with exit code: %ERRORLEVEL%" - echo "Contents after build:" - dir - echo "=== Searching for Clouck executable ===" - echo "Checking build directory structure:" - dir build /s /b 2>nul || echo "Build directory not found or empty" - echo "Looking for Clouck.exe in specific locations:" - dir build\Clouck.exe 2>nul && echo "✓ Found Clouck.exe in build\" || echo "✗ Clouck.exe not in build\" - dir build\Release\Clouck.exe 2>nul && echo "✓ Found Clouck.exe in build\Release\" || echo "✗ Clouck.exe not in build\Release\" - dir build\MinSizeRel\Clouck.exe 2>nul && echo "✓ Found Clouck.exe in build\MinSizeRel\" || echo "✗ Clouck.exe not in build\MinSizeRel\" - echo "Searching entire directory tree for any Clouck.exe:" - dir Clouck.exe /s /b 2>nul || echo "No Clouck.exe found anywhere" - echo "Searching for any .exe files in build directory:" - dir build\*.exe /s /b 2>nul || echo "No .exe files found in build" - - - name: Build (macOS) - if: runner.os == 'macOS' + - name: Build run: cmake --build build --config Release - - name: Quick Binary Validation (macOS) - if: runner.os == 'macOS' - run: find ./build -name "Clouck" -type f - - - name: Test Build (macOS) - if: runner.os == 'macOS' - run: timeout 3s ./build/Clouck.app/Contents/MacOS/Clouck || echo "Test - completed" - - - name: Quick Binary Validation (Windows) - if: runner.os == 'Windows' - shell: cmd - run: | - echo "=== Windows Quick Binary Validation ===" - echo "Current directory: %CD%" - echo "Looking for build directory..." - dir build 2>nul && echo "Build directory exists" || echo "Build directory NOT found" - echo "Looking for Clouck executable in possible locations:" - dir build\Clouck.exe 2>nul && echo "✓ Found Clouck.exe in build\" || echo "✗ Clouck.exe not in build\" - dir build\Release\Clouck.exe 2>nul && echo "✓ Found Clouck.exe in build\Release\" || echo "✗ Clouck.exe not in build\Release\" - dir build\MinSizeRel\Clouck.exe 2>nul && echo "✓ Found Clouck.exe in build\MinSizeRel\" || echo "✗ Clouck.exe not in build\MinSizeRel\" - echo "Searching entire build directory for any .exe files:" - dir build\*.exe /s /b 2>nul || echo "No .exe files found in build directory" - echo "=== End Validation ===" - - - name: Test Build (Windows) - if: runner.os == 'Windows' - shell: cmd - run: | - echo "=== Windows Test Build Diagnostics ===" - echo "Current directory: %CD%" - echo "Visual Studio environment is configured (see env vars above)" - echo "Checking for build directory..." - if exist build ( - echo "Build directory exists" - echo "Contents of build directory:" - dir build - echo "Looking for Clouck.exe in build directory..." - if exist build\Clouck.exe ( - echo "Found Clouck.exe in build\" - echo "Testing Windows binary..." - start /min build\Clouck.exe & timeout /t 2 /nobreak >nul 2>&1 & tasklist | findstr Clouck.exe >nul 2>&1 - ) else ( - echo "Clouck.exe not found in build\" - echo "Checking build\Release directory..." - if exist build\Release\Clouck.exe ( - echo "Found Clouck.exe in build\Release\" - echo "Testing Windows binary..." - start /min build\Release\Clouck.exe & timeout /t 2 /nobreak >nul 2>&1 & tasklist | findstr Clouck.exe >nul 2>&1 - ) else ( - echo "Clouck.exe not found in build\Release\" - echo "Checking build\MinSizeRel directory..." - if exist build\MinSizeRel\Clouck.exe ( - echo "Found Clouck.exe in build\MinSizeRel\" - echo "Testing Windows binary..." - start /min build\MinSizeRel\Clouck.exe & timeout /t 2 /nobreak >nul 2>&1 & tasklist | findstr Clouck.exe >nul 2>&1 - ) else ( - echo "ERROR: Clouck.exe not found in any expected location!" - echo "Searching entire build directory for any .exe files:" - dir build\*.exe /s /b - echo "Searching entire working directory for Clouck.exe:" - dir Clouck.exe /s /b - echo "Build failed - no executable found" - exit 1 - ) - ) - ) - ) else ( - echo "ERROR: Build directory does not exist!" - echo "Contents of current directory:" - dir - exit 1 - ) - - - name: Upload Build Artifact (Windows) - if: runner.os == 'Windows' + - name: Upload Build Artifact uses: actions/upload-artifact@v7 with: - name: Clouck-windows - path: build/Clouck*.exe - - - name: Upload Build Artifact (macOS) - if: runner.os == 'macOS' - run: | - echo "Checking for macOS app bundle..." - ls -la ./build/Clouck.app/Contents/MacOS/Clouck || echo "Clouck.app not found" - - - name: Upload macOS Artifact - if: runner.os == 'macOS' - uses: actions/upload-artifact@v7 - with: - name: Clouck-macos - path: | - build/Clouck.app/**/* - !build/Clouck.app/Contents/Frameworks/* - !build/Clouck.app/Contents/PlugIns/* + name: Clouck-${{ runner.os }}-cmake + path: build/Clouck* diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6f07a43..9d21e41 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,285 +1,281 @@ name: Build and Release Clouck on: - push: - tags: - - "v*" - workflow_dispatch: - inputs: - version: - description: "Version to build (e.g., v1.0.0)" - required: true - default: "v1.0.0" + push: + tags: + - "v*" + - "[0-9]+.[0-9]+.[0-9]+" + branches: + - main + - master + workflow_dispatch: + inputs: + version: + description: "Version to build (e.g., v1.0.0)" + required: true + default: "v1.0.0" jobs: - build-macos: - runs-on: macos-latest - steps: - - uses: actions/checkout@v6 + build-macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v6 - - name: Install Qt - uses: jurplel/install-qt-action@v4 - with: - version: "6.5.*" - cache: true + - name: Install Qt + uses: jurplel/install-qt-action@v4 + with: + version: "6.5.*" + cache: true - - name: Configure CMake - run: | - cmake -B build -S . -DCMAKE_BUILD_TYPE=Release + - name: Configure and Build + run: | + cmake -B build -S . -DCMAKE_BUILD_TYPE=Release + cmake --build build --config Release - - name: Build - run: cmake --build build --config Release + - name: Create macOS App Bundle + run: | + # Check what was actually built + echo "Contents of build directory:" + ls -la build/ - - name: Create macOS App Bundle - run: | - # Debug: Check current directory and build output - echo "Current directory: $(pwd)" - echo "Build directory contents:" - ls -la build/ - echo "Checking if Clouck executable exists:" - ls -la build/Clouck || echo "ERROR: Clouck executable not found!" + # Look for the .app bundle or executable + if [ -d "build/Clouck.app" ]; then + echo "Found .app bundle" + cp -r build/Clouck.app ./ + elif [ -f "build/Clouck" ]; then + echo "Found standalone executable" + # Create app bundle + mkdir -p Clouck.app/Contents/MacOS + mkdir -p Clouck.app/Contents/Resources + cp build/Clouck Clouck.app/Contents/MacOS/ + else + echo "Looking for executable in build directory..." + find build/ -name "Clouck*" -type f + # Try to find and copy the first executable + EXECUTABLE=$(find build/ -name "Clouck*" -type f | head -1) + if [ -n "$EXECUTABLE" ]; then + echo "Found executable: $EXECUTABLE" + mkdir -p Clouck.app/Contents/MacOS + mkdir -p Clouck.app/Contents/Resources + cp "$EXECUTABLE" Clouck.app/Contents/MacOS/ + else + echo "ERROR: No Clouck executable found!" + exit 1 + fi + fi - # Create app bundle structure - mkdir -p Clouck.app/Contents/MacOS - mkdir -p Clouck.app/Contents/Resources + # Create Info.plist + cat > Clouck.app/Contents/Info.plist << EOF + + + + + CFBundleExecutable + Clouck + CFBundleIdentifier + com.clouck.app + CFBundleName + Clouck + CFBundleVersion + 1.0.0 + CFBundlePackageType + APPL + LSUIElement + + + + EOF - # Copy executable - cp build/Clouck Clouck.app/Contents/MacOS/ + - name: Deploy Qt Dependencies + run: | + if [ -d "Clouck.app" ]; then + macdeployqt Clouck.app -dmg || hdiutil create -volname "Clouck" -srcfolder Clouck.app -ov -format UDZO Clouck.dmg + else + echo "ERROR: Clouck.app not found!" + exit 1 + fi - # Verify executable was copied - echo "App bundle contents:" - ls -la Clouck.app/Contents/MacOS/ + - name: Upload macOS Artifact + uses: actions/upload-artifact@v7 + with: + name: Clouck-macos + path: Clouck.dmg - # Create Info.plist - cat > Clouck.app/Contents/Info.plist << EOF - - - - - CFBundleExecutable - Clouck - CFBundleIdentifier - com.clouck.app - CFBundleName - Clouck - CFBundleVersion - 1.0.0 - CFBundlePackageType - APPL - LSUIElement - - - - EOF + build-windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v6 - # Verify app bundle exists before running macdeployqt - echo "Verifying app bundle structure:" - if [ -d "Clouck.app" ]; then - echo "App bundle directory exists" - ls -la Clouck.app/ - ls -la Clouck.app/Contents/ - ls -la Clouck.app/Contents/MacOS/ - else - echo "ERROR: Clouck.app directory not found!" - exit 1 - fi + - name: Install Qt + uses: jurplel/install-qt-action@v4 + with: + version: "6.5.*" + cache: true - # Check if macdeployqt is available - echo "Checking macdeployqt availability:" - which macdeployqt || echo "macdeployqt not found in PATH" + - name: Configure and Build + run: | + cmake -B build -S . -DCMAKE_BUILD_TYPE=Release + cmake --build build --config Release - # Deploy Qt dependencies (ignore non-critical errors) - echo "Running macdeployqt..." - echo "Current directory before macdeployqt: $(pwd)" - echo "Listing current directory contents:" - ls -la - echo "Calling: macdeployqt Clouck.app -dmg" - macdeployqt build/Clouck.app -dmg || echo "macdeployqt failed, will use fallback" + - name: Create Windows Distribution + shell: pwsh + run: | + # Check what was actually built + Get-ChildItem -Path "build" -Recurse -Name - # Check what was created - echo "Files after macdeployqt:" - ls -la *.dmg 2>/dev/null || echo "No DMG files found" + New-Item -ItemType Directory -Path Clouck-windows -Force + Copy-Item "build/Release/Clouck.exe" -Destination "Clouck-windows/" -ErrorAction SilentlyContinue + Copy-Item "build/Release/*.dll" -Destination "Clouck-windows/" -ErrorAction SilentlyContinue + windeployqt --release Clouck-windows/Clouck.exe + Compress-Archive -Path Clouck-windows -DestinationPath Clouck-windows.zip - - name: Check DMG Creation - run: | - echo "Checking for DMG files after macdeployqt:" - ls -la *.dmg 2>/dev/null || echo "No DMG files found" + - name: Upload Windows Artifact + uses: actions/upload-artifact@v7 + with: + name: Clouck-windows + path: Clouck-windows.zip - # Check if DMG was created by macdeployqt - if [ -f "Clouck.dmg" ]; then - echo "Found Clouck.dmg, renaming to Clouck.dmg" - mv Clouck.dmg Clouck.dmg - echo "DMG created successfully" - else - echo "Clouck.dmg not found, checking for other DMG files:" - ls -la *.dmg 2>/dev/null || echo "Still no DMG files found" - echo "Creating DMG manually using hdiutil..." - # Fallback: create DMG manually if macdeployqt failed - hdiutil create -volname "Clouck" -srcfolder Clouck.app -ov -format UDZO Clouck.dmg - fi + build-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 - - name: Upload macOS Artifact - uses: actions/upload-artifact@v7 - with: - name: Clouck - path: Clouck.dmg + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y build-essential cmake libx11-dev libxfixes-dev - build-windows: - runs-on: windows-latest - steps: - - uses: actions/checkout@v6 + - name: Install Qt + uses: jurplel/install-qt-action@v4 + with: + version: "6.5.*" + cache: true - - name: Install Qt - uses: jurplel/install-qt-action@v4 - with: - version: "6.5.*" - cache: true + - name: Configure CMake + run: | + cmake -B build -S . -DCMAKE_BUILD_TYPE=Release - - name: Configure CMake - run: | - cmake -B build -S . -DCMAKE_BUILD_TYPE=Release + - name: Build + run: cmake --build build --config Release - - name: Build - run: cmake --build build --config Release + - name: Create Linux Distribution + run: | + # Check what was actually built + echo "Contents of build directory:" + ls -la build/ - - name: Create Windows Installer - run: | - # Copy executable and dependencies - mkdir Clouck-windows - cp build/Release/Clouck.exe Clouck-windows/ - cp build/Release/*.dll Clouck-windows/ 2>/dev/null || true + # Look for the executable + EXECUTABLE=$(find build/ -name "Clouck" -type f -executable | head -1) + if [ -n "$EXECUTABLE" ]; then + echo "Found executable: $EXECUTABLE" + mkdir -p Clouck-linux + cp "$EXECUTABLE" Clouck-linux/ + else + echo "ERROR: No Clouck executable found!" + exit 1 + fi - # Deploy Qt dependencies - windeployqt --release Clouck-windows/Clouck.exe + # Copy any Qt libraries + find build/ -name "*.so*" -exec cp {} Clouck-linux/ \; 2>/dev/null || true - # Create ZIP archive - Compress-Archive -Path Clouck-windows -DestinationPath Clouck-windows.zip + # Create tar.gz for distribution + tar -czf Clouck-linux.tar.gz Clouck-linux/ - - name: Upload Windows Artifact - uses: actions/upload-artifact@v7 - with: - name: Clouck-windows - path: Clouck-windows.zip + - name: Upload Linux Artifact + uses: actions/upload-artifact@v7 + with: + name: Clouck-linux + path: Clouck-linux.tar.gz - # build-linux: - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v6 - # - # - name: Install Dependencies - # run: | - # sudo apt-get update - # sudo apt-get install -y build-essential cmake qt6-base-dev qt6-tools-dev libx11-dev libxfixes-dev - # - # - name: Install Qt - # uses: jurplel/install-qt-action@v4 - # with: - # version: "6.5.*" - # cache: true - # - # - name: Configure CMake - # run: | - # cmake -B build -S . -DCMAKE_BUILD_TYPE=Release - # - # - name: Build - # run: cmake --build build --config Release - # - # - name: Create Linux AppImage - # run: | - # mkdir -p Clouck.AppDir/usr/bin - # mkdir -p Clouck.AppDir/usr/lib - # - # cp build/Clouck Clouck.AppDir/usr/bin/ - # - # cat > Clouck.AppDir/clouck.desktop << EOF - # [Desktop Entry] - # Name=Clouck - # Exec=Clouck - # Icon=clouck - # Type=Application - # Categories=Utility; - # EOF - # - # # Copy desktop file - # cp Clouck.AppDir/clouck.desktop Clouck.AppDir/ - # - # # Deploy Qt dependencies (simplified) - # ldd build/Clouck | grep -o '/lib[^ ]*' | xargs -I {} cp {} Clouck.AppDir/usr/lib/ 2>/dev/null || true - # - # # Create AppImage (simplified approach) - # cd Clouck.AppDir - # ln -s usr/bin/Clouck AppRun - # cd .. - # - # # Create tar.gz for distribution - # tar -czf Clouck-linux.tar.gz Clouck.AppDir/ - # - # - name: Upload Linux Artifact - # uses: actions/upload-artifact@v7 - # with: - # name: Clouck-linux - # path: Clouck-linux.tar.gz + generate-changelog: + needs: [ build-macos, build-windows, build-linux ] + runs-on: ubuntu-latest + if: always() + outputs: + changelog: ${{ steps.changelog.outputs.changelog }} + version: ${{ steps.version.outputs.version }} - create-release: - needs: [ build-macos, build-windows ] - runs-on: ubuntu-latest - if: startsWith(github.ref, 'refs/tags/v') || github.event_name == - 'workflow_dispatch' + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 - steps: - - name: Download All Artifacts - uses: actions/download-artifact@v8 - with: - path: artifacts + - name: Get Version + id: version + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT + else + echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + fi - - name: Get Version - id: version - run: | - if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then - echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT - else - echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - fi + - name: Generate Changelog + id: changelog + run: | + VERSION="${{ steps.version.outputs.version }}" + CHANGELOG=$(git log --pretty=format:"- %s" $(git describe --tags --abbrev=0 HEAD~1)..HEAD 2>/dev/null || echo "- Initial release") + echo "changelog<> $GITHUB_OUTPUT + echo "## What's New in $VERSION" >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + echo "$CHANGELOG" >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + echo "## Downloads" >> $GITHUB_OUTPUT + echo "- **macOS**: Clouck.dmg" >> $GITHUB_OUTPUT + echo "- **Windows**: Clouck-windows.zip" >> $GITHUB_OUTPUT + echo "- **Linux**: Clouck-linux.tar.gz" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT - - name: Create Release - uses: softprops/action-gh-release@v3 - with: - name: Clouck ${{ steps.version.outputs.VERSION }} - body: | - Cross-platform clock widget application + create-release: + needs: [ build-macos, build-windows, build-linux, generate-changelog ] + runs-on: ubuntu-latest + if: always() - ## Features - - Always-on-top functionality across all platforms - - Fullscreen mode compatibility - - Resizable interface - - Context menu with customization options - - Native platform integration + steps: + - name: Download All Artifacts + uses: actions/download-artifact@v8 + with: + path: artifacts - ## Downloads - - **macOS**: Clouck.dmg - - **Windows**: Clouck-windows.zip - - **Linux**: Clouck-linux.tar.gz + - name: Display Structure + run: ls -R artifacts - ## Installation - ### macOS - 1. Download Clouck.dmg - 2. Open the DMG file - 3. Drag Clouck.app to Applications folder + - name: Create Release + uses: softprops/action-gh-release@v3 + with: + name: Clouck ${{ needs.generate-changelog.outputs.version }} + body: | + Cross-platform clock widget application - ### Windows - 1. Download Clouck-windows.zip - 2. Extract the ZIP file - 3. Run Clouck.exe + ${{ needs.generate-changelog.outputs.changelog }} - ### Linux - 1. Download Clouck-linux.tar.gz - 2. Extract the tar.gz file - 3. Run the Clouck executable - files: | - artifacts/Clouck/Clouck.dmg - artifacts/Clouck-windows/Clouck-windows.zip - artifacts/Clouck-linux/Clouck-linux.tar.gz - draft: false - prerelease: false - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ## Installation + ### macOS + 1. Download Clouck.dmg + 2. Open the DMG file + 3. Drag Clouck.app to Applications folder + + ### Windows + 1. Download Clouck-windows.zip + 2. Extract the ZIP file + 3. Run Clouck.exe + + ### Linux + 1. Download Clouck-linux.tar.gz + 2. Extract the tar.gz file + 3. Run the Clouck executable + + ### Features + - Always-on-top functionality across all platforms + - Fullscreen mode compatibility + - Resizable interface + - Context menu with customization options + - Native platform integration + files: | + artifacts/Clouck-macos/Clouck.dmg + artifacts/Clouck-windows/Clouck-windows.zip + artifacts/Clouck-linux/Clouck-linux.tar.gz + draft: false + prerelease: false + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.vscode/settings.json b/.vscode/settings.json index d9118e6..8b86dd7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { "cmake.configureOnOpen": false, + "C_Cpp.errorSquiggles": "enabled", } diff --git a/README.md b/README.md index 8121ce9..8543302 100644 --- a/README.md +++ b/README.md @@ -16,22 +16,27 @@ When on macOS / Linux, the clock on the menu bar is too small to be noticeable, ## ✨ Features -- [ ] **Main Window** +- Cross Platform + - [x] MacOS + - [x] Windows + - [ ] Linux +- [x] **Main Window** - [x] Always On Top - [x] Frameless - [x] Drag and Move - - [x] Right Click Menu - [x] Resizable - - [ ] Show in Fullscreen Mode + - [x] Show in Fullscreen Mode - [x] **Style** + - [x] Right Click Menu - [x] Set Background Color + - [ ] Transparent Background - [x] Set Font Color - [x] Set FontSize -- [x] **Configuration File** (XML) +- [x] **Tweakable** (XML) - [x] Read Settings - [x] Write Settings - [x] Reset Settings -- [ ] **Time** +- [ ] **Time Zone** - [ ] Select Time Zone ## Quick Start @@ -104,8 +109,6 @@ Visit the [Releases](https://github.com/ivaquero/clouck/releases) page to downlo 2. GitHub Actions will automatically build and create a release with binaries for all platforms -See [`.github/workflows/`](.github/workflows/) for detailed workflow configuration. - ### Configuration The application now uses XML configuration files instead of QSettings. Configuration is stored in `config.xml` with the following options: diff --git a/window_helper_linux.cpp b/window_helper_linux.cpp index ed000ae..4cd1a2d 100644 --- a/window_helper_linux.cpp +++ b/window_helper_linux.cpp @@ -2,13 +2,20 @@ #ifdef Q_OS_LINUX -#include -#include -#include +#include +#include #include #include #include +// X11 type definitions for compatibility +typedef XserverRegion Region; + +// X11 shape constants +#define ShapeInput 2 +#define ShapeBounding 0 + +// Qt 6.x compatibility - use only public Qt interfaces void WindowHelperLinux::setupAlwaysOnTopForFullscreen(QWidget *widget) { if (!widget) @@ -30,29 +37,28 @@ void WindowHelperLinux::setupAlwaysOnTopForFullscreen(QWidget *widget) // Set window type to utility (similar to macOS panel) Atom windowType = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); Atom windowTypeUtility = XInternAtom(display, "_NET_WM_WINDOW_TYPE_UTILITY", False); - XChangeProperty(display, windowId, windowType, XA_ATOM, 32, - PropModeReplace, (unsigned char *)&windowTypeUtility, 1); + XChangeProperty(display, windowId, windowType, XA_ATOM, 32, PropModeReplace, + (unsigned char *)&windowTypeUtility, 1); - // Set window state to above - Atom windowState = XInternAtom(display, "_NET_WM_STATE", False); - Atom windowStateAbove = XInternAtom(display, "_NET_WM_STATE_ABOVE", False); - XChangeProperty(display, windowId, windowState, XA_ATOM, 32, - PropModeReplace, (unsigned char *)&windowStateAbove, 1); + // Set window state to above (always on top) + Atom wmState = XInternAtom(display, "_NET_WM_STATE", False); + Atom wmStateAbove = XInternAtom(display, "_NET_WM_STATE_ABOVE", False); + XChangeProperty(display, windowId, wmState, XA_ATOM, 32, PropModeReplace, + (unsigned char *)&wmStateAbove, 1); - // Set window state to skip taskbar - Atom windowStateSkipTaskbar = XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", False); - XChangeProperty(display, windowId, windowState, XA_ATOM, 32, - PropModeReplace, (unsigned char *)&windowStateSkipTaskbar, 1); + // Set window state to sticky (appears on all desktops) + Atom wmStateSticky = XInternAtom(display, "_NET_WM_STATE_STICKY", False); + XChangeProperty(display, windowId, wmState, XA_ATOM, 32, PropModeAppend, + (unsigned char *)&wmStateSticky, 1); - // Set window state to skip pager - Atom windowStateSkipPager = XInternAtom(display, "_NET_WM_STATE_SKIP_PAGER", False); - XChangeProperty(display, windowId, windowState, XA_ATOM, 32, - PropModeReplace, (unsigned char *)&windowStateSkipPager, 1); + // Set window state to skip taskbar and pager + Atom wmStateSkipTaskbar = XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", False); + Atom wmStateSkipPager = XInternAtom(display, "_NET_WM_STATE_SKIP_PAGER", False); + Atom states[] = {wmStateSkipTaskbar, wmStateSkipPager}; + XChangeProperty(display, windowId, wmState, XA_ATOM, 32, PropModeAppend, + (unsigned char *)states, 2); - // Set window state to sticky (appear on all workspaces) - Atom windowStateSticky = XInternAtom(display, "_NET_WM_STATE_STICKY", False); - XChangeProperty(display, windowId, windowState, XA_ATOM, 32, - PropModeReplace, (unsigned char *)&windowStateSticky, 1); + XFlush(display); } void WindowHelperLinux::setWindowAlwaysOnTop(QWidget *widget, bool alwaysOnTop) @@ -60,17 +66,35 @@ void WindowHelperLinux::setWindowAlwaysOnTop(QWidget *widget, bool alwaysOnTop) if (!widget) return; - Qt::WindowFlags flags = widget->windowFlags(); + QNativeInterface::QX11Application *x11App = qApp->nativeInterface(); + if (!x11App) + return; + + Display *display = x11App->display(); + if (!display) + return; + + WId windowId = widget->winId(); + if (!windowId) + return; + if (alwaysOnTop) { - flags |= Qt::WindowStaysOnTopHint; + // Set window state to above (always on top) + Atom wmState = XInternAtom(display, "_NET_WM_STATE", False); + Atom wmStateAbove = XInternAtom(display, "_NET_WM_STATE_ABOVE", False); + XChangeProperty(display, windowId, wmState, XA_ATOM, 32, PropModeReplace, + (unsigned char *)&wmStateAbove, 1); } else { - flags &= ~Qt::WindowStaysOnTopHint; + // Remove always on top state + Atom wmState = XInternAtom(display, "_NET_WM_STATE", False); + Atom wmStateAbove = XInternAtom(display, "_NET_WM_STATE_ABOVE", False); + XDeleteProperty(display, windowId, wmState); } - widget->setWindowFlags(flags); - widget->show(); // Required to apply new flags + + XFlush(display); } void WindowHelperLinux::setWindowClickThrough(QWidget *widget, bool clickThrough) @@ -78,7 +102,6 @@ void WindowHelperLinux::setWindowClickThrough(QWidget *widget, bool clickThrough if (!widget) return; - // Get X11 display from Qt platform interface QNativeInterface::QX11Application *x11App = qApp->nativeInterface(); if (!x11App) return; @@ -93,21 +116,30 @@ void WindowHelperLinux::setWindowClickThrough(QWidget *widget, bool clickThrough if (clickThrough) { - // Set window input shape to empty region - XRectangle rect = {0, 0, 0, 0}; - XFixesSetWindowShapeRegion(display, windowId, ShapeInput, 0, 0, None); - XFixesSetWindowShapeRegion(display, windowId, ShapeInput, 0, 0, - XFixesCreateRegion(display, &rect, 1)); + // Enable click-through using X11 shape extension + XRectangle rect = {0, 0, 1, 1}; + Region region = XFixesCreateRegion(display, &rect, 1); + XFixesSetWindowShapeRegion(display, windowId, ShapeInput, 0, 0, region); + XFixesSetWindowShapeRegion(display, windowId, ShapeBounding, 0, 0, region); + XFixesDestroyRegion(display, region); } else { - // Reset window input shape - XFixesSetWindowShapeRegion(display, windowId, ShapeInput, 0, 0, None); + // Disable click-through - restore normal input handling + XRectangle rect = {0, 0, 0, 0}; + Region region = XFixesCreateRegion(display, &rect, 1); + XFixesSetWindowShapeRegion(display, windowId, ShapeInput, 0, 0, region); + XFixesDestroyRegion(display, region); } + + XFlush(display); } void WindowHelperLinux::setupLinux(QWidget *widget) { + if (!widget) + return; + setupAlwaysOnTopForFullscreen(widget); }