# CI workflow cross-building wxMSW under Linux.
name: MSW cross-builds

on:
  push:
    branches:
      - master
    paths-ignore:
      - '.circleci/**'
      - '.github/ISSUE_TEMPLATE/**'
      - '.github/workflows/ci.yml'
      - '.github/workflows/ci_cmake.yml'
      - '.github/workflows/ci_mac.yml'
      - '.github/workflows/ci_msw.yml'
      - '.github/workflows/docs_update.yml'
      - 'build/cmake/**'
      - 'build/tools/appveyor*.bat'
      - 'distrib/**'
      - 'docs/**'
      - 'interface/**'
      - 'include/msvc/**'
      - 'include/wx/gtk/**'
      - 'include/wx/osx/**'
      - 'locale/**'
      - 'src/gtk/**'
      - 'src/osx/**'
      - '*.md'
      - '*.yml'
      - 'wxwidgets.props'
      - 'CMakeLists.txt'
  pull_request:
    branches:
      - master
    paths-ignore:
      - '.circleci/**'
      - '.github/ISSUE_TEMPLATE/**'
      - '.github/workflows/ci.yml'
      - '.github/workflows/ci_cmake.yml'
      - '.github/workflows/ci_mac.yml'
      - '.github/workflows/ci_msw.yml'
      - '.github/workflows/docs_update.yml'
      - 'build/cmake/**'
      - 'build/tools/appveyor*.bat'
      - 'distrib/**'
      - 'docs/**'
      - 'interface/**'
      - 'include/msvc/**'
      - 'include/wx/gtk/**'
      - 'include/wx/osx/**'
      - 'locale/**'
      - 'src/gtk/**'
      - 'src/osx/**'
      - '*.md'
      - '*.yml'
      - 'wxwidgets.props'
      - 'CMakeLists.txt'

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

permissions:
  contents: read

jobs:
  msw-cross-build:
    # Set up this job to run in a Debian Testing container because it has recent
    # versions of MinGW and Wine and is simpler to test with locally than the
    # bespoke container used by GitHub Actions by default.
    runs-on: ubuntu-latest
    container: debian:${{ matrix.debian_release }}-slim
    name: ${{ matrix.name }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: wxMSW 64 bits
            debian_release: testing
            configure_flags: --disable-compat32
          - name: wxMSW 32 bits
            # Testing doesn't have 32 bit support any more.
            debian_release: stable
            triplet: i686-w64-mingw32
          - name: wxMSW/Univ
            debian_release: testing
            configure_flags: --enable-universal --disable-compat32 --disable-debug --disable-optimise
            minimal: true
    env:
      wxCONFIGURE_FLAGS: ${{ matrix.configure_flags }}

      # Default to 64-bit build.
      HOST_TRIPLET: ${{ matrix.triplet || 'x86_64-w64-mingw32' }}

      # While our tests should run in any locale natively, it seems that Wine
      # requires the locale encoding to be UTF-8 for Unicode file names to work
      # correctly, so set the locale explicitly for it.
      LC_ALL: C.UTF-8

    defaults:
      run:
        shell: bash

    steps:
      - name: Install prerequisites
        run: |
          export DEBIAN_FRONTEND=noninteractive

          packages="bash git make wine x11-xserver-utils"

          case "${HOST_TRIPLET}" in
            x86_64-w64-mingw32)
              packages="$packages g++-mingw-w64-x86-64 wine wine64 xvfb"
              ;;

            i686-w64-mingw32)
              dpkg --add-architecture i386
              packages="$packages g++-mingw-w64-i686 wine32 libgl1:i386 xvfb:i386"
              ;;

            *)
              echo "Unknown host triplet \"${HOST_TRIPLET}\"."
              exit 1
              ;;
          esac

          apt-get -q -o=Dpkg::Use-Pty=0 update
          apt-get -q -o=Dpkg::Use-Pty=0 -y install $packages

          echo "wxTEST_RUNNER=wine" >> $GITHUB_ENV

      - name: Checkout
        uses: actions/checkout@v4
        with:
          submodules: 'recursive'

      - name: Install CCache
        uses: hendrikmuhs/ccache-action@v1.2.12
        with:
          key: ${{ matrix.name }}

      - name: System and environment setup
        run: |
          # Wine refuses to run if home is not owned by the current user (which
          # is actually root, but /github/home is actually owned by "runner").
          chown -R `id --user` $HOME

          # Add the directories containing MinGW and wx DLLs to Wine path.
          winepath="$(winepath --windows $(dirname $(${HOST_TRIPLET}-g++ -print-libgcc-file-name)))"
          winepath="${winepath};$(winepath --windows $(pwd)/lib)"
          echo "WINEPATH=${winepath}" >> $GITHUB_ENV

          cpu_count=`./build/tools/proc_count.sh`
          echo "wxMAKE_ARGS=-k -j$cpu_count" >> $GITHUB_ENV

          echo "wxMAKEFILE_ERROR_CXXFLAGS=-Werror -Wno-error=cpp" >> $GITHUB_ENV

          echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV

          echo "Compiler version:"
          ${HOST_TRIPLET}-g++ --version
          echo

      - name: Configure
        run: |
          ./configure --host=${HOST_TRIPLET} --disable-sys-libs --disable-debug_info $wxCONFIGURE_FLAGS || rc=$?

          if [ -n "$rc" ]; then
            echo '*** Configuring failed, contents of config.log follows: ***'
            echo '-----------------------------------------------------------'
            cat config.log
            echo '-----------------------------------------------------------'
            exit $rc
          fi

      - name: Build
        run: |
          make $wxMAKE_ARGS "CXXFLAGS=$wxMAKEFILE_ERROR_CXXFLAGS"

      - name: Install and test
        run: |
          make install
          make -C samples/minimal -f makefile.unx "CXXFLAGS=$wxMAKEFILE_ERROR_CXXFLAGS"


      - name: Build samples
        if: matrix.minimal != true
        run: |
          make $wxMAKE_ARGS "CXXFLAGS=$wxMAKEFILE_ERROR_CXXFLAGS" samples

      - name: Build tests
        if: matrix.minimal != true
        working-directory: tests
        run: |
          make $wxMAKE_ARGS failtest
          make $wxMAKE_ARGS "CXXFLAGS=$wxMAKEFILE_ERROR_CXXFLAGS"

      - name: Launch Xvfb
        if: matrix.minimal != true
        run: |
          echo 'Launching Xvfb...'
          mkdir /tmp/.X11-unix
          chmod 1777 /tmp/.X11-unix
          Xvfb :10 -screen 0 1600x1200x24 &
          num_tries=1
          while true; do
              if xset -d :10 -q >/dev/null 2>&1; then
                  echo 'Xvfb has become available.'
                  # Trying to use it immediately can still result in errors
                  # when creating the windows, somehow, so give it some time
                  # to settle.
                  sleep 3
                  break
              fi

              if [[ $num_tries -gt 10 ]]; then
                  echo 'Timed out waiting for Xvfb'
                  exit 1
              fi

              ((num_tries++))
              echo "Still waiting for Xvfb (attempt #$num_tries)"
              sleep 3
          done
          echo 'Xvfb is running on display :10'
          echo 'DISPLAY=:10' >> $GITHUB_ENV

      - name: Run non-GUI tests
        if: matrix.minimal != true
        working-directory: tests
        run: |
          # Some tests are currently failing under Wine while they pass under
          # native MSW, just skip running them until they can be dealt with.

          # As soon as we specify the tests to exclude explicitly, we also need
          # to exclude the tests that are not run by default, so start with this.
          excluded_tests=('~[.]')

          # There is 1 day difference in creation time under Wine somehow.
          excluded_tests+=('~wxFileName::SetTimes')

          # Closing the file fails for unknown reason under Wine.
          excluded_tests+=('~FileFunctions::Error')

          # Sporadic failures due to extra events.
          excluded_tests+=('~wxFileSystemWatcher::EventCreate')

          # The test fails (even with wxTEST_RUNNER-related changes) and hangs.
          excluded_tests+=('~ExecTestCase')

          # Wine WinHTTP implementations seems buggy, there are many errors.
          excluded_tests+=('~[webrequest]')

          $wxTEST_RUNNER ./test.exe "${excluded_tests[@]}"

      - name: Run GUI tests
        if: matrix.minimal != true
        working-directory: tests
        run: |
          # Same as for the non-GUI test above, except many more GUI tests fail
          # under Wine.
          excluded_gui_tests=('~[.]')

          excluded_gui_tests+=('~BitmapComboBoxTestCase') # TextChangeEvents
          excluded_gui_tests+=('~ClippingBoxTestCase*')
          excluded_gui_tests+=('~ComboBoxTestCase') # TextChangeEvents
          excluded_gui_tests+=('~DatePickerCtrlTestCase') # Range
          excluded_gui_tests+=('~wxEnhMetaFileDC::GetTextExtent')
          excluded_gui_tests+=('~ExecTestCase')
          excluded_gui_tests+=('~wxFont::GetSet')
          excluded_gui_tests+=('~GraphicsPathTestCaseGDIPlus')
          excluded_gui_tests+=('~ImageList*')
          excluded_gui_tests+=('~RadioButton::Focus')
          excluded_gui_tests+=('~SettingsTestCase') # GetFont fails
          excluded_gui_tests+=('~SliderTestCase')   # Thumb
          excluded_gui_tests+=('~TransformMatrixTestCase*')
          excluded_gui_tests+=('~TreeCtrlTestCase') # LabelEdit
          excluded_gui_tests+=('~TextCtrlTestCase') # many sub-tests
          excluded_gui_tests+=('~wxTextCtrl::InitialCanUndo')
          excluded_gui_tests+=('~[wxWebView]')
          excluded_gui_tests+=('~Window::PositioningBeyondShortLimit')
          excluded_gui_tests+=('~XRC::LoadURL')

          $wxTEST_RUNNER ./test_gui.exe "${excluded_gui_tests[@]}"
