diff options
180 files changed, 5884 insertions, 5776 deletions
diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 9ac24be468..0000000000 --- a/.editorconfig +++ /dev/null @@ -1,14 +0,0 @@ -root = true - -[*] -charset = utf-8 -indent_size = 4 -indent_style = space -insert_final_newline = true -trim_trailing_whitespace = true - -[Makefile] -indent_style = tab - -[*.{yml,yaml}] -indent_size = 2 diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 57faafc042..e3cc2f8527 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -21,13 +21,19 @@ jobs:      runs-on: ubuntu-latest      outputs:        release_run: ${{ steps.setvar.outputs.release_run }} +      branch:   ${{ steps.which-branch.outputs.branch }} +      relnotes: ${{ steps.which-branch.outputs.relnotes }}      env:        # Build with a tag like "Second_Life#abcdef0" to generate a release page        # (used for builds we are planning to deploy). +      # Even though inputs.release_run is specified with type boolean, which +      # correctly presents a checkbox, its *value* is a GH workflow string +      # 'true' or 'false'. If you simply test github.event.inputs.release_run, +      # it always evaluates as true because it's a non-empty string either way.        # When you want to use a string variable as a workflow YAML boolean, it's        # important to ensure it's the empty string when false. If you omit || '', -      # its value when false is "false", which is interpreted as true. -      RELEASE_RUN: ${{ (github.event.inputs.release_run || github.ref_type == 'tag' && startsWith(github.ref_name, 'Second_Life')) && 'Y' || '' }} +      # its value when false is "false", which (again) is interpreted as true. +      RELEASE_RUN: ${{ (github.event.inputs.release_run != 'false' || (github.ref_type == 'tag' && startsWith(github.ref_name, 'Second_Life'))) && 'Y' || '' }}      steps:        - name: Set Variable          id: setvar @@ -35,25 +41,33 @@ jobs:          run: |            echo "release_run=$RELEASE_RUN" >> "$GITHUB_OUTPUT" +      - name: Determine source branch +        id: which-branch +        uses: secondlife/viewer-build-util/which-branch@v2 +        with: +          token: ${{ github.token }} +    build:      needs: setvar      strategy:        matrix: -        runner: [windows-large, macos-12-xl] -        configuration: [Release] +        runner: [windows-large, macos-12-xl, linux-large] +        configuration: [Release, ReleaseOS]          Linden: [true]          include:            - runner: macos-12-xl              developer_dir: "/Applications/Xcode_14.0.1.app/Contents/Developer" +        exclude:            - runner: windows-large              configuration: ReleaseOS -            Linden: false +          - runner: macos-12-xl +            configuration: ReleaseOS +          - runner: linux-large +            configuration: Release      runs-on: ${{ matrix.runner }}      outputs:        viewer_channel: ${{ steps.build.outputs.viewer_channel }}        viewer_version: ${{ steps.build.outputs.viewer_version }} -      viewer_branch:  ${{ steps.which-branch.outputs.branch }} -      relnotes:       ${{ steps.which-branch.outputs.relnotes }}        imagename: ${{ steps.build.outputs.imagename }}      env:        AUTOBUILD_ADDRSIZE: 64 @@ -132,23 +146,27 @@ jobs:              ${{ runner.os }}-64-${{ matrix.configuration }}-              ${{ runner.os }}-64- +      - name: Install Linux dependencies +        if: runner.os == 'Linux' +        run: | +          sudo apt update +          sudo apt install -y \ +            libpulse-dev libunwind-dev \ +            libgl1-mesa-dev libglu1-mesa-dev libxinerama-dev \ +            libxcursor-dev libxfixes-dev libgstreamer1.0-dev \ +            libgstreamer-plugins-base1.0-dev ninja-build libxft-dev \ +            llvm mold libpipewire-0.3-dev +        - name: Install windows dependencies          if: env.BUILD && runner.os == 'Windows'          run: choco install nsis-unicode -      - name: Determine source branch -        id: which-branch -        if: env.BUILD -        uses: secondlife/viewer-build-util/which-branch@v2 -        with: -          token: ${{ github.token }} -        - name: Build          id: build          if: env.BUILD          shell: bash          env: -          AUTOBUILD_VCS_BRANCH: ${{ steps.which-branch.outputs.branch }} +          AUTOBUILD_VCS_BRANCH: ${{ needs.setvar.outputs.branch }}            RUNNER_OS: ${{ runner.os }}          run: |            # set up things the viewer's build.sh script expects @@ -247,6 +265,13 @@ jobs:            fi            export PYTHON_COMMAND_NATIVE="$(native_path "$PYTHON_COMMAND")" +          # Compile with clang, link with mold on linux. +          if [[ "$RUNNER_OS" == "Linux" ]]; then +            export CC=clang +            export CXX=clang++ +            export CMAKE_OPTIONS='-DLINK_WITH_MOLD=ON' +          fi +            ./build.sh            # Each artifact is downloaded as a distinct .zip file. Multiple jobs @@ -268,13 +293,14 @@ jobs:            echo "artifact=$RUNNER_OS$cfg_suffix" >> $GITHUB_OUTPUT        - name: Upload executable -        if: matrix.Linden && steps.build.outputs.viewer_app +        if: (matrix.Linden && steps.build.outputs.viewer_app) || runner.os == 'Linux'          uses: actions/upload-artifact@v4          with:            name: "${{ steps.build.outputs.artifact }}-app"            path: |              ${{ steps.build.outputs.viewer_app }} +        # The other upload of nontrivial size is the symbol file. Use a distinct        # artifact for that too.        - name: Upload symbol file @@ -403,7 +429,11 @@ jobs:    release:      needs: [setvar, build, sign-and-package-windows, sign-and-package-mac]      runs-on: ubuntu-latest -    if: needs.setvar.outputs.release_run +    # action-gh-release requires a tag (presumably for automatic generation of +    # release notes). Possible TODO: if we arrive here but do not have a +    # suitable tag for github.sha, create one? If we do that, of course remove +    # this == 'tag' condition. +    if: needs.setvar.outputs.release_run && github.ref_type == 'tag'      steps:        - uses: actions/download-artifact@v4          with: @@ -413,6 +443,10 @@ jobs:          with:            pattern: "*-metadata" +      - uses: actions/download-artifact@v4 +        with: +          pattern: "LinuxOS-app" +        - name: Rename metadata          run: |            cp Windows-metadata/autobuild-package.xml Windows-autobuild-package.xml @@ -433,7 +467,7 @@ jobs:              Build ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}              ${{ needs.build.outputs.viewer_channel }}              ${{ needs.build.outputs.viewer_version }} -            ${{ needs.build.outputs.relnotes }} +            ${{ needs.setvar.outputs.relnotes }}            prerelease: true            generate_release_notes: true            target_commitish: ${{ github.sha }} diff --git a/.gitignore b/.gitignore index 3b3666af84..c4accf37b5 100755 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,6 @@ debian/files  debian/secondlife-appearance-utility*  debian/secondlife-viewer*  indra/.distcc -indra/cmake/*  indra/out/*  indra/packages/* diff --git a/autobuild.xml b/autobuild.xml index 4c251c5d48..eed4e1ed1a 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -7,7 +7,7 @@      <string>autobuild</string>      <key>installables</key>      <map> -      <key>SDL</key> +      <key>SDL2</key>        <map>          <key>platforms</key>          <map> @@ -16,9 +16,11 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>7ea2df03bfc35c06acf23dd9e734adac</string> +              <string>ceb0392106c2f50d79dc724fd5a6d8ec82b92cdb</string> +              <key>hash_algorithm</key> +              <string>sha1</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1103/2554/SDL-1.2.15-linux64-501092.tar.bz2</string> +              <string>https://github.com/secondlife/3p-sdl2/releases/download/v2.28.0-r3/SDL2-2.28.0-linux64-8663899652.tar.zst</string>              </map>              <key>name</key>              <string>linux64</string> @@ -27,16 +29,46 @@          <key>license</key>          <string>lgpl</string>          <key>license_file</key> -        <string>LICENSES/SDL.txt</string> +        <string>LICENSES/SDL2.txt</string>          <key>copyright</key> -        <string>Copyright (C) 1997-2012 Sam Lantinga</string> +        <string>Copyright (C) 1997-2022 Sam Lantinga (slouken@libsdl.org)</string>          <key>version</key> -        <string>1.2.15</string> +        <string>2.28.0</string>          <key>name</key> -        <string>SDL</string> +        <string>SDL2</string>          <key>description</key>          <string>Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer.</string>        </map> +      <key>fltk</key> +      <map> +        <key>platforms</key> +        <map> +          <key>linux64</key> +          <map> +            <key>archive</key> +            <map> +              <key>hash</key> +              <string>691fef2ddd57d7b6c26e87fc82d9ace3f54e078c</string> +              <key>hash_algorithm</key> +              <string>sha1</string> +              <key>url</key> +              <string>https://github.com/secondlife/3p-fltk/releases/download/v1.3.9-r1/fltk-1.3.9.8556992788-linux64-8556992788.tar.zst</string> +            </map> +            <key>name</key> +            <string>linux</string> +          </map> +        </map> +        <key>license</key> +        <string>LGPL/fltk</string> +        <key>license_file</key> +        <string>LICENSES/fltk.txt</string> +        <key>copyright</key> +        <string>Copyright (C) fltk project</string> +        <key>version</key> +        <string>1.3.5</string> +        <key>name</key> +        <string>fltk</string> +      </map>        <key>apr_suite</key>        <map>          <key>platforms</key> @@ -60,9 +92,11 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>84a1a140f20b25d714949185e854d14b</string> +              <string>95137cd3f4d6ffa5bd7a00d7d91bd8fc272b7ca2</string> +              <key>hash_algorithm</key> +              <string>sha1</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/4811/15302/apr_suite-1.4.5.504800-linux64-504800.tar.bz2</string> +              <string>https://github.com/secondlife/3p-apr_suite/releases/download/v1.7.2-c5f3347/apr_suite-1.7.2-c5f3347-linux64-c5f3347.tar.zst</string>              </map>              <key>name</key>              <string>linux64</string> @@ -89,7 +123,7 @@          <key>copyright</key>          <string>Copyright © 2012 The Apache Software Foundation, Licensed under the Apache License, Version 2.0.</string>          <key>version</key> -        <string>1.7.2-e935465</string> +        <string>1.7.2-c5f3347</string>          <key>name</key>          <string>apr_suite</string>          <key>description</key> @@ -113,6 +147,20 @@              <key>name</key>              <string>darwin64</string>            </map> +          <key>linux64</key> +          <map> +            <key>archive</key> +            <map> +              <key>hash</key> +              <string>a3bfbdba7e1977e7e65266ec654990bb13994bd3</string> +              <key>hash_algorithm</key> +              <string>sha1</string> +              <key>url</key> +              <string>https://github.com/secondlife/3p-boost/releases/download/v1.81-3d0d7fc/boost-1.81-linux64-3d0d7fc.tar.zst</string> +            </map> +            <key>name</key> +            <string>linux64</string> +          </map>            <key>windows64</key>            <map>              <key>archive</key> @@ -205,6 +253,20 @@              <key>name</key>              <string>darwin64</string>            </map> +          <key>linux64</key> +          <map> +            <key>archive</key> +            <map> +              <key>hash</key> +              <string>cab0237b5194254c0c0ff6bf77bc6a2f946d4f57</string> +              <key>hash_algorithm</key> +              <string>sha1</string> +              <key>url</key> +              <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3-2f532e1/colladadom-2.3.2f532e1-linux64-2f532e1.tar.zst</string> +            </map> +            <key>name</key> +            <string>linux64</string> +          </map>            <key>windows64</key>            <map>              <key>archive</key> @@ -254,12 +316,14 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>77c53daf558f51aec6e9f4bd9e930a103630ee7d</string> +              <string>aea0bed0f953a9371b9091f09230b41597f891f7</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-d7afe27/cubemaptoequirectangular-1.1.0-linux64-d7afe27.tar.zst</string> +              <string>https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-cb8785a/cubemaptoequirectangular-1.1.0-linux64-cb8785a.tar.zst</string>              </map> +            <key>name</key> +            <string>linux64</string>            </map>            <key>windows64</key>            <map> @@ -310,9 +374,11 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>630a2ddf43bba6e5b6e171dc68921dcb</string> +              <string>7bb9bbadb44dd7490c3e6804395df01ab800bc18</string> +              <key>hash_algorithm</key> +              <string>sha1</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/8663/36142/curl-7.54.1.508652-linux64-508652.tar.bz2</string> +              <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-513145c/curl-7.54.1-513145c-linux64-513145c.tar.zst</string>              </map>              <key>name</key>              <string>linux64</string> @@ -339,7 +405,7 @@          <key>copyright</key>          <string>Copyright (c) 1996 - 2014, Daniel Stenberg, (daniel@haxx.se).</string>          <key>version</key> -        <string>7.54.1-5a4a82d</string> +        <string>7.54.1-513145c</string>          <key>name</key>          <string>curl</string>          <key>description</key> @@ -439,6 +505,20 @@              <key>name</key>              <string>windows64</string>            </map> +          <key>linux64</key> +          <map> +            <key>archive</key> +            <map> +              <key>hash</key> +              <string>08491c609b5f77835977fa459e386fddbad00064</string> +              <key>hash_algorithm</key> +              <string>sha1</string> +              <key>url</key> +              <string>https://github.com/secondlife/dullahan/releases/download/v1.14.0-r2/dullahan-1.14.0.202404051708_118.4.1_g3dd6078_chromium-118.0.5993.54-linux64-8573290624.tar.zst</string> +            </map> +            <key>name</key> +            <string>linux64</string> +          </map>          </map>          <key>license</key>          <string>MPL</string> @@ -471,6 +551,20 @@              <key>name</key>              <string>darwin64</string>            </map> +          <key>linux64</key> +          <map> +            <key>archive</key> +            <map> +              <key>hash</key> +              <string>5b957aa7f353b10ae17b7119e5b3668f48a35325</string> +              <key>hash_algorithm</key> +              <string>sha1</string> +              <key>url</key> +              <string>https://github.com/secondlife/3p-emoji-shortcodes/releases/download/v6.1.0.5413f58/emoji_shortcodes-6.1.0.5413f58-linux64-5413f58.tar.zst</string> +            </map> +            <key>name</key> +            <string>linux64</string> +          </map>            <key>windows64</key>            <map>              <key>archive</key> @@ -627,36 +721,6 @@          <key>description</key>          <string>FMOD Studio API</string>        </map> -      <key>fontconfig</key> -      <map> -        <key>platforms</key> -        <map> -          <key>linux64</key> -          <map> -            <key>archive</key> -            <map> -              <key>hash</key> -              <string>e2419d56960c160670051fbb055fb729</string> -              <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-fontconfig/rev/314281/arch/Linux/installer/fontconfig-2.11.0-linux64-314281.tar.bz2</string> -            </map> -            <key>name</key> -            <string>linux64</string> -          </map> -        </map> -        <key>license</key> -        <string>bsd</string> -        <key>license_file</key> -        <string>LICENSES/fontconfig.txt</string> -        <key>copyright</key> -        <string>Copyright (C) 2000,2001,2002,2003,2004,2006,2007 Keith Packard, 2005 Patrick Lam, 2009 Roozbeh Pournader, 2008,2009 Red Hat, Inc., 2008 Danilo Å egan, 2012 Google, Inc.</string> -        <key>version</key> -        <string>2.11.0</string> -        <key>name</key> -        <string>fontconfig</string> -        <key>description</key> -        <string>Fontconfig is a library for configuring and customizing font access.</string> -      </map>        <key>freetype</key>        <map>          <key>platforms</key> @@ -680,11 +744,11 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>4a999279562e8f3e4ba02d3e78a844ddf6fe18f1</string> +              <string>07a38133c008ce6f728d652d00a756bea3a70288</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://github.com/secondlife/3p-freetype/releases/download/v.2.12.1.557becd/freetype-2.12.1.557becd-linux64-557becd.tar.zst</string> +              <string>https://github.com/secondlife/3p-freetype/releases/download/v2.12.1-r1/freetype-2.12.1.8503093630-linux64-8503093630.tar.zst</string>              </map>              <key>name</key>              <string>linux64</string> @@ -795,52 +859,6 @@          <key>description</key>          <string>glh - is a platform-indepenedent C++ OpenGL helper library</string>        </map> -      <key>googlemock</key> -      <map> -        <key>platforms</key> -        <map> -          <key>darwin64</key> -          <map> -            <key>archive</key> -            <map> -              <key>hash</key> -              <string>dce3174b12136746f5f910e311e895c1b47bf8fb</string> -              <key>hash_algorithm</key> -              <string>sha1</string> -              <key>url</key> -              <string>https://github.com/secondlife/3p-googlemock/releases/download/v1.7.0.2b109d4/googlemock-1.7.0.2b109d4-darwin64-2b109d4.tar.zst</string> -            </map> -            <key>name</key> -            <string>darwin64</string> -          </map> -          <key>windows64</key> -          <map> -            <key>archive</key> -            <map> -              <key>hash</key> -              <string>265813f84b04c3b03f3d7d33e149b3d5e3cf31db</string> -              <key>hash_algorithm</key> -              <string>sha1</string> -              <key>url</key> -              <string>https://github.com/secondlife/3p-googlemock/releases/download/v1.7.0.2b109d4/googlemock-1.7.0.2b109d4-windows64-2b109d4.tar.zst</string> -            </map> -            <key>name</key> -            <string>windows64</string> -          </map> -        </map> -        <key>license</key> -        <string>BSD</string> -        <key>license_file</key> -        <string>LICENSES/gmock.txt</string> -        <key>copyright</key> -        <string>Copyright 2008, Google Inc.</string> -        <key>version</key> -        <string>1.7.0.2b109d4</string> -        <key>name</key> -        <string>googlemock</string> -        <key>description</key> -        <string>a library for writing and using C++ mock classes</string> -      </map>        <key>gstreamer</key>        <map>          <key>platforms</key> @@ -869,34 +887,6 @@          <key>name</key>          <string>gstreamer</string>        </map> -      <key>gtk-atk-pango-glib</key> -      <map> -        <key>platforms</key> -        <map> -          <key>linux64</key> -          <map> -            <key>archive</key> -            <map> -              <key>hash</key> -              <string>de7bba8fd2275a11b077b124413065d0</string> -              <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-gtk-atk-pango-glib/rev/314220/arch/Linux/installer/gtk_atk_pango_glib-0.1-linux64-314220.tar.bz2</string> -            </map> -            <key>name</key> -            <string>linux64</string> -          </map> -        </map> -        <key>license</key> -        <string>lgpl</string> -        <key>license_file</key> -        <string>LICENSES/gtk-atk-pango-glib.txt</string> -        <key>copyright</key> -        <string>Copyright (various, see sources)</string> -        <key>version</key> -        <string>0.1</string> -        <key>name</key> -        <string>gtk-atk-pango-glib</string> -      </map>        <key>havok-source</key>        <map>          <key>platforms</key> @@ -921,10 +911,14 @@            <map>              <key>archive</key>              <map> +              <key>creds</key> +              <string>github</string>                <key>hash</key> -              <string>00d0333936a67059a43a6ec8ac38d564</string> +              <string>ebfb82b6143874e7938b9d1e8a70d0a2e28aa818</string> +              <key>hash_algorithm</key> +              <string>sha1</string>                <key>url</key> -              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/748/1563/havok_source-2012.1-2-linux64-500739.tar.bz2</string> +              <string>https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/108912599</string>              </map>              <key>name</key>              <string>linux64</string> @@ -982,11 +976,11 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>35d6a617444fde9c8a5e998ef29dc43b95747637</string> +              <string>23daab838f4b8f92e5dc1a2f6c568cb7b0cb43b7</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-9165e47/jpegencoderbasic-1.0-linux64-9165e47.tar.zst</string> +              <string>https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-790015a/jpegencoderbasic-1.0-linux64-790015a.tar.zst</string>              </map>            </map>            <key>windows64</key> @@ -1098,11 +1092,11 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>97e268754808cb2fbd682c4d3beafd2c598e1ba7</string> +              <string>66dce1d0c2fc19dff13db279d973773fc7e2aa13</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://github.com/secondlife/3p-jsoncpp/releases/download/v0.5.0.bc46e62/jsoncpp-0.5.0.bc46e62-linux64-bc46e62.tar.zst</string> +              <string>https://github.com/secondlife/3p-jsoncpp/releases/download/v0.5.0-cc63e92/jsoncpp-0.5.0.cc63e92-linux64-cc63e92.tar.zst</string>              </map>              <key>name</key>              <string>linux64</string> @@ -1129,7 +1123,7 @@          <key>copyright</key>          <string>Copyright (c) 2007-2010 Baptiste Lepilleur</string>          <key>version</key> -        <string>0.5.0.bc46e62</string> +        <string>0.5.0.1db375e</string>          <key>name</key>          <string>jsoncpp</string>          <key>description</key> @@ -1346,9 +1340,11 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>13de93ea11544051b69f238eeb644fd3</string> +              <string>39d5779fd79e23da16a7b5bf608008999004c828</string> +              <key>hash_algorithm</key> +              <string>sha1</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/882/1946/libpng-1.6.8.500873-linux64-500873.tar.bz2</string> +              <string>https://github.com/secondlife/3p-libpng/releases/download/v1.16.38-d427738/libpng-1.6.38-8318603154-linux64-8318603154.tar.zst</string>              </map>              <key>name</key>              <string>linux64</string> @@ -1434,11 +1430,11 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>4cda464277bfa6756ce4663a91cd724f3f45b8d8</string> +              <string>fda5d399c21c3ad29a78f29599523ca4ecf76bd2</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.9.4.7476681/libxml2-2.9.4.7476681-linux64-7476681.tar.zst</string> +              <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.9.4-2db4418/libxml2-2.9.4.2db4418-linux64-2db4418.tar.zst</string>              </map>              <key>name</key>              <string>linux64</string> @@ -1465,7 +1461,7 @@          <key>copyright</key>          <string>Copyright (C) 1998-2012 Daniel Veillard.  All Rights Reserved.</string>          <key>version</key> -        <string>2.9.4.7476681</string> +        <string>2.9.4.2db4418</string>          <key>name</key>          <string>libxml2</string>          <key>description</key> @@ -1744,6 +1740,20 @@              <key>name</key>              <string>darwin64</string>            </map> +          <key>linux64</key> +          <map> +            <key>archive</key> +            <map> +              <key>hash</key> +              <string>6f4509dca9e32e3b4f9c4b13d875ce0e24340efc</string> +              <key>hash_algorithm</key> +              <string>sha1</string> +              <key>url</key> +              <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v160-4f905dd/meshoptimizer-160-linux64-4f905dd.tar.zst</string> +            </map> +            <key>name</key> +            <string>linux64</string> +          </map>            <key>windows64</key>            <map>              <key>archive</key> @@ -2072,9 +2082,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>              <key>archive</key>              <map>                <key>hash</key> -              <string>45ebd074053dc9cae8c5c74b52085d4b</string> +              <string>90052be851c4fcecc35d8424b4f31352de14ab2f</string> +              <key>hash_algorithm</key> +              <string>sha1</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/465/990/ogg_vorbis-1.2.2-1.3.2.500397-linux64-500397.tar.bz2</string> +              <string>https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.3-1.3.6-881f65e/ogg_vorbis-1.3.3-1.3.6.881f65e-linux64-881f65e.tar.zst</string>              </map>              <key>name</key>              <string>linux64</string> @@ -2101,7 +2113,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>          <key>copyright</key>          <string>Copyright (c) 2002, Xiph.org Foundation</string>          <key>version</key> -        <string>1.3.3-1.3.6.e4101b6</string> +        <string>1.3.3-1.3.6.881f65e</string>          <key>name</key>          <string>ogg_vorbis</string>          <key>description</key> @@ -2109,6 +2121,23 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>        </map>        <key>open-libndofdev</key>        <map> +        <key>platforms</key> +        <map> +          <key>linux64</key> +          <map> +            <key>archive</key> +            <map> +              <key>hash</key> +              <string>f215c7e1a10f04a2c18cbb837e0039521fd150b6</string> +              <key>hash_algorithm</key> +              <string>sha1</string> +              <key>url</key> +              <string>https://github.com/secondlife/3p-open-libndofdev/releases/download/v1.14-r2/open_libndofdev-0.14.8730039102-linux64-8730039102.tar.zst</string> +            </map> +            <key>name</key> +            <string>linux64</string> +          </map> +        </map>          <key>license</key>          <string>BSD</string>          <key>license_file</key> @@ -2116,7 +2145,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>          <key>copyright</key>          <string>Copyright (c) 2008, Jan Ciger (jan.ciger (at) gmail.com)</string>          <key>version</key> -        <string>0.3</string> +        <string>0.14.8730039102</string>          <key>name</key>          <string>open-libndofdev</string>          <key>description</key> @@ -2131,11 +2160,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>              <key>archive</key>              <map>                <key>hash</key> -              <string>e0fbc4874acc4167a6e2b6489fbb8258d98fd665</string> +              <string>561032415ea95ce38d8836da2bb56e46968f5a82</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.23.1-18e315c/openal-1.23.1-linux64-18e315c.tar.zst</string> +              <string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.23.1-r3/openal-1.23.1-linux64-8730177813.tar.zst</string>              </map>              <key>name</key>              <string>linux64</string> @@ -2325,9 +2354,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>              <key>archive</key>              <map>                <key>hash</key> -              <string>0f058ca2176e7d02d51e54c66a96f336</string> +              <string>3a722c508a9278a49317e3f749f3256768f1c50b</string> +              <key>hash_algorithm</key> +              <string>sha1</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/908/2010/pcre-8.35.500898-linux64-500898.tar.bz2</string> +              <string>https://github.com/secondlife/3p-pcre/releases/download/v8.35-3c0eb51/pcre-8.35.3c0eb51-linux64-3c0eb51.tar.zst</string>              </map>              <key>name</key>              <string>linux64</string> @@ -2354,7 +2385,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>          <key>copyright</key>          <string>Copyright (c) 1997-2014 University of Cambridge; Copyright(c) 2009-2014 Zoltan Herczeg; Copyright (c) 2007-2012, Google Inc.</string>          <key>version</key> -        <string>8.35.979fd86</string> +        <string>8.35.3c0eb51</string>          <key>name</key>          <string>pcre</string>          <key>description</key> @@ -2441,11 +2472,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>              <key>archive</key>              <map>                <key>hash</key> -              <string>9de1295b157c9913c28be81ff933c73493ecc132</string> +              <string>982c0fa427458082ea9e3cb9603904210732b64e</string>                <key>hash_algorithm</key>                <string>sha1</string>                <key>url</key> -              <string>https://github.com/secondlife/3p-three_js/releases/download/v0.132.2-b8f6746/threejs-0.132.2-linux64-b8f6746.tar.zst</string> +              <string>https://github.com/secondlife/3p-three_js/releases/download/v0.132.2-5da28d9/threejs-0.132.2-common-8454371083.tar.zst</string>              </map>            </map>            <key>windows64</key> @@ -2544,6 +2575,20 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>              <key>name</key>              <string>windows64</string>            </map> +          <key>linux64</key> +          <map> +            <key>archive</key> +            <map> +              <key>hash</key> +              <string>0cac6af362861d90cdd3dc4adfff95f54e619f4a</string> +              <key>hash_algorithm</key> +              <string>sha1</string> +              <key>url</key> +              <string>https://github.com/secondlife/3p-tracy/releases/download/v0.8.1%2Br1/tracy-v0.8.1.38bf5f3-linux64-38bf5f3.tar.zst</string> +            </map> +            <key>name</key> +            <string>linux64</string> +          </map>          </map>          <key>license</key>          <string>bsd</string> @@ -2684,6 +2729,20 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>              <key>name</key>              <string>windows64</string>            </map> +          <key>common</key> +          <map> +            <key>archive</key> +            <map> +              <key>hash</key> +              <string>c25de57e57856a826b2c146ac951ae0b53250666</string> +              <key>hash_algorithm</key> +              <string>sha1</string> +              <key>url</key> +              <string>https://github.com/secondlife/3p-viewer-fonts/releases/download/v1.0.0-r1/viewer_fonts-1.0.0.8512067490-common-8512067490.tar.zst</string> +            </map> +            <key>name</key> +            <string>common</string> +          </map>          </map>          <key>license</key>          <string>Various open source</string> @@ -2692,7 +2751,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>          <key>copyright</key>          <string>Copyright 2016-2022 Brad Erickson CC-BY-4.0/MIT, Copyright 2016-2022 Twitter, Inc. CC-BY-4.0, Copyright 2013 Joe Loughry and Terence Eden MIT</string>          <key>version</key> -        <string>1.579464</string> +        <string>1.0.0.8512067490</string>          <key>name</key>          <string>viewer-fonts</string>          <key>description</key> @@ -3291,6 +3350,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>                    <string>-G</string>                    <string>Ninja</string>                    <string>-DLL_TESTS=Off</string> +                  <string>-DUSE_OPENAL=On</string>                  </array>                </map>                <key>build</key> @@ -45,7 +45,7 @@ build_dir_Darwin()  build_dir_Linux()  { -  echo build-linux-i686 +  echo build-linux-x86_64  }  build_dir_CYGWIN() @@ -154,6 +154,22 @@ pre_build()                    "-DSIGNING_IDENTITY:STRING=Developer ID Application: Linden Research, Inc.")      fi +    if [[ "$arch" == "Linux" ]] +    then +      # RELEASE_CRASH_REPORTING is tuned on unconditionaly, this is fine but not for Linux as of now (due to missing breakpad/crashpad support) +      RELEASE_CRASH_REPORTING=OFF + +      # Builds turn on HAVOK even when config is ReleaseOS. +      # This needs AUTOBUILD_GITHUB_TOKEN to be set in the environment. But this is not set for PRs apparently. +      # Still this seemlingy works on Windows and Mac, why not on the Linux runner? Mystery to be solved elsewhere. + + +      if [[ "$variant" == "ReleaseOS" ]] +      then +          HAVOK=OFF +      fi +    fi +      if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ]      then          case "$arch" in @@ -176,9 +192,17 @@ pre_build()      # honor autobuild_configure_parameters same as sling-buildscripts      eval_autobuild_configure_parameters=$(eval $(echo echo $autobuild_configure_parameters)) +    # We build the viewer on Linux, but we haven't committed to support the +    # Linux viewer. As of 2024-05-30, Linux build-time test infrastructure is +    # not in place, so don't even bother running tests on Linux. +    if [[ "$RUNNER_OS" == "Linux" ]] +    then LL_TESTS=OFF +    else LL_TESTS=ON +    fi +      "$autobuild" configure --quiet -c $variant \       ${eval_autobuild_configure_parameters:---} \ -     -DLL_TESTS:BOOL=ON \ +     -DLL_TESTS:BOOL=$LL_TESTS \       -DPACKAGE:BOOL=ON \       -DHAVOK:BOOL="$HAVOK" \       -DRELEASE_CRASH_REPORTING:BOOL="$RELEASE_CRASH_REPORTING" \ @@ -187,6 +211,7 @@ pre_build()       -DVIEWER_CHANNEL:STRING="${viewer_channel}" \       -DGRID:STRING="\"$viewer_grid\"" \       -DTEMPLATE_VERIFIER_OPTIONS:STRING="$template_verifier_options" $template_verifier_master_url \ +     $CMAKE_OPTIONS \       "${SIGNING[@]}" \      || fatal "$variant configuration failed" @@ -199,14 +224,14 @@ package_llphysicsextensions_tpv()    tpv_status=0    # nat 2016-12-21: without HAVOK, can't build PhysicsExtensions_TPV.    if [ "$variant" = "Release" -a "${HAVOK:-}" != "OFF" ] -  then  +  then        tpvconfig="$build_dir/packages/llphysicsextensions/autobuild-tpv.xml"        test -r "$tpvconfig" || fatal "No llphysicsextensions_tpv autobuild configuration found"        # SL-19942: autobuild ignores -c switch if AUTOBUILD_CONFIGURATION set        unset AUTOBUILD_CONFIGURATION        "$autobuild" build --quiet --config-file "$(native_path "$tpvconfig")" -c Tpv \            || fatal "failed to build llphysicsextensions_tpv" -       +        # capture the package file name for use in upload later...        PKGTMP=`mktemp -t pgktpv.XXXXXX`        cleanup="$cleanup ; rm $PKGTMP* 2>/dev/null" @@ -239,7 +264,7 @@ build()      || fatal "failed building $variant"      echo true >"$build_dir"/build_ok      end_section "autobuild $variant" -     +      begin_section "extensions $variant"      # Run build extensions      if [ -d ${build_dir}/packages/build-extensions ] @@ -312,7 +337,7 @@ begin_section "select viewer channel"  # Look for a branch-specific viewer_channel setting  #    changeset_branch is set in the sling-buildscripts  viewer_build_branch=$(echo -n "${changeset_branch:-$(repo_branch ${BUILDSCRIPTS_SRC:-$(pwd)})}" | tr -Cs 'A-Za-z0-9_' '_' | sed -E 's/^_+//; s/_+$//') -if [ -n "$viewer_build_branch" ]  +if [ -n "$viewer_build_branch" ]  then      branch_viewer_channel_var="${viewer_build_branch}_viewer_channel"      if [ -n "${!branch_viewer_channel_var}" ] @@ -434,7 +459,7 @@ do        record_event "configure for $variant failed: build skipped"    fi -  if ! $succeeded  +  if ! $succeeded    then        record_event "remaining variants skipped due to $variant failure"        break @@ -499,7 +524,7 @@ then          fi        done        end_section "Upload Debian Repository" -       +      else        record_event "debian build not enabled"      fi diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 4471380c6b..68348cc9d2 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -15,6 +15,7 @@  include_guard()  include(Variables) +include(Linker)  # We go to some trouble to set LL_BUILD to the set of relevant compiler flags.  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} $ENV{LL_BUILD}") @@ -110,51 +111,90 @@ if (WINDOWS)    add_compile_definitions(_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)  endif (WINDOWS) -  if (LINUX) -  set(CMAKE_SKIP_RPATH TRUE) - -   # EXTERNAL_TOS -   # force this platform to accept TOS via external browser +  set( CMAKE_BUILD_WITH_INSTALL_RPATH TRUE ) +  set( CMAKE_INSTALL_RPATH $ORIGIN $ORIGIN/../lib ) +  set(CMAKE_EXE_LINKER_FLAGS "-Wl,--exclude-libs,ALL") + +  find_program(CCACHE_EXE ccache) +  if(CCACHE_EXE AND NOT DISABLE_CCACHE) +    set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_EXE} ) +    set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_EXE} ) +  endif() -   # LL_IGNORE_SIGCHLD -   # don't catch SIGCHLD in our base application class for the viewer - some of -   # our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The -   # viewer doesn't need to catch SIGCHLD anyway. +  # LL_IGNORE_SIGCHLD +  # don't catch SIGCHLD in our base application class for the viewer - some of +  # our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The +  # viewer doesn't need to catch SIGCHLD anyway.    add_compile_definitions(            _REENTRANT -          _FORTIFY_SOURCE=2 -          EXTERNAL_TOS            APPID=secondlife            LL_IGNORE_SIGCHLD    ) + +  if( ENABLE_ASAN ) +      add_compile_options(-U_FORTIFY_SOURCE +        -fsanitize=address +        --param asan-stack=0 +      ) +      add_link_options(-fsanitize=address) +  else() +   add_compile_definitions( _FORTIFY_SOURCE=2 ) +  endif() +    add_compile_options( -          -fexceptions -          -fno-math-errno -          -fno-strict-aliasing -          -fsigned-char -          -msse2 -          -mfpmath=sse -          -pthread -          -Wno-parentheses -          -Wno-deprecated -          -fvisibility=hidden +      -fexceptions +      -fno-math-errno +      -fno-strict-aliasing +      -fsigned-char +      -msse2 +      -mfpmath=sse +      -pthread +      -fvisibility=hidden +  ) + +  set(GCC_CLANG_COMPATIBLE_WARNINGS +      -Wno-parentheses +      -Wno-deprecated +      -Wno-c++20-compat +      -Wno-pessimizing-move +  ) + +  set(CLANG_WARNINGS +      ${GCC_CLANG_COMPATIBLE_WARNINGS} +      # Put clang specific warning configuration here +  ) + +  set(GCC_WARNINGS +      ${GCC_CLANG_COMPATIBLE_WARNINGS} +      -Wno-dangling-pointer    ) -  if (ADDRESS_SIZE EQUAL 32) -    add_compile_options(-march=pentium4) -  endif (ADDRESS_SIZE EQUAL 32) +  add_link_options( +          -Wl,--no-keep-memory +          -Wl,--build-id +          -Wl,--no-undefined +  ) +  if (NOT GCC_DISABLE_FATAL_WARNINGS) +    add_compile_options( -Werror ) +  endif (NOT GCC_DISABLE_FATAL_WARNINGS)    # this stops us requiring a really recent glibc at runtime    add_compile_options(-fno-stack-protector) -  # linking can be very memory-hungry, especially the final viewer link -  set(CMAKE_CXX_LINK_FLAGS "-Wl,--no-keep-memory") -  set(CMAKE_CXX_FLAGS_DEBUG "-fno-inline ${CMAKE_CXX_FLAGS_DEBUG}") +  if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") +    # ND: clang is a bit more picky than GCC, the latter seems to auto include -lstdc++ and -lm. The former not so and thus fails to link +    add_link_options( +            -lstdc++ +            -lm +    ) +    add_compile_options(${CLANG_WARNINGS}) +  else() +    add_compile_options(${GCC_WARNINGS}) +  endif()  endif (LINUX) -  if (DARWIN)    # Warnings should be fatal -- thanks, Nicky Perian, for spotting reversed default    set(CLANG_DISABLE_FATAL_WARNINGS OFF) @@ -176,20 +216,11 @@ if (DARWIN)    # required for clang-15/xcode-15 since our boost package still uses deprecated std::unary_function/binary_function    # see https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#C++-Standard-Library    add_compile_definitions(_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION) -endif (DARWIN) -if (LINUX OR DARWIN)    set(GCC_WARNINGS -Wall -Wno-sign-compare -Wno-trigraphs) -  if (NOT GCC_DISABLE_FATAL_WARNINGS) -    list(APPEND GCC_WARNINGS -Werror) -  endif (NOT GCC_DISABLE_FATAL_WARNINGS) -    list(APPEND GCC_WARNINGS -Wno-reorder -Wno-non-virtual-dtor )    add_compile_options(${GCC_WARNINGS})    add_compile_options(-m${ADDRESS_SIZE}) -endif (LINUX OR DARWIN) - - - +endif () diff --git a/indra/cmake/Audio.cmake b/indra/cmake/Audio.cmake index 38547bb017..5efaff07c7 100644 --- a/indra/cmake/Audio.cmake +++ b/indra/cmake/Audio.cmake @@ -11,6 +11,6 @@ target_include_directories( ll::vorbis SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/inc  if (WINDOWS)    target_link_libraries(ll::vorbis INTERFACE ogg_static vorbis_static vorbisenc_static vorbisfile_static )  else (WINDOWS) -  target_link_libraries(ll::vorbis INTERFACE ogg vorbis vorbisenc vorbisfile ) +  target_link_libraries(ll::vorbis INTERFACE vorbisfile vorbis ogg vorbisenc )  endif (WINDOWS) diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index 601a23a86d..293d8931cb 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -27,14 +27,14 @@ if (WINDOWS)            libboost_thread-mt${addrsfx})  elseif (LINUX)    target_link_libraries( ll::boost INTERFACE -          boost_context-mt${addrsfx}            boost_fiber-mt${addrsfx} +          boost_context-mt${addrsfx}            boost_filesystem-mt${addrsfx}            boost_program_options-mt${addrsfx}            boost_regex-mt${addrsfx} -          boost_signals-mt${addrsfx} +          boost_thread-mt${addrsfx}            boost_system-mt${addrsfx} -          boost_thread-mt${addrsfx}) +  )  elseif (DARWIN)    target_link_libraries( ll::boost INTERFACE            boost_context-mt${addrsfx} diff --git a/indra/cmake/CEFPlugin.cmake b/indra/cmake/CEFPlugin.cmake index 9b77becf29..555d2aebbf 100644 --- a/indra/cmake/CEFPlugin.cmake +++ b/indra/cmake/CEFPlugin.cmake @@ -33,4 +33,9 @@ elseif (DARWIN)         )  elseif (LINUX) +    target_link_libraries( ll::cef INTERFACE +            libdullahan.a +            cef +            cef_dll_wrapper.a +    )  endif (WINDOWS) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index df05032172..793ee1365f 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -15,7 +15,6 @@ set(cmake_SOURCE_FILES          CEFPlugin.cmake          CEFPlugin.cmake          CMakeCopyIfDifferent.cmake -        ConfigurePkgConfig.cmake          CURL.cmake          Copy3rdPartyLibs.cmake          DBusGlib.cmake @@ -27,7 +26,6 @@ set(cmake_SOURCE_FILES          FreeType.cmake          GLEXT.cmake          GLH.cmake -        GoogleMock.cmake          Havok.cmake          Hunspell.cmake          JsonCpp.cmake diff --git a/indra/cmake/ConfigurePkgConfig.cmake b/indra/cmake/ConfigurePkgConfig.cmake deleted file mode 100644 index 9e798d663b..0000000000 --- a/indra/cmake/ConfigurePkgConfig.cmake +++ /dev/null @@ -1,74 +0,0 @@ -# -*- cmake -*- - -SET(DEBUG_PKG_CONFIG "YES") - -# Don't change this if manually set by user. -IF("$ENV{PKG_CONFIG_LIBDIR}" STREQUAL "") - -  # Guess at architecture-specific system library paths. -  if (ADDRESS_SIZE EQUAL 32) -    SET(PKG_CONFIG_NO_MULTI_GUESS /usr/lib32 /usr/lib) -    SET(PKG_CONFIG_NO_MULTI_LOCAL_GUESS /usr/local/lib32 /usr/local/lib) -    SET(PKG_CONFIG_MULTI_GUESS /usr/lib/i386-linux-gnu) -    SET(PKG_CONFIG_MULTI_LOCAL_GUESS /usr/local/lib/i386-linux-gnu) -  else (ADDRESS_SIZE EQUAL 32) -    SET(PKG_CONFIG_NO_MULTI_GUESS /usr/lib64 /usr/lib) -    SET(PKG_CONFIG_NO_MULTI_LOCAL_GUESS /usr/local/lib64 /usr/local/lib) -    SET(PKG_CONFIG_MULTI_GUESS /usr/local/lib/x86_64-linux-gnu) -    SET(PKG_CONFIG_MULTI_LOCAL_GUESS /usr/local/lib/x86_64-linux-gnu) -  endif (ADDRESS_SIZE EQUAL 32) - -  # Use DPKG architecture, if available. -  IF (${DPKG_ARCH}) -    SET(PKG_CONFIG_MULTI_GUESS /usr/lib/${DPKG_ARCH}) -    SET(PKG_CONFIG_MULTI_LOCAL_GUESS /usrlocal/lib/${DPKG_ARCH}) -  ENDIF (${DPKG_ARCH}) - -  # Explicitly include anything listed in PKG_CONFIG_PATH -  string(REPLACE ":" ";" PKG_CONFIG_PATH_LIST "$ENV{PKG_CONFIG_PATH}") -  FOREACH(PKG_CONFIG_DIR ${PKG_CONFIG_PATH_LIST}) -    SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:${PKG_CONFIG_DIR}/pkgconfig") -  ENDFOREACH(PKG_CONFIG_DIR) - -  # Look for valid pkgconfig directories. -  FIND_PATH(PKG_CONFIG_ENV pkgconfig ENV LD_LIBRARY_PATH) -  FIND_PATH(PKG_CONFIG_MULTI pkgconfig HINT ${PKG_CONFIG_MULTI_GUESS}) -  FIND_PATH(PKG_CONFIG_MULTI_LOCAL pkgconfig HINT ${PKG_CONFIG_MULTI_LOCAL_GUESS}) -  FIND_PATH(PKG_CONFIG_NO_MULTI pkgconfig HINT ${PKG_CONFIG_NO_MULTI_GUESS}) -  FIND_PATH(PKG_CONFIG_NO_MULTI_LOCAL pkgconfig HINT ${PKG_CONFIG_NO_MULTI_LOCAL_GUESS}) - -  # Add anything we found to our list. -  IF(NOT PKG_CONFIG_ENV STREQUAL PKG_CONFIG_ENV-NOTFOUND) -    SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:${PKG_CONFIG_ENV}/pkgconfig") -  ENDIF(NOT PKG_CONFIG_ENV STREQUAL PKG_CONFIG_ENV-NOTFOUND) - -  IF(NOT PKG_CONFIG_MULTI STREQUAL PKG_CONFIG_MULTI-NOTFOUND) -    SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:${PKG_CONFIG_MULTI}/pkgconfig") -  ENDIF(NOT PKG_CONFIG_MULTI STREQUAL PKG_CONFIG_MULTI-NOTFOUND) - -  IF(NOT PKG_CONFIG_MULTI_LOCAL STREQUAL PKG_CONFIG_MULTI_LOCAL-NOTFOUND) -    SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:${PKG_CONFIG_MULTI_LOCAL}/pkgconfig") -  ENDIF(NOT PKG_CONFIG_MULTI_LOCAL STREQUAL PKG_CONFIG_MULTI_LOCAL-NOTFOUND) - -  IF(NOT PKG_CONFIG_NO_MULTI STREQUAL PKG_CONFIG_NO_MULTI-NOTFOUND) -    SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:${PKG_CONFIG_NO_MULTI}/pkgconfig") -  ENDIF(NOT PKG_CONFIG_NO_MULTI STREQUAL PKG_CONFIG_NO_MULTI-NOTFOUND) - -  IF(NOT PKG_CONFIG_NO_MULTI_LOCAL STREQUAL PKG_CONFIG_NO_MULTI_LOCAL-NOTFOUND) -    SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:${PKG_CONFIG_NO_MULTI_LOCAL}/pkgconfig") -  ENDIF(NOT PKG_CONFIG_NO_MULTI_LOCAL STREQUAL PKG_CONFIG_NO_MULTI_LOCAL-NOTFOUND) - -  # Also add some non-architecture specific package locations. -  SET(VALID_PKG_LIBDIRS "${VALID_PKG_LIBDIRS}:/usr/share/pkgconfig:/usr/local/share/pkgconfig") - -  # Remove first unwanted ':' -  string(SUBSTRING ${VALID_PKG_LIBDIRS} 1 -1 VALID_PKG_LIBDIRS) - -  # Set PKG_CONFIG_LIBDIR environment. -  SET(ENV{PKG_CONFIG_LIBDIR} ${VALID_PKG_LIBDIRS}) -ENDIF("$ENV{PKG_CONFIG_LIBDIR}" STREQUAL "") - -IF(DEBUG_PKG_CONFIG) -  MESSAGE(STATUS "Using PKG_CONFIG_LIBDIR=$ENV{PKG_CONFIG_LIBDIR}") -ENDIF(DEBUG_PKG_CONFIG) - diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 27b20ee3b1..a1a67512c4 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -215,17 +215,7 @@ elseif(LINUX)           list( APPEND release_files                   libapr-1.so.0                   libaprutil-1.so.0 -                 libatk-1.0.so -                 libfreetype.so.6.6.2 -                 libfreetype.so.6                   libhunspell-1.3.so.0.0.0 -                 libopenjp2.so -                 libuuid.so.16 -                 libuuid.so.16.0.22 -                 libfontconfig.so.1.8.0 -                 libfontconfig.so.1 -                 libgmodule-2.0.so -                 libgobject-2.0.so                   )       endif() diff --git a/indra/cmake/FindPipeWire.cmake b/indra/cmake/FindPipeWire.cmake new file mode 100644 index 0000000000..868acf5ec1 --- /dev/null +++ b/indra/cmake/FindPipeWire.cmake @@ -0,0 +1,100 @@ +# cmake-format: off +# .rst: FindPipeWire +# ------- +# +# Try to find PipeWire on a Unix system. +# +# This will define the following variables: +# +# ``PIPEWIRE_FOUND`` True if (the requested version of) PipeWire is available +# ``PIPEWIRE_VERSION`` The version of PipeWire ``PIPEWIRE_LIBRARIES`` This can +# be passed to target_link_libraries() instead of the ``PipeWire::PipeWire`` +# target ``PIPEWIRE_INCLUDE_DIRS`` This should be passed to +# target_include_directories() if the target is not used for linking +# ``PIPEWIRE_COMPILE_FLAGS`` This should be passed to target_compile_options() +# if the target is not used for linking +# +# If ``PIPEWIRE_FOUND`` is TRUE, it will also define the following imported +# target: +# +# ``PipeWire::PipeWire`` The PipeWire library +# +# In general we recommend using the imported target, as it is easier to use. +# Bear in mind, however, that if the target is in the link interface of an +# exported library, it must be made available by the package config file. + +# ============================================================================= +# Copyright 2014 Alex Merry <alex.merry@kde.org> Copyright 2014 Martin Gräßlin +# <mgraesslin@kde.org> Copyright 2018-2020 Jan Grulich <jgrulich@redhat.com> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the copyright notice, this list +#    of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright notice, this +#    list of conditions and the following disclaimer in the documentation and/or +#    other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +#    derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# ============================================================================= +# cmake-format: on + +# Use pkg-config to get the directories and then use these values in the FIND_PATH() and FIND_LIBRARY() calls +find_package(PkgConfig QUIET) + +pkg_search_module(PKG_PIPEWIRE QUIET libpipewire-0.3) +pkg_search_module(PKG_SPA QUIET libspa-0.2) + +set(PIPEWIRE_COMPILE_FLAGS "${PKG_PIPEWIRE_CFLAGS}" "${PKG_SPA_CFLAGS}") +set(PIPEWIRE_VERSION "${PKG_PIPEWIRE_VERSION}") + +find_path( +  PIPEWIRE_INCLUDE_DIRS +  NAMES pipewire/pipewire.h +  HINTS ${PKG_PIPEWIRE_INCLUDE_DIRS} ${PKG_PIPEWIRE_INCLUDE_DIRS}/pipewire-0.3) + +find_path( +  SPA_INCLUDE_DIRS +  NAMES spa/param/props.h +  HINTS ${PKG_SPA_INCLUDE_DIRS} ${PKG_SPA_INCLUDE_DIRS}/spa-0.2) + +find_library( +  PIPEWIRE_LIBRARIES +  NAMES pipewire-0.3 +  HINTS ${PKG_PIPEWIRE_LIBRARY_DIRS}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( +  PipeWire +  FOUND_VAR PIPEWIRE_FOUND +  REQUIRED_VARS PIPEWIRE_LIBRARIES PIPEWIRE_INCLUDE_DIRS SPA_INCLUDE_DIRS +  VERSION_VAR PIPEWIRE_VERSION) + +if(PIPEWIRE_FOUND AND NOT TARGET PipeWire::PipeWire) +  add_library(PipeWire::PipeWire UNKNOWN IMPORTED) +  set_target_properties( +    PipeWire::PipeWire +    PROPERTIES IMPORTED_LOCATION "${PIPEWIRE_LIBRARIES}" +               INTERFACE_COMPILE_OPTIONS "${PIPEWIRE_COMPILE_FLAGS}" +               INTERFACE_INCLUDE_DIRECTORIES "${PIPEWIRE_INCLUDE_DIRS};${SPA_INCLUDE_DIRS}") +endif() + +mark_as_advanced(PIPEWIRE_LIBRARIES PIPEWIRE_INCLUDE_DIRS) + +include(FeatureSummary) +set_package_properties( +  PipeWire PROPERTIES +  URL "https://www.pipewire.org" +  DESCRIPTION "PipeWire - multimedia processing") diff --git a/indra/cmake/FreeType.cmake b/indra/cmake/FreeType.cmake index 77140af641..e7e28a44d0 100644 --- a/indra/cmake/FreeType.cmake +++ b/indra/cmake/FreeType.cmake @@ -4,8 +4,11 @@ include(Prebuilt)  include_guard()  add_library( ll::freetype INTERFACE IMPORTED ) -use_system_binary(freetype) -use_prebuilt_binary(freetype) -target_include_directories( ll::freetype SYSTEM INTERFACE  ${LIBS_PREBUILT_DIR}/include/freetype2/) -target_link_libraries( ll::freetype INTERFACE freetype ) - +    use_system_binary(freetype) +    use_prebuilt_binary(freetype) +    target_include_directories( ll::freetype SYSTEM INTERFACE  ${LIBS_PREBUILT_DIR}/include/freetype2/) +if( LINUX ) +    target_link_libraries( ll::freetype INTERFACE ${LIBS_PREBUILT_DIR}/lib/release/libfreetype.a ${LIBS_PREBUILT_DIR}/lib/release/libpng16.a) +else() +    target_link_libraries( ll::freetype INTERFACE freetype ) +endif() diff --git a/indra/cmake/GLIB.cmake b/indra/cmake/GLIB.cmake new file mode 100644 index 0000000000..f52cbb7f87 --- /dev/null +++ b/indra/cmake/GLIB.cmake @@ -0,0 +1,22 @@ +include_guard() + +include(Prebuilt) + +add_library( ll::glib INTERFACE IMPORTED ) +add_library( ll::glib_headers INTERFACE IMPORTED ) +add_library( ll::gio INTERFACE IMPORTED ) + +if( LINUX ) +  find_package(PkgConfig REQUIRED) +  pkg_search_module(GLIB REQUIRED glib-2.0) +  pkg_search_module(GIO REQUIRED gio-2.0) + +  target_include_directories( ll::glib SYSTEM INTERFACE ${GLIB_INCLUDE_DIRS}  ) +  target_link_libraries( ll::glib INTERFACE ${GLIB_LDFLAGS} ) +  target_compile_definitions( ll::glib INTERFACE -DLL_GLIB=1) + +  target_include_directories( ll::glib_headers SYSTEM INTERFACE ${GLIB_INCLUDE_DIRS}  ) +  target_compile_definitions( ll::glib_headers INTERFACE -DLL_GLIB=1) + +  target_link_libraries( ll::gio INTERFACE ${GIO_LDFLAGS} ) +endif() diff --git a/indra/cmake/GStreamer10Plugin.cmake b/indra/cmake/GStreamer10Plugin.cmake new file mode 100644 index 0000000000..da2e33d04d --- /dev/null +++ b/indra/cmake/GStreamer10Plugin.cmake @@ -0,0 +1,27 @@ +# -*- cmake -*- + +include_guard() + +include(Prebuilt) +include(GLIB) + +add_library( ll::gstreamer10 INTERFACE IMPORTED ) + +if (LINUX) +  include(FindPkgConfig) + +  pkg_check_modules(GSTREAMER10 REQUIRED gstreamer-1.0) +  pkg_check_modules(GSTREAMER10_PLUGINS_BASE REQUIRED gstreamer-plugins-base-1.0) + +  target_include_directories( ll::gstreamer10 SYSTEM INTERFACE ${GSTREAMER10_INCLUDE_DIRS}) +  target_link_libraries( ll::gstreamer10 INTERFACE  ll::glib_headers) + +endif () + +if (GSTREAMER10_FOUND AND GSTREAMER10_PLUGINS_BASE_FOUND) +  set(GSTREAMER10 ON CACHE BOOL "Build with GStreamer-1.0 streaming media support.") +endif (GSTREAMER10_FOUND AND GSTREAMER10_PLUGINS_BASE_FOUND) + +if (GSTREAMER10) +  add_definitions(-DLL_GSTREAMER10_ENABLED=1) +endif (GSTREAMER10) diff --git a/indra/cmake/GoogleMock.cmake b/indra/cmake/GoogleMock.cmake deleted file mode 100644 index c3d195c37b..0000000000 --- a/indra/cmake/GoogleMock.cmake +++ /dev/null @@ -1,32 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) -include(Linking) - -include_guard() - -add_library( ll::googlemock INTERFACE IMPORTED ) -if(USE_CONAN) -  target_link_libraries( ll::googlemock INTERFACE  CONAN_PKG::gtest ) - -  #Not very nice, but for the moment we need this for tut.hpp -  target_include_directories( ll::googlemock SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include ) -  return() -endif() - -use_prebuilt_binary(googlemock) - -target_include_directories( ll::googlemock SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include ) - -if (LINUX) -    # VWR-24366: gmock is underlinked, it needs gtest. -    target_link_libraries( ll::googlemock INTERFACE gmock gtest) -elseif(WINDOWS) -    target_link_libraries( ll::googlemock INTERFACE gmock) -    target_include_directories( ll::googlemock SYSTEM INTERFACE -            ${LIBS_PREBUILT_DIR}/include -            ${LIBS_PREBUILT_DIR}/include/gmock) -elseif(DARWIN) -    target_link_libraries( ll::googlemock INTERFACE gmock gtest) -endif(LINUX) - - diff --git a/indra/cmake/JsonCpp.cmake b/indra/cmake/JsonCpp.cmake index 17f8e47a97..a9b992ab20 100644 --- a/indra/cmake/JsonCpp.cmake +++ b/indra/cmake/JsonCpp.cmake @@ -12,6 +12,6 @@ if (WINDOWS)  elseif (DARWIN)    target_link_libraries( ll::jsoncpp INTERFACE libjson_darwin_libmt.a )  elseif (LINUX) -  target_link_libraries( ll::jsoncpp INTERFACE libjson_linux-gcc-4.1.3_libmt.a ) +  target_link_libraries( ll::jsoncpp INTERFACE libjson_linux-gcc-11_libmt.a )  endif (WINDOWS)  target_include_directories( ll::jsoncpp SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include) diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index 2172b56da2..5d96a4398f 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -1,7 +1,13 @@  # -*- cmake -*- + +include_guard() + +if( NOT LL_TESTS ) +  return() +endif() +  include(00-Common)  include(LLTestCommand) -include(GoogleMock)  include(bugsplat)  include(Tut) @@ -19,10 +25,6 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)    #    # More info and examples at: https://wiki.secondlife.com/wiki/How_to_add_unit_tests_to_indra_code -  # This here looks weird, but is needed. It will inject GoogleMock into projects that forgot to include `this` (LLAddBuildTest.cmake) -  # But through some other means have access to this macro -  include(GoogleMock) -    if(LL_TEST_VERBOSE)      message("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} sources: ${sources}")    endif() @@ -41,7 +43,6 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)    set(alltest_LIBRARIES            llcommon -          ll::googlemock            )    if(NOT "${project}" STREQUAL "llmath")      # add llmath as a dep unless the tested module *is* llmath! @@ -204,7 +205,6 @@ FUNCTION(LL_ADD_INTEGRATION_TEST    set(libraries            ${library_dependencies} -          ll::googlemock            )    # Add test executable build target diff --git a/indra/cmake/LLWindow.cmake b/indra/cmake/LLWindow.cmake index 2e1b601b79..23f4115aeb 100644 --- a/indra/cmake/LLWindow.cmake +++ b/indra/cmake/LLWindow.cmake @@ -10,13 +10,11 @@ add_library( ll::SDL INTERFACE IMPORTED )  if (LINUX)    #Must come first as use_system_binary can exit this file early -  target_compile_definitions( ll::SDL INTERFACE LL_SDL=1) +  target_compile_definitions( ll::SDL INTERFACE LL_SDL_VERSION=2 LL_SDL) -  use_system_binary(SDL) -  use_prebuilt_binary(SDL) +  #find_package(SDL2 REQUIRED) +  #target_link_libraries( ll::SDL INTERFACE SDL2::SDL2 SDL2::SDL2main X11) -  target_include_directories( ll::SDL SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include) -  target_link_libraries( ll::SDL INTERFACE SDL directfb fusion direct X11) +  use_prebuilt_binary(SDL2) +  target_link_libraries( ll::SDL INTERFACE SDL2 X11)  endif (LINUX) - - diff --git a/indra/cmake/Linker.cmake b/indra/cmake/Linker.cmake new file mode 100644 index 0000000000..8016842192 --- /dev/null +++ b/indra/cmake/Linker.cmake @@ -0,0 +1,11 @@ +include_guard(GLOBAL) + +if( LINK_WITH_MOLD ) +  find_program(MOLD_BIN mold) +  if(MOLD_BIN) +    message(STATUS "Mold linker found: ${MOLD_BIN}. Enabling mold as active linker.") +    add_link_options("-fuse-ld=${MOLD_BIN}") +  else() +    message(STATUS "Mold linker not found. Using default linker.") +  endif() +endif() diff --git a/indra/cmake/Meshoptimizer.cmake b/indra/cmake/Meshoptimizer.cmake index fd144d2b97..6983a5895a 100644 --- a/indra/cmake/Meshoptimizer.cmake +++ b/indra/cmake/Meshoptimizer.cmake @@ -12,7 +12,7 @@ use_prebuilt_binary(meshoptimizer)  if (WINDOWS)    target_link_libraries( ll::meshoptimizer INTERFACE meshoptimizer.lib)  elseif (LINUX) -  target_link_libraries( ll::meshoptimizer INTERFACE meshoptimizer.o) +  target_link_libraries( ll::meshoptimizer INTERFACE libmeshoptimizer.a)  elseif (DARWIN)    target_link_libraries( ll::meshoptimizer INTERFACE libmeshoptimizer.a)  endif (WINDOWS) diff --git a/indra/cmake/NDOF.cmake b/indra/cmake/NDOF.cmake index b88fbccf2a..db9c8b1780 100644 --- a/indra/cmake/NDOF.cmake +++ b/indra/cmake/NDOF.cmake @@ -19,6 +19,6 @@ if (NDOF)      target_link_libraries( ll::ndof INTERFACE ndofdev)    endif (WINDOWS)    target_compile_definitions( ll::ndof INTERFACE LIB_NDOF=1) +else() +  add_compile_options(-ULIB_NDOF)  endif (NDOF) - - diff --git a/indra/cmake/UI.cmake b/indra/cmake/UI.cmake index 8f135676d6..0df62808e7 100644 --- a/indra/cmake/UI.cmake +++ b/indra/cmake/UI.cmake @@ -1,35 +1,33 @@  # -*- cmake -*-  include(Prebuilt)  include(FreeType) +include(GLIB)  add_library( ll::uilibraries INTERFACE IMPORTED )  if (LINUX) -  target_compile_definitions(ll::uilibraries INTERFACE LL_GTK=1 LL_X11=1 ) +  use_prebuilt_binary(fltk) +  target_compile_definitions(ll::uilibraries INTERFACE LL_FLTK=1 LL_X11=1 )    if( USE_CONAN ) -    target_link_libraries( ll::uilibraries INTERFACE CONAN_PKG::gtk )      return()    endif() -  use_prebuilt_binary(gtk-atk-pango-glib)    target_link_libraries( ll::uilibraries INTERFACE -          atk-1.0 -          gdk-x11-2.0 -          gdk_pixbuf-2.0 -          Xinerama -          glib-2.0 -          gmodule-2.0 -          gobject-2.0 -          gthread-2.0 -          gtk-x11-2.0 -          pango-1.0 -          pangoft2-1.0 -          pangox-1.0 -          pangoxft-1.0 +          fltk +          Xrender +          Xcursor +          Xfixes +          Xext +          Xft            Xinerama +          ll::fontconfig            ll::freetype -          ) +          ll::SDL +          ll::glib +          ll::gio +  ) +  endif (LINUX)  if( WINDOWS )    target_link_libraries( ll::uilibraries INTERFACE @@ -51,4 +49,3 @@ endif()  target_include_directories( ll::uilibraries SYSTEM INTERFACE          ${LIBS_PREBUILT_DIR}/include          ) - diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 59725ecc65..c037d657eb 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -117,7 +117,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")      set(FIND_LIBRARY_USE_LIB64_PATHS ON)    endif (ADDRESS_SIZE EQUAL 32) -  execute_process(COMMAND dpkg-architecture -a${DEB_ARCHITECTURE} -qDEB_HOST_MULTIARCH +  execute_process(COMMAND dpkg-architecture -a${DEB_ARCHITECTURE} -qDEB_HOST_MULTIARCH         RESULT_VARIABLE DPKG_RESULT        OUTPUT_VARIABLE DPKG_ARCH        OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) @@ -127,8 +127,6 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")      set(CMAKE_SYSTEM_LIBRARY_PATH /usr/lib/${DPKG_ARCH} /usr/local/lib/${DPKG_ARCH} ${CMAKE_SYSTEM_LIBRARY_PATH})    endif (DPKG_RESULT EQUAL 0) -  include(ConfigurePkgConfig) -    if (INSTALL_PROPRIETARY)      # Only turn on headless if we can find osmesa libraries.      include(FindPkgConfig) diff --git a/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake index cae68fbc11..2cb11994fc 100644 --- a/indra/cmake/ViewerMiscLibs.cmake +++ b/indra/cmake/ViewerMiscLibs.cmake @@ -2,14 +2,10 @@  include(Prebuilt)  if (LINUX) -  #use_prebuilt_binary(libuuid)    add_library( ll::fontconfig INTERFACE IMPORTED ) -  if( NOT USE_CONAN ) -    use_prebuilt_binary(fontconfig) -  else() -    target_link_libraries( ll::fontconfig INTERFACE CONAN_PKG::fontconfig ) -  endif() +  find_package(Fontconfig REQUIRED) +  target_link_libraries( ll::fontconfig INTERFACE  Fontconfig::Fontconfig )  endif (LINUX)  if( NOT USE_CONAN ) diff --git a/indra/linux_crash_logger/llcrashloggerlinux.cpp b/indra/linux_crash_logger/llcrashloggerlinux.cpp index 9b40de741e..7992f59b36 100644 --- a/indra/linux_crash_logger/llcrashloggerlinux.cpp +++ b/indra/linux_crash_logger/llcrashloggerlinux.cpp @@ -38,9 +38,6 @@  #include "lldir.h"  #include "llsdserialize.h" -#if LL_GTK -# include "gtk/gtk.h" -#endif // LL_GTK  #define MAX_LOADSTRING 100 @@ -54,52 +51,9 @@ static const char dialog_text[] =  static const char dialog_title[] =  "Second Life Crash Logger"; -#if LL_GTK -static void response_callback (GtkDialog *dialog, -                   gint       arg1, -                   gpointer   user_data) -{ -    gint *response = (gint*)user_data; -    *response = arg1; -    gtk_widget_destroy(GTK_WIDGET(dialog)); -    gtk_main_quit(); -} -#endif // LL_GTK -  static BOOL do_ask_dialog(void)  { -#if LL_GTK -    gtk_disable_setlocale(); -    if (!gtk_init_check(NULL, NULL)) { -        LL_INFOS() << "Could not initialize GTK for 'ask to send crash report' dialog; not sending report." << LL_ENDL; -        return FALSE; -    } - -    GtkWidget *win = NULL; -    GtkDialogFlags flags = GTK_DIALOG_MODAL; -    GtkMessageType messagetype = GTK_MESSAGE_QUESTION; -    GtkButtonsType buttons = GTK_BUTTONS_YES_NO; -    gint response = GTK_RESPONSE_NONE; - -    win = gtk_message_dialog_new(NULL, -                     flags, messagetype, buttons, -                     "%s", dialog_text); -    gtk_window_set_type_hint(GTK_WINDOW(win), -                 GDK_WINDOW_TYPE_HINT_DIALOG); -    gtk_window_set_title(GTK_WINDOW(win), dialog_title); -    g_signal_connect (win, -              "response", -              G_CALLBACK (response_callback), -              &response); -    gtk_widget_show_all (win); -    gtk_main(); - -    return (GTK_RESPONSE_OK == response || -        GTK_RESPONSE_YES == response || -        GTK_RESPONSE_APPLY == response); -#else -    return FALSE; -#endif // LL_GTK +    // Ask to send crash report. Yes/No dialog.  }  LLCrashLoggerLinux::LLCrashLoggerLinux(void) diff --git a/indra/llappearance/llpolymesh.cpp b/indra/llappearance/llpolymesh.cpp index 75d5d23260..819e95ef52 100644 --- a/indra/llappearance/llpolymesh.cpp +++ b/indra/llappearance/llpolymesh.cpp @@ -981,7 +981,7 @@ void LLPolyMesh::initializeForMorph()      LLVector4a::memcpyNonAliased16((F32*) mScaledNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);      LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);      LLVector4a::memcpyNonAliased16((F32*) mScaledBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices); -    LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices + mSharedData->mNumVertices%2)); +    memcpy((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices)); // allocated in LLPolyMeshSharedData::allocateVertexData      for (U32 i = 0; i < mSharedData->mNumVertices; ++i)      { diff --git a/indra/llcommon/always_return.h b/indra/llcommon/always_return.h index a206471da5..b99eb49096 100644 --- a/indra/llcommon/always_return.h +++ b/indra/llcommon/always_return.h @@ -79,6 +79,22 @@ namespace LL          DESIRED mDefault;      }; +    // specialize for AlwaysReturn<void> +    template <> +    struct AlwaysReturn<void> +    { +    public: +        AlwaysReturn() {} + +        // callable returns a type not convertible to DESIRED, return default +        template <typename CALLABLE, typename... ARGS> +        void operator()(CALLABLE&& callable, ARGS&&... args) +        { +            // discard whatever callable(args) returns +            std::forward<CALLABLE>(callable)(std::forward<ARGS>(args)...); +        } +    }; +      /**       * always_return<T>(some_function, some_args...) calls       * some_function(some_args...). It is guaranteed to return a value of type diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 8612f9353f..6285ac86ad 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -123,7 +123,7 @@ LLCoros::LLCoros():      // Previously we used      // boost::context::guarded_stack_allocator::default_stacksize();      // empirically this is insufficient. -    mStackSize(1024*1024), +    mStackSize(512*1024),      // mCurrent does NOT own the current CoroData instance -- it simply      // points to it. So initialize it with a no-op deleter.      mCurrent{ [](CoroData*){} } @@ -155,7 +155,7 @@ void LLCoros::cleanupSingleton()          // don't use llcoro::suspend() because that module depends          // on this one          // This will yield current(main) thread and will let active -        // corutines run once +        // coroutines run once          boost::this_fiber::yield();      }      printActiveCoroutines("after pumping"); @@ -286,55 +286,6 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl      return name;  } -namespace -{ - -#if LL_WINDOWS - -static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific - -U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) -{ -    if (code == STATUS_MSC_EXCEPTION) -    { -        // C++ exception, go on -        return EXCEPTION_CONTINUE_SEARCH; -    } -    else -    { -        // handle it -        return EXCEPTION_EXECUTE_HANDLER; -    } -} - -void sehandle(const LLCoros::callable_t& callable) -{ -    __try -    { -        callable(); -    } -    __except (exception_filter(GetExceptionCode(), GetExceptionInformation())) -    { -        // convert to C++ styled exception -        // Note: it might be better to use _se_set_translator -        // if you want exception to inherit full callstack -        char integer_string[512]; -        sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); -        throw std::exception(integer_string); -    } -} - -#else  // ! LL_WINDOWS - -inline void sehandle(const LLCoros::callable_t& callable) -{ -    callable(); -} - -#endif // ! LL_WINDOWS - -} // anonymous namespace -  // Top-level wrapper around caller's coroutine callable.  // Normally we like to pass strings and such by const reference -- but in this  // case, we WANT to copy both the name and the callable to our local stack! @@ -348,7 +299,7 @@ void LLCoros::toplevel(std::string name, callable_t callable)      // run the code the caller actually wants in the coroutine      try      { -        sehandle(callable); +        LL::seh::catcher(callable);      }      catch (const Stop& exc)      { diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 6176ce0d1d..7353a36c5f 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -95,6 +95,11 @@ const int LL_ERR_NOERR = 0;  #define LL_STATIC_ASSERT(func, msg) static_assert(func, msg)  #define LL_BAD_TEMPLATE_INSTANTIATION(type, msg) static_assert(false, msg)  #else +#if LL_LINUX +// We need access to raise and SIGSEGV +#include <signal.h> +#endif +  #define LL_STATIC_ASSERT(func, msg) BOOST_STATIC_ASSERT(func)  #define LL_BAD_TEMPLATE_INSTANTIATION(type, msg) BOOST_STATIC_ASSERT(sizeof(type) != 0 && false);  #endif @@ -408,10 +413,16 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;  #define LL_NEWLINE '\n'  // Use this only in LL_ERRS or in a place that LL_ERRS may not be used + +#ifndef LL_LINUX  #define LLERROR_CRASH                                   \  {                                                       \      crashdriver([](int* ptr){ *ptr = 0; exit(*ptr); }); \  } +#else +// For Linux we just call raise and be done with it. No fighting the compiler to create a crashing code snippet. +#define LLERROR_CRASH raise(SIGSEGV ); +#endif  #define LL_ENDL                                         \              LLError::End();                             \ diff --git a/indra/llcommon/llexception.cpp b/indra/llcommon/llexception.cpp index c0154a569f..107fdc2b2d 100644 --- a/indra/llcommon/llexception.cpp +++ b/indra/llcommon/llexception.cpp @@ -15,7 +15,12 @@  #include "llexception.h"  // STL headers  // std headers +#include <iomanip> +#include <sstream>  #include <typeinfo> +#if LL_WINDOWS +#include <excpt.h> +#endif // LL_WINDOWS  // external library headers  #include <boost/exception/diagnostic_information.hpp>  #include <boost/exception/error_info.hpp> @@ -29,7 +34,6 @@  // On Windows, header-only implementation causes macro collisions -- use  // prebuilt library  #define BOOST_STACKTRACE_LINK -#include <excpt.h>  #endif // LL_WINDOWS  #include <boost/stacktrace.hpp> @@ -94,25 +98,47 @@ void annotate_exception_(boost::exception& exc)  // For windows SEH exception handling we sometimes need a filter that will  // separate C++ exceptions from C SEH exceptions -static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific +static constexpr U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific +static constexpr U32 STATUS_STACK_FULL    = 0xC00000FD; -U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) +void LL::seh::fill_stacktrace(std::string& stacktrace, U32 code)  { -    const auto stack = to_string(boost::stacktrace::stacktrace()); -    LL_WARNS() << "SEH Exception handled (that probably shouldn't be): Code " << code -        << "\n Stack trace: \n" -        << stack << LL_ENDL; +    // Sadly, despite its diagnostic importance, trying to capture a +    // stacktrace when the stack is already blown only terminates us faster. +    if (code == STATUS_STACK_FULL) +    { +        stacktrace = "(stack overflow, no traceback)"; +    } +    else +    { +        stacktrace = to_string(boost::stacktrace::stacktrace()); +    } +} +U32 LL::seh::common_filter(U32 code, struct _EXCEPTION_POINTERS*) +{      if (code == STATUS_MSC_EXCEPTION)      { -        // C++ exception, go on +        // C++ exception, don't stop at this handler          return EXCEPTION_CONTINUE_SEARCH;      }      else      { -        // handle it +        // This is a non-C++ exception, e.g. hardware check. +        // Pass control into the handler block.          return EXCEPTION_EXECUTE_HANDLER;      }  } +void LL::seh::rethrow(U32 code, const std::string& stacktrace) +{ +    std::ostringstream out; +    out << "Windows exception 0x" << std::hex << code; +    if (! stacktrace.empty()) +    { +        out << '\n' << stacktrace; +    } +    LLTHROW(Windows_SEH_exception(out.str())); +} +  #endif //LL_WINDOWS diff --git a/indra/llcommon/llexception.h b/indra/llcommon/llexception.h index 68e609444e..f58a553eb3 100644 --- a/indra/llcommon/llexception.h +++ b/indra/llcommon/llexception.h @@ -12,6 +12,7 @@  #if ! defined(LL_LLEXCEPTION_H)  #define LL_LLEXCEPTION_H +#include "always_return.h"  #include <stdexcept>  #include <boost/exception/exception.hpp>  #include <boost/throw_exception.hpp> @@ -102,14 +103,115 @@ void crash_on_unhandled_exception_(const char*, int, const char*, const std::str       log_unhandled_exception_(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, CONTEXT)  void log_unhandled_exception_(const char*, int, const char*, const std::string&); +/***************************************************************************** +*   Structured Exception Handling +*****************************************************************************/ +// this is used in platform-generic code -- define outside #if LL_WINDOWS +struct Windows_SEH_exception: public LLException +{ +    Windows_SEH_exception(const std::string& what): LLException(what) {} +}; + +namespace LL +{ +namespace seh +{ + +#if LL_WINDOWS //------------------------------------------------------------- + +void fill_stacktrace(std::string& stacktrace, U32 code); + +// wrapper around caller's U32 filter(U32 code, struct _EXCEPTION_POINTERS*) +// filter function: capture a stacktrace, if possible, before forwarding the +// call to the caller's filter() function +template <typename FILTER> +U32 filter_(std::string& stacktrace, FILTER&& filter, +            U32 code, struct _EXCEPTION_POINTERS* exptrs) +{ +    // By the time the handler gets control, the stack has been unwound, +    // so report the stack trace now at filter() time. +    fill_stacktrace(stacktrace, code); +    return std::forward<FILTER>(filter)(code, exptrs); +} + +template <typename TRYCODE, typename FILTER, typename HANDLER> +auto catcher_inner(std::string& stacktrace, +                   TRYCODE&& trycode, FILTER&& filter, HANDLER&& handler) +{ +    __try +    { +        return std::forward<TRYCODE>(trycode)(); +    } +    __except (filter_(stacktrace, +                      std::forward<FILTER>(filter), +                      GetExceptionCode(), GetExceptionInformation())) +    { +        return always_return<decltype(trycode())>( +            std::forward<HANDLER>(handler), GetExceptionCode(), stacktrace); +    } +} + +// triadic variant specifies try(), filter(U32, struct _EXCEPTION_POINTERS*), +// handler(U32, const std::string& stacktrace) +// stacktrace may or may not be available +template <typename TRYCODE, typename FILTER, typename HANDLER> +auto catcher(TRYCODE&& trycode, FILTER&& filter, HANDLER&& handler) +{ +    // Construct and destroy this stacktrace string in the outer function +    // because we can't do either in the function with __try/__except. +    std::string stacktrace; +    return catcher_inner(stacktrace, +                         std::forward<TRYCODE>(trycode), +                         std::forward<FILTER>(filter), +                         std::forward<HANDLER>(handler)); +} -#if LL_WINDOWS +// common_filter() handles the typical case in which we want our handler +// clause to handle only Structured Exceptions rather than explicitly-thrown +// C++ exceptions +U32 common_filter(U32 code, struct _EXCEPTION_POINTERS*); + +// dyadic variant specifies try(), handler(U32, stacktrace), assumes common_filter() +template <typename TRYCODE, typename HANDLER> +auto catcher(TRYCODE&& trycode, HANDLER&& handler) +{ +    return catcher(std::forward<TRYCODE>(trycode), +                   common_filter, +                   std::forward<HANDLER>(handler)); +} + +// monadic variant specifies try(), assumes default filter and handler +template <typename TRYCODE> +auto catcher(TRYCODE&& trycode) +{ +    return catcher(std::forward<TRYCODE>(trycode), rethrow); +} + +[[noreturn]] void rethrow(U32 code, const std::string& stacktrace); + +#else  // not LL_WINDOWS ----------------------------------------------------- + +template <typename TRYCODE, typename FILTER, typename HANDLER> +auto catcher(TRYCODE&& trycode, FILTER&&, HANDLER&&) +{ +    return std::forward<TRYCODE>(trycode)(); +} + +template <typename TRYCODE, typename HANDLER> +auto catcher(TRYCODE&& trycode, HANDLER&&) +{ +    return std::forward<TRYCODE>(trycode)(); +} + +template <typename TRYCODE> +auto catcher(TRYCODE&& trycode) +{ +    return std::forward<TRYCODE>(trycode)(); +} -// SEH exception filtering for use in __try __except -// Separates C++ exceptions from C SEH exceptions -// Todo: might be good idea to do some kind of seh_to_msc_wrapper(function, ARGS&&); -U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop); +#endif // not LL_WINDOWS ----------------------------------------------------- -#endif //LL_WINDOWS +} // namespace LL::seh +} // namespace LL  #endif /* ! defined(LL_LLEXCEPTION_H) */ diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 9d53b9be35..3a05407dd0 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -793,19 +793,55 @@ private:  };  #elif LL_LINUX + +// *NOTE:Mani - eww, macros! srry. +#define LLPI_SET_INFO_STRING(llpi_id, cpuinfo_id) \ +        if (!cpuinfo[cpuinfo_id].empty()) \ +        { setInfo(llpi_id, cpuinfo[cpuinfo_id]);} + +#define LLPI_SET_INFO_INT(llpi_id, cpuinfo_id) \ +        {\ +            S32 result; \ +            if (!cpuinfo[cpuinfo_id].empty() \ +                && LLStringUtil::convertToS32(cpuinfo[cpuinfo_id], result)) \ +            { setInfo(llpi_id, result);} \ +        } +  const char CPUINFO_FILE[] = "/proc/cpuinfo"; -class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl -{ +class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl {  public: -    LLProcessorInfoLinuxImpl() -    { +    LLProcessorInfoLinuxImpl() {          get_proc_cpuinfo();      }      virtual ~LLProcessorInfoLinuxImpl() {} +  private: +    F64 getCPUMaxMHZ() +    { +        // Nicky: We just look into cpu0. In theory we could iterate over all cores +        // "/sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_max_freq" +        // But those should not fluctuate that much? +        std::ifstream fIn { "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq" }; + +        if( !fIn.is_open() ) +            return 0.0; + +        std::string strLine; +        fIn >> strLine; +        if( strLine.empty() ) +            return 0.0l; + +        F64 mhz {}; +        if( !LLStringUtil::convertToF64(strLine, mhz ) ) +            return 0.0; + +        mhz = mhz / 1000.0; +        return mhz; +    } +      void get_proc_cpuinfo()      {          std::map< std::string, std::string > cpuinfo; @@ -834,30 +870,23 @@ private:                  std::string llinename(linename);                  LLStringUtil::toLower(llinename);                  std::string lineval( spacespot + 1, nlspot ); -                cpuinfo[ llinename ] = lineval; +                    cpuinfo[ llinename ] = lineval;              }              fclose(cpuinfo_fp);          }  # if LL_X86 -// *NOTE:Mani - eww, macros! srry. -#define LLPI_SET_INFO_STRING(llpi_id, cpuinfo_id) \ -        if (!cpuinfo[cpuinfo_id].empty()) \ -        { setInfo(llpi_id, cpuinfo[cpuinfo_id]);} - -#define LLPI_SET_INFO_INT(llpi_id, cpuinfo_id) \ -        {\ -            S32 result; \ -            if (!cpuinfo[cpuinfo_id].empty() \ -                && LLStringUtil::convertToS32(cpuinfo[cpuinfo_id], result)) \ -            { setInfo(llpi_id, result);} \ +        F64 mhzFromSys = getCPUMaxMHZ(); +        F64 mhzFromProc {}; +        if( !LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhzFromProc ) ) +            mhzFromProc = 0.0; +        if (mhzFromSys > 1.0 && mhzFromSys > mhzFromProc ) +        { +            setInfo( eFrequency, mhzFromSys );          } - -        F64 mhz; -        if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz) -            && 200.0 < mhz && mhz < 10000.0) +        else if (  200.0 < mhzFromProc && mhzFromProc < 10000.0)          { -            setInfo(eFrequency,(F64)(mhz)); +            setInfo(eFrequency,(F64)(mhzFromProc));          }          LLPI_SET_INFO_STRING(eBrandName, "model name"); @@ -867,7 +896,7 @@ private:          LLPI_SET_INFO_INT(eModel, "model"); -        S32 family; +        S32 family{};          if (!cpuinfo["cpu family"].empty()              && LLStringUtil::convertToS32(cpuinfo["cpu family"], family))          { diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index efce458117..dff7fdb160 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -161,7 +161,7 @@ LLSD ll_binary_from_string(const LLSD& sd)  char* ll_print_sd(const LLSD& sd)  {      const U32 bufferSize = 10 * 1024; -    static char buffer[bufferSize]; +    static char buffer[bufferSize + 1];      std::ostringstream stream;      //stream.rdbuf()->pubsetbuf(buffer, bufferSize);      stream << LLSDOStreamer<LLSDXMLFormatter>(sd); @@ -183,7 +183,7 @@ char* ll_pretty_print_sd_ptr(const LLSD* sd)  char* ll_pretty_print_sd(const LLSD& sd)  {      const U32 bufferSize = 100 * 1024; -    static char buffer[bufferSize]; +    static char buffer[bufferSize + 1];      std::ostringstream stream;      //stream.rdbuf()->pubsetbuf(buffer, bufferSize);      stream << LLSDOStreamer<LLSDXMLFormatter>(sd, LLSDFormatter::OPTIONS_PRETTY); diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index b7ffddc023..4f888f1f5a 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -509,57 +509,46 @@ const S32 LLOSInfo::getOSBitness() const      return mOSBitness;  } -//static -U32 LLOSInfo::getProcessVirtualSizeKB() -{ -    U32 virtual_size = 0; -#if LL_LINUX -#   define STATUS_SIZE 2048 -    LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); -    if (status_filep) -    { -        S32 numRead = 0; -        char buff[STATUS_SIZE];     /* Flawfinder: ignore */ +namespace { -        size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); -        buff[nbytes] = '\0'; +    U32 readFromProcStat( std::string entryName ) +    { +        U32 val{}; +#if LL_LINUX +        constexpr U32 STATUS_SIZE  = 2048; -        // All these guys return numbers in KB -        char *memp = strstr(buff, "VmSize:"); -        if (memp) +        LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); +        if (status_filep)          { -            numRead += sscanf(memp, "%*s %u", &virtual_size); +            char buff[STATUS_SIZE];     /* Flawfinder: ignore */ + +            size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); +            buff[nbytes] = '\0'; + +            // All these guys return numbers in KB +            char *memp = strstr(buff, entryName.c_str()); +            if (memp) +            { +                (void) sscanf(memp, "%*s %u", &val); +            } +            fclose(status_filep);          } -        fclose(status_filep); -    }  #endif -    return virtual_size; +        return val; +    } +  }  //static -U32 LLOSInfo::getProcessResidentSizeKB() +U32 LLOSInfo::getProcessVirtualSizeKB()  { -    U32 resident_size = 0; -#if LL_LINUX -    LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); -    if (status_filep != NULL) -    { -        S32 numRead = 0; -        char buff[STATUS_SIZE];     /* Flawfinder: ignore */ - -        size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); -        buff[nbytes] = '\0'; +    return readFromProcStat( "VmSize:" ); +} -        // All these guys return numbers in KB -        char *memp = strstr(buff, "VmRSS:"); -        if (memp) -        { -            numRead += sscanf(memp, "%*s %u", &resident_size); -        } -        fclose(status_filep); -    } -#endif -    return resident_size; +//static +U32 LLOSInfo::getProcessResidentSizeKB() +{ +    return readFromProcStat( "VmRSS:" );  }  //static diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index fa48bcdefd..3fb25b4cef 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -35,7 +35,7 @@  // causes Windows abdominal pain such that it later fails code-signing in some  // mysterious way. Entirely suppressing these LLLeap tests pushes the failure  // rate MUCH lower. Can we re-enable them with a smaller data size on Windows? -const size_t BUFFERED_LENGTH =  100*1024; +const size_t BUFFERED_LENGTH = 1023*1024;  #else // not Windows  const size_t BUFFERED_LENGTH = 1023*1024; // try wrangling just under a megabyte of data diff --git a/indra/llcommon/tests/llstring_test.cpp b/indra/llcommon/tests/llstring_test.cpp index 3fadfa5334..ea5b0ee5fc 100644 --- a/indra/llcommon/tests/llstring_test.cpp +++ b/indra/llcommon/tests/llstring_test.cpp @@ -377,7 +377,7 @@ namespace tut      {          F32 value;          std::string str_val("2147483647"); //0x7FFFFFFF -        ensure("1: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == 2147483647); +        ensure("1: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == 2147483647.f);          str_val = "0";          ensure("2: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == 0); @@ -399,7 +399,7 @@ namespace tut      {          F64 value;          std::string str_val("9223372036854775807"); //0x7FFFFFFFFFFFFFFF -        ensure("1: convertToF64 failed", LLStringUtil::convertToF64(str_val, value) && value == 9223372036854775807LL); +        ensure("1: convertToF64 failed", LLStringUtil::convertToF64(str_val, value) && value == 9223372036854775807.);          str_val = "0";          ensure("2: convertToF64 failed", LLStringUtil::convertToF64(str_val, value) && value == 0.0F); diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt index 87796abd3c..8b0f8c2e4c 100644 --- a/indra/llcorehttp/CMakeLists.txt +++ b/indra/llcorehttp/CMakeLists.txt @@ -3,7 +3,6 @@  project(llcorehttp)  include(00-Common) -include(GoogleMock)  include(CURL)  include(OpenSSL)  include(NGHTTP2) @@ -11,7 +10,6 @@ include(ZLIBNG)  include(LLCoreHttp)  include(LLAddBuildTest)  include(LLCommon) -include(Tut)  include(bugsplat)  set(llcorehttp_SOURCE_FILES diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 587f25dc1b..8ce17b5753 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -170,7 +170,7 @@ bool ImageRequest::processRequest()                  mErrorString = LLImage::getLastThreadError();                  return true; // done (failed)              } -            if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents())) +            if (0 == (mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()))              {                  mErrorString = "Invalid image size";                  return true; // done (failed) diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index f5f151e27b..e35f4ae0b7 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -573,7 +573,6 @@ public:          for (S32 c = 0; c < numcomps; c++)          {              cmptparm[c].prec = 8; -            cmptparm[c].bpp = 8;              cmptparm[c].sgnd = 0;              cmptparm[c].dx = parameters.subsampling_dx;              cmptparm[c].dy = parameters.subsampling_dy; diff --git a/indra/llmath/llcalcparser.h b/indra/llmath/llcalcparser.h index e8fdcc9ae3..b40001cf7e 100644 --- a/indra/llmath/llcalcparser.h +++ b/indra/llmath/llcalcparser.h @@ -131,14 +131,14 @@ struct LLCalcParser : grammar<LLCalcParser>              power =                  unary_expr[power.value = arg1] >> -                *('^' >> assert_syntax(unary_expr[power.value = phoenix::bind(&powf)(power.value, arg1)])) +                *('^' >> assert_syntax(unary_expr[power.value = phoenix::bind(&LLCalcParser::_pow)(self, power.value, arg1)]))              ;              term =                  power[term.value = arg1] >>                  *(('*' >> assert_syntax(power[term.value *= arg1])) |                    ('/' >> assert_syntax(power[term.value /= arg1])) | -                  ('%' >> assert_syntax(power[term.value = phoenix::bind(&fmodf)(term.value, arg1)])) +                  ('%' >> assert_syntax(power[term.value = phoenix::bind(&LLCalcParser::_fmod)(self, term.value, arg1)]))                  )              ; @@ -177,6 +177,8 @@ private:      F32 _floor(const F32& a) const { return (F32)llfloor(a); }      F32 _ceil(const F32& a) const { return llceil(a); }      F32 _atan2(const F32& a,const F32& b) const { return atan2(a,b); } +    F32 _pow(const F32& a, const F32& b) const { return powf(a, b); } +    F32 _fmod(const F32&a, const F32& b) const { return fmodf(a, b); }      LLCalc::calc_map_t* mConstants;      LLCalc::calc_map_t* mVariables; diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index e44309476b..88ab29ec67 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -3,14 +3,11 @@  project(llmessage)  include(00-Common) -include(GoogleMock)  include(LLAddBuildTest)  include(LLCommon)  include(LLCoreHttp)  include(LLAddBuildTest)  include(Python) -include(Tut) -include(Python)  include(JsonCpp)  set(llmessage_SOURCE_FILES diff --git a/indra/llmessage/llnamevalue.cpp b/indra/llmessage/llnamevalue.cpp index c275f4ef00..0e31a6d6e6 100644 --- a/indra/llmessage/llnamevalue.cpp +++ b/indra/llmessage/llnamevalue.cpp @@ -967,4 +967,3 @@ std::ostream&       operator<<(std::ostream& s, const LLNameValue &a)      }      return s;  } - diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp index 3e1e5daa02..8a395c26a8 100644 --- a/indra/llmessage/llproxy.cpp +++ b/indra/llmessage/llproxy.cpp @@ -465,7 +465,7 @@ void LLProxy::applyProxySettings(CURL* handle)  /**   * @brief Send one TCP packet and receive one in return.   * - * This operation is done synchronously with a 1000ms timeout. Therefore, it should not be used when a blocking + * This operation is done synchronously with a 100ms timeout. Therefore, it should not be used when a blocking   * operation would impact the operation of the viewer.   *   * @param handle_ptr    Pointer to a connected LLSocket of type STREAM_TCP. @@ -482,7 +482,7 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou      apr_size_t expected_len = outlen; -    handle->setBlocking(1000); +    handle->setBlocking(100000); // 100ms, 100000us. Should be sufficient for localhost, nearby network      rv = apr_socket_send(apr_socket, dataout, &outlen);      if (APR_SUCCESS != rv) @@ -498,8 +498,6 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou          rv = -1;      } -    ms_sleep(1); -      if (APR_SUCCESS == rv)      {          expected_len = maxinlen; diff --git a/indra/llmessage/tests/llmockhttpclient.h b/indra/llmessage/tests/llmockhttpclient.h deleted file mode 100644 index 1611ab7bd8..0000000000 --- a/indra/llmessage/tests/llmockhttpclient.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file - * @brief - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -/* Macro Definitions */ -#ifndef LL_LLMOCKHTTPCLIENT_H -#define LL_LLMOCKHTTPCLIENT_H - -#include "linden_common.h" -#include "llhttpclientinterface.h" - -#include <gmock/gmock.h> - -class LLMockHTTPClient : public LLHTTPClientInterface -{ -public: -  MOCK_METHOD2(get, void(const std::string& url, LLCurl::ResponderPtr responder)); -  MOCK_METHOD3(get, void(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers)); -  MOCK_METHOD3(put, void(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder)); -}; - -// A helper to match responder types -template<typename T> -struct ResponderType -{ -    bool operator()(LLCurl::ResponderPtr ptr) const -    { -        T* p = dynamic_cast<T*>(ptr.get()); -        return p != NULL; -    } -}; - -inline bool operator==(const LLSD& l, const LLSD& r) -{ -    std::ostringstream ls, rs; -    ls << l; -    rs << r; -    return ls.str() == rs.str(); - -} - - -#endif //LL_LLMOCKHTTPCLIENT_H - diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt index 14a69afe6e..005426acde 100644 --- a/indra/llplugin/CMakeLists.txt +++ b/indra/llplugin/CMakeLists.txt @@ -31,14 +31,6 @@ set(llplugin_HEADER_FILES      llpluginsharedmemory.h      ) -if(NOT ADDRESS_SIZE EQUAL 32) -  if(WINDOWS) -    ##add_definitions(/FIXED:NO) -  else(WINDOWS) # not windows therefore gcc LINUX and DARWIN -    add_definitions(-fPIC) -  endif(WINDOWS) -endif(NOT ADDRESS_SIZE EQUAL 32) -  list(APPEND llplugin_SOURCE_FILES ${llplugin_HEADER_FILES})  add_library (llplugin ${llplugin_SOURCE_FILES}) diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 5857ee32e7..4e5013ec8f 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -981,6 +981,15 @@ void LLPluginClassMedia::enableMediaPluginDebugging( bool enable )      sendMessage( message );  } +#if LL_LINUX +void LLPluginClassMedia::enablePipeWireVolumeCatcher( bool enable ) +{ +    LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "enable_pipewire_volume_catcher"); +    message.setValueBoolean( "enable", enable ); +    sendMessage( message ); +} +#endif +  void LLPluginClassMedia::setTarget(const std::string &target)  {      mTarget = target; diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index d74b790d8f..5d2f3bbb79 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -135,6 +135,10 @@ public:      // Text may be unicode (utf8 encoded)      bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data); +#if LL_LINUX +    void enablePipeWireVolumeCatcher( bool enable ); +#endif +      static std::string sOIDcookieUrl;      static std::string sOIDcookieName;      static std::string sOIDcookieValue; diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index e8b586fdf1..432ac5510c 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -1120,19 +1120,17 @@ bool LLDAELoader::OpenFile(const std::string& filename)          if (skin)          { -            domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement()); - -            if (geom) +            if (domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement()))              { -                domMesh* mesh = geom->getMesh(); -                if (mesh) +                if (domMesh* mesh = geom->getMesh())                  { -                    std::vector< LLPointer< LLModel > >::iterator i = mModelsMap[mesh].begin(); -                    while (i != mModelsMap[mesh].end()) +                    dae_model_map::const_iterator it = mModelsMap.find(mesh); +                    if (it != mModelsMap.end())                      { -                        LLPointer<LLModel> mdl = *i; -                        LLDAELoader::processDomModel(mdl, &dae, root, mesh, skin); -                        i++; +                        for (const LLPointer<LLModel>& model : it->second) +                        { +                            LLDAELoader::processDomModel(model, &dae, root, mesh, skin); +                        }                      }                  }              } @@ -1302,6 +1300,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do              }          }          else +        {              //Has one or more skeletons              for (std::vector<domInstance_controller::domSkeleton*>::iterator skel_it = skeletons.begin();                   skel_it != skeletons.end(); ++skel_it) @@ -1386,6 +1385,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do                      }                  }//got skeleton?              } +        }          domSkin::domJoints* joints = skin->getJoints(); @@ -1686,7 +1686,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do              materials[model->mMaterialList[i]] = LLImportMaterial();          }          mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); -        stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); +        stretch_extents(model, transformation);      }  } @@ -2079,21 +2079,14 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da          mTransform.condition();      } -    domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element); -    if (instance_geo) +    if (domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element))      { -        domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement()); -        if (geo) +        if (domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement()))          { -            domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID()))); -            if (mesh) +            if (domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID()))))              { - -                std::vector< LLPointer< LLModel > >::iterator i = mModelsMap[mesh].begin(); -                while (i != mModelsMap[mesh].end()) +                for (LLModel* model : mModelsMap.find(mesh)->second)                  { -                    LLModel* model = *i; -                      LLMatrix4 transformation = mTransform;                      if (mTransform.determinant() < 0) @@ -2164,8 +2157,7 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da                      }                      mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials)); -                    stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); -                    i++; +                    stretch_extents(model, transformation);                  }              }          } diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 236cef9c3f..d21c6e974a 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -91,19 +91,15 @@ std::string LLModel::getStatusString(U32 status)  } -void LLModel::offsetMesh( const LLVector3& pivotPoint ) +void LLModel::offsetMesh(const LLVector3& pivotPoint)  { -    LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] ); +    LLVector4a pivot(pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ]); -    for (std::vector<LLVolumeFace>::iterator faceIt = mVolumeFaces.begin(); faceIt != mVolumeFaces.end(); ) +    for (LLVolumeFace& face : mVolumeFaces)      { -        std::vector<LLVolumeFace>:: iterator currentFaceIt = faceIt++; -        LLVolumeFace& face = *currentFaceIt; -        LLVector4a *pos = (LLVector4a*) face.mPositions; - -        for (U32 i=0; i<face.mNumVertices; ++i ) +        for (U32 i = 0; i < face.mNumVertices; ++i)          { -            pos[i].add( pivot ); +            face.mPositions[i].add(pivot);          }      }  } @@ -338,7 +334,7 @@ void LLModel::normalizeVolumeFaces()      }  } -void LLModel::getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out) +void LLModel::getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out) const  {      scale_out = mNormalizedScale;      translation_out = mNormalizedTranslation; diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index 657dc31fd2..b5b1ad9515 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -202,8 +202,8 @@ public:      void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL);      void remapVolumeFaces();      void optimizeVolumeFaces(); -    void offsetMesh( const LLVector3& pivotPoint ); -    void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out); +    void offsetMesh(const LLVector3& pivotPoint); +    void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out) const;      LLVector3 getTransformedCenter(const LLMatrix4& mat);      //reorder face list based on mMaterialList in this and reference so diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp index 4120352b40..6093a41bc1 100644 --- a/indra/llprimitive/llmodelloader.cpp +++ b/indra/llprimitive/llmodelloader.cpp @@ -37,7 +37,7 @@  std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList; -void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) +static void stretch_extents(const LLModel* model, const LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, bool& first_transform)  {      LLVector4a box[] =      { @@ -59,7 +59,7 @@ void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4          center.setAdd(face.mExtents[0], face.mExtents[1]);          center.mul(0.5f);          LLVector4a size; -        size.setSub(face.mExtents[1],face.mExtents[0]); +        size.setSub(face.mExtents[1], face.mExtents[0]);          size.mul(0.5f);          for (U32 i = 0; i < 8; i++) @@ -74,7 +74,7 @@ void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4              if (first_transform)              { -                first_transform = FALSE; +                first_transform = false;                  min = max = v;              }              else @@ -85,19 +85,19 @@ void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4      }  } -void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) +void LLModelLoader::stretch_extents(const LLModel* model, const LLMatrix4& mat)  {      LLVector4a mina, maxa;      LLMatrix4a mata;      mata.loadu(mat); -    mina.load3(min.mV); -    maxa.load3(max.mV); +    mina.load3(mExtents[0].mV); +    maxa.load3(mExtents[1].mV); -    stretch_extents(model, mata, mina, maxa, first_transform); +    ::stretch_extents(model, mata, mina, maxa, mFirstTransform); -    min.set(mina.getF32ptr()); -    max.set(maxa.getF32ptr()); +    mExtents[0].set(mina.getF32ptr()); +    mExtents[1].set(maxa.getF32ptr());  }  //----------------------------------------------------------------------------- @@ -121,7 +121,7 @@ LLModelLoader::LLModelLoader(  , mFilename(filename)  , mLod(lod)  , mTrySLM(false) -, mFirstTransform(TRUE) +, mFirstTransform(true)  , mNumOfFetchingTextures(0)  , mLoadCallback(load_cb)  , mJointLookupFunc(joint_lookup_func) @@ -292,14 +292,7 @@ bool LLModelLoader::loadFromSLM(const std::string& filename)              {                  if (idx >= model[lod].size())                  { -                    if (model[lod].size()) -                    { -                        instance_list[i].mLOD[lod] = model[lod][0]; -                    } -                    else -                    { -                        instance_list[i].mLOD[lod] = NULL; -                    } +                    instance_list[i].mLOD[lod] = model[lod].front();                      continue;                  } @@ -337,12 +330,12 @@ bool LLModelLoader::loadFromSLM(const std::string& filename)      //convert instance_list to mScene -    mFirstTransform = TRUE; +    mFirstTransform = true;      for (U32 i = 0; i < instance_list.size(); ++i)      {          LLModelInstance& cur_instance = instance_list[i];          mScene[cur_instance.mTransform].push_back(cur_instance); -        stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform); +        stretch_extents(cur_instance.mModel, cur_instance.mTransform);      }      setLoadState( DONE ); diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h index 402c29c260..637dabe08a 100644 --- a/indra/llprimitive/llmodelloader.h +++ b/indra/llprimitive/llmodelloader.h @@ -34,13 +34,13 @@  class LLJoint; -typedef std::map<std::string, LLMatrix4>            JointTransformMap; -typedef std::map<std::string, LLMatrix4>::iterator  JointTransformMapIt; -typedef std::map<std::string, std::string>          JointMap; -typedef std::deque<std::string>                     JointNameSet; +typedef std::map<std::string, LLMatrix4> JointTransformMap; +typedef std::map<std::string, LLMatrix4>::iterator JointTransformMapIt; +typedef std::map<std::string, std::string> JointMap; +typedef std::deque<std::string> JointNameSet;  const S32 SLM_SUPPORTED_VERSION = 3; -const S32 NUM_LOD                       = 4; +const S32 NUM_LOD = 4;  const U32 LEGACY_RIG_OK = 0;  const U32 LEGACY_RIG_FLAG_TOO_MANY_JOINTS = 1; @@ -50,32 +50,32 @@ class LLModelLoader : public LLThread  {  public: -    typedef std::map<std::string, LLImportMaterial>         material_map; -    typedef std::vector<LLPointer<LLModel > >                   model_list; -    typedef std::vector<LLModelInstance>                        model_instance_list; -    typedef std::map<LLMatrix4, model_instance_list >       scene; +    typedef std::map<std::string, LLImportMaterial> material_map; +    typedef std::vector<LLPointer<LLModel>> model_list; +    typedef std::vector<LLModelInstance> model_instance_list; +    typedef std::map<LLMatrix4, model_instance_list> scene;      // Callback with loaded model data and loaded LoD      // -    typedef boost::function<void (scene&,model_list&,S32,void*) >       load_callback_t; +    typedef boost::function<void (scene&, model_list&, S32, void*)> load_callback_t;      // Function to provide joint lookup by name      // (within preview avi skeleton, for example)      // -    typedef boost::function<LLJoint* (const std::string&,void*) >       joint_lookup_func_t; +    typedef boost::function<LLJoint* (const std::string&, void*)> joint_lookup_func_t;      // Func to load and associate material with all it's textures,      // returned value is the number of textures loaded      // intentionally non-const so func can modify material to      // store platform-specific data      // -    typedef boost::function<U32 (LLImportMaterial&,void*) >             texture_load_func_t; +    typedef boost::function<U32 (LLImportMaterial&, void*)> texture_load_func_t;      // Callback to inform client of state changes      // during loading process (errors will be reported      // as state changes here as well)      // -    typedef boost::function<void (U32,void*) >                              state_callback_t; +    typedef boost::function<void (U32, void*)> state_callback_t;      typedef enum      { @@ -104,7 +104,7 @@ public:      S32 mLod;      LLMatrix4 mTransform; -    BOOL mFirstTransform; +    bool mFirstTransform;      LLVector3 mExtents[2];      bool mTrySLM; @@ -136,7 +136,7 @@ public:          JointNameSet&                       jointsFromNodes,          JointMap&                           legalJointNamesMap,          U32                                 maxJointsPerMesh); -    virtual ~LLModelLoader() ; +    virtual ~LLModelLoader();      virtual void setNoNormalize() { mNoNormalize = true; }      virtual void setNoOptimize() { mNoOptimize = true; } @@ -156,13 +156,13 @@ public:      bool loadFromSLM(const std::string& filename);      void loadModelCallback(); -    void loadTextures() ; //called in the main thread. +    void loadTextures(); // called in the main thread.      void setLoadState(U32 state); +    void stretch_extents(const LLModel* model, const LLMatrix4& mat); - -    S32 mNumOfFetchingTextures ; //updated in the main thread -    bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread. +    S32 mNumOfFetchingTextures; // updated in the main thread +    bool areTexturesReady() { return !mNumOfFetchingTextures; } // called in the main thread.      bool verifyCount( int expected, int result ); @@ -212,10 +212,7 @@ protected:      LLSD mWarningsArray; // preview floater will pull logs from here      static std::list<LLModelLoader*> sActiveLoaderList; -    static bool isAlive(LLModelLoader* loader) ; +    static bool isAlive(LLModelLoader* loader);  }; -class LLMatrix4a; -void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform); -void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform);  #endif  // LL_LLMODELLOADER_H diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp index ce4df843ea..011e5d5ce6 100644 --- a/indra/llprimitive/llprimtexturelist.cpp +++ b/indra/llprimitive/llprimtexturelist.cpp @@ -137,14 +137,7 @@ S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te)          // we're changing an existing entry      llassert(mEntryList[index]);      delete (mEntryList[index]); -    if  (&te) -    { -        mEntryList[index] = te.newCopy(); -    } -    else -    { -        mEntryList[index] = LLPrimTextureList::newTextureEntry(); -    } +    mEntryList[index] = te.newCopy();      return TEM_CHANGE_TEXTURE;  } diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index 92b373c835..554e70d6a7 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -52,7 +52,9 @@  #include "llfontbitmapcache.h"  #include "llgl.h" -#define ENABLE_OT_SVG_SUPPORT +#if !defined(LL_NO_OTSVG) +    #define ENABLE_OT_SVG_SUPPORT +#endif  FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL; @@ -87,7 +89,7 @@ LLFontManager::LLFontManager()          FT_Done_FreeType(gFTLibrary);      } -#ifdef ENABLE_OT_SVG_SUPPORT +#if defined(ENABLE_OT_SVG_SUPPORT)      SVG_RendererHooks hooks = {          LLFontFreeTypeSvgRenderer::OnInit,          LLFontFreeTypeSvgRenderer::OnFree, @@ -483,8 +485,8 @@ LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type                      continue;                  }                  glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch); -                if (glyph_index) -                { +            if (glyph_index) +            {                      return addGlyphFromFont(pair.first, wch, glyph_index,                                              glyph_type);                  } diff --git a/indra/llrender/llfontfreetypesvg.cpp b/indra/llrender/llfontfreetypesvg.cpp index 355e8432aa..e33da7cf86 100644 --- a/indra/llrender/llfontfreetypesvg.cpp +++ b/indra/llrender/llfontfreetypesvg.cpp @@ -80,6 +80,7 @@ void LLFontFreeTypeSvgRenderer::OnDataFinalizer(void* objectp)  //static  FT_Error LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot(FT_GlyphSlot glyph_slot, FT_Bool cache, FT_Pointer*)  { +#ifndef LL_NO_OTSVG      FT_SVG_Document document = static_cast<FT_SVG_Document>(glyph_slot->other);      llassert(!glyph_slot->generic.data || !cache || glyph_slot->glyph_index == ((LLSvgRenderData*)glyph_slot->generic.data)->GlyphIndex); @@ -166,6 +167,9 @@ FT_Error LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot(FT_GlyphSlot glyph_slot,      }      return FT_Err_Ok; +#else +    return FT_Err_Unimplemented_Feature; +#endif  }  // static diff --git a/indra/llrender/llfontfreetypesvg.h b/indra/llrender/llfontfreetypesvg.h index 72ac5293ce..62aefd10b5 100644 --- a/indra/llrender/llfontfreetypesvg.h +++ b/indra/llrender/llfontfreetypesvg.h @@ -29,7 +29,11 @@  #include <ft2build.h>  #include FT_TYPES_H  #include FT_MODULE_H -#include FT_OTSVG_H +#ifdef FT_OTSVG_H +    #include FT_OTSVG_H +#else +   #define LL_NO_OTSVG +#endif   // See https://freetype.org/freetype2/docs/reference/ft2-svg_fonts.html  class LLFontFreeTypeSvgRenderer diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 1b5566a3f7..a34efe24d3 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -211,8 +211,6 @@ LLMatrix4 gGLObliqueProjectionInverse;  std::list<LLGLUpdate*> LLGLUpdate::sGLQ; -#if (LL_WINDOWS || LL_LINUX)  && !LL_MESA_HEADLESS -  #if LL_WINDOWS  // WGL_ARB_create_context  PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; @@ -232,8 +230,6 @@ PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC             wglBlitContextFramebufferAMD = n  PFNWGLSWAPINTERVALEXTPROC    wglSwapIntervalEXT = nullptr;  PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = nullptr; -#endif -  // GL_VERSION_1_2  //PFNGLDRAWRANGEELEMENTSPROC  glDrawRangeElements = nullptr;  //PFNGLTEXIMAGE3DPROC         glTexImage3D = nullptr; @@ -1381,6 +1377,9 @@ void LLGLManager::shutdownGL()  void LLGLManager::initExtensions()  { +#if LL_LINUX +    glh_init_extensions(""); +#endif  #if LL_DARWIN      GLint num_extensions = 0;      std::string all_extensions{""}; @@ -1411,10 +1410,9 @@ void LLGLManager::initExtensions()      mInited = TRUE; -#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS +#if LL_WINDOWS      LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL; -#if LL_WINDOWS      // WGL_AMD_gpu_association      wglGetGPUIDsAMD = (PFNWGLGETGPUIDSAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUIDsAMD");      wglGetGPUInfoAMD = (PFNWGLGETGPUINFOAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUInfoAMD"); @@ -1432,8 +1430,6 @@ void LLGLManager::initExtensions()      // WGL_ARB_create_context      wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreateContextAttribsARB"); -#endif -      // Load entire OpenGL API through GetProcAddress, leaving sections beyond mGLVersion unloaded @@ -2561,6 +2557,7 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor      {          return;      } +    LL_INFOS() << "GL: "  << version << LL_ENDL;      version_string->assign(version); @@ -2940,5 +2937,3 @@ extern "C"      __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;  }  #endif - - diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index c5e1ff3e23..df23a9da1d 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -41,6 +41,22 @@  # include "GL/glh_extensions.h"  # undef __APPLE__ +#elif LL_LINUX +#define GL_GLEXT_PROTOTYPES +#define GLX_GLEXT_PROTOTYPES + +#include "GL/gl.h" +#include "GL/glext.h" +#include "GL/glu.h" + +// The __APPLE__ kludge is to make glh_extensions.h not symbol-clash horribly +# define __APPLE__ +# include "GL/glh_extensions.h" +# undef __APPLE__ + +# include "GL/glx.h" +# include "GL/glxext.h" +  #elif LL_WINDOWS  //----------------------------------------------------------------------------  // LL_WINDOWS @@ -1029,6 +1045,25 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);  #include <OpenGL/gl.h> +#elif LL_LINUX + +#define GL_GLEXT_PROTOTYPES +#define GLX_GLEXT_PROTOTYPES + +#include "GL/gl.h" +#include "GL/glu.h" +#include "GL/glext.h" +#include "GL/glx.h" + +// The __APPLE__ kludge is to make glh_extensions.h not symbol-clash horribly +# define __APPLE__ +# include "GL/glh_extensions.h" +# undef __APPLE__ + +// #include <X11/Xlib.h> +// #include <X11/Xutil.h> +#include "GL/glh_extensions.h" +  #endif // LL_MESA / LL_WINDOWS / LL_DARWIN  // Even when GL_ARB_depth_clamp is available in the driver, the (correct) diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 28b5bc7495..3cc26b14bd 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -279,7 +279,7 @@ bool LLGLSLShader::readProfileQuery(bool for_runtime, bool force_read)              GLuint64 samples_passed = 0;              glGetQueryObjectui64v(mSamplesQuery, GL_QUERY_RESULT, &samples_passed); -            U64 primitives_generated = 0; +            GLuint64 primitives_generated = 0;              glGetQueryObjectui64v(mPrimitivesQuery, GL_QUERY_RESULT, &primitives_generated);              sTotalTimeElapsed += time_elapsed; diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index 7b1430c67c..9ebd6ef0b0 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -59,11 +59,12 @@ set(llwindow_LINK_LIBRARIES          ll::uilibraries          ll::SDL          ) +  # Libraries on which this library depends, needed for Linux builds  # Sort by high-level to low-level  if (LINUX) -  list(APPEND viewer_SOURCE_FILES  -       llkeyboardsdl.cpp  +  list(APPEND viewer_SOURCE_FILES +       llkeyboardsdl.cpp         llwindowsdl.cpp         )    list(APPEND viewer_HEADER_FILES @@ -83,7 +84,6 @@ if (LINUX)          fontconfig          # For FCInit and other FC* functions.          )    endif (BUILD_HEADLESS) -  endif (LINUX)  if (DARWIN) @@ -179,7 +179,7 @@ endif (SDL_FOUND)    target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES})    target_include_directories(llwindow INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) -   +  if (DARWIN)    include(CMakeFindFrameworks)    find_library(CARBON_LIBRARY Carbon) diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp index b3dcac6222..d4b0743f32 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -41,7 +41,6 @@ std::map<KEY,std::string> LLKeyboard::sKeysToNames;  std::map<std::string,KEY> LLKeyboard::sNamesToKeys;  LLKeyStringTranslatorFunc*  LLKeyboard::mStringTranslator = NULL;   // Used for l10n + PC/Mac/Linux accelerator labeling -  //  // Class Implementation  // @@ -195,12 +194,11 @@ void LLKeyboard::resetKeys()  } -BOOL LLKeyboard::translateKey(const U16 os_key, KEY *out_key) +BOOL LLKeyboard::translateKey(const NATIVE_KEY_TYPE os_key, KEY *out_key)  { -    std::map<U16, KEY>::iterator iter;      // Only translate keys in the map, ignore all other keys for now -    iter = mTranslateKeyMap.find(os_key); +    auto iter = mTranslateKeyMap.find(os_key);      if (iter == mTranslateKeyMap.end())      {          //LL_WARNS() << "Unknown virtual key " << os_key << LL_ENDL; @@ -214,11 +212,9 @@ BOOL LLKeyboard::translateKey(const U16 os_key, KEY *out_key)      }  } - -U16 LLKeyboard::inverseTranslateKey(const KEY translated_key) +LLKeyboard::NATIVE_KEY_TYPE LLKeyboard::inverseTranslateKey(const KEY translated_key)  { -    std::map<KEY, U16>::iterator iter; -    iter = mInvTranslateKeyMap.find(translated_key); +    auto iter = mInvTranslateKeyMap.find(translated_key);      if (iter == mInvTranslateKeyMap.end())      {          return 0; diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index 2618f9f022..11c745ae71 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -55,6 +55,11 @@ class LLWindowCallbacks;  class LLKeyboard  {  public: +#ifndef LL_SDL +    typedef U16 NATIVE_KEY_TYPE; +#else +    typedef U32 NATIVE_KEY_TYPE; +#endif      LLKeyboard();      virtual ~LLKeyboard(); @@ -67,14 +72,13 @@ public:      BOOL            getKeyDown(const KEY key) { return mKeyLevel[key]; }      BOOL            getKeyRepeated(const KEY key) { return mKeyRepeated[key]; } -    BOOL            translateKey(const U16 os_key, KEY *translated_key); -    U16             inverseTranslateKey(const KEY translated_key); +    BOOL            translateKey(const NATIVE_KEY_TYPE os_key, KEY *translated_key); +    NATIVE_KEY_TYPE     inverseTranslateKey(const KEY translated_key);      BOOL            handleTranslatedKeyUp(KEY translated_key, U32 translated_mask);     // Translated into "Linden" keycodes      BOOL            handleTranslatedKeyDown(KEY translated_key, U32 translated_mask);   // Translated into "Linden" keycodes - -    virtual BOOL    handleKeyUp(const U16 key, MASK mask) = 0; -    virtual BOOL    handleKeyDown(const U16 key, MASK mask) = 0; +    virtual BOOL    handleKeyUp(const NATIVE_KEY_TYPE key, MASK mask) = 0; +    virtual BOOL    handleKeyDown(const NATIVE_KEY_TYPE key, MASK mask) = 0;  #ifdef LL_DARWIN      // We only actually use this for OS X. @@ -111,8 +115,8 @@ protected:      void            addKeyName(KEY key, const std::string& name);  protected: -    std::map<U16, KEY>  mTranslateKeyMap;       // Map of translations from OS keys to Linden KEYs -    std::map<KEY, U16>  mInvTranslateKeyMap;    // Map of translations from Linden KEYs to OS keys +    std::map<NATIVE_KEY_TYPE, KEY>  mTranslateKeyMap;       // Map of translations from OS keys to Linden KEYs +    std::map<KEY, NATIVE_KEY_TYPE>  mInvTranslateKeyMap;    // Map of translations from Linden KEYs to OS keys      LLWindowCallbacks *mCallbacks;      LLTimer         mKeyLevelTimer[KEY_COUNT];  // Time since level was set diff --git a/indra/llwindow/llkeyboardheadless.cpp b/indra/llwindow/llkeyboardheadless.cpp index 01ac26261b..265d7e6c76 100644 --- a/indra/llwindow/llkeyboardheadless.cpp +++ b/indra/llwindow/llkeyboardheadless.cpp @@ -35,12 +35,8 @@ void LLKeyboardHeadless::resetMaskKeys()  { } -BOOL LLKeyboardHeadless::handleKeyDown(const U16 key, const U32 mask) -{ return FALSE; } -BOOL LLKeyboardHeadless::handleKeyUp(const U16 key, const U32 mask) -{ return FALSE; }  MASK LLKeyboardHeadless::currentMask(BOOL for_mouse_event)  { return MASK_NONE; } diff --git a/indra/llwindow/llkeyboardheadless.h b/indra/llwindow/llkeyboardheadless.h index 8e067e6108..595f824872 100644 --- a/indra/llwindow/llkeyboardheadless.h +++ b/indra/llwindow/llkeyboardheadless.h @@ -35,8 +35,13 @@ public:      LLKeyboardHeadless();      /*virtual*/ ~LLKeyboardHeadless() {}; -    /*virtual*/ BOOL    handleKeyUp(const U16 key, MASK mask); -    /*virtual*/ BOOL    handleKeyDown(const U16 key, MASK mask); +#ifndef LL_SDL +    /*virtual*/ BOOL    handleKeyUp(const U16 key, MASK mask) { return FALSE; } +    /*virtual*/ BOOL    handleKeyDown(const U16 key, MASK mask) { return FALSE; } +#else +    /*virtual*/ BOOL    handleKeyUp(const U32 key, MASK mask) { return FALSE; } +    /*virtual*/ BOOL    handleKeyDown(const U32 key, MASK mask) { return FALSE; } +#endif      /*virtual*/ void    resetMaskKeys();      /*virtual*/ MASK    currentMask(BOOL for_mouse_event);      /*virtual*/ void    scanKeyboard(); diff --git a/indra/llwindow/llkeyboardsdl.cpp b/indra/llwindow/llkeyboardsdl.cpp index 3ee10f70cd..0fe0b5b771 100644 --- a/indra/llwindow/llkeyboardsdl.cpp +++ b/indra/llwindow/llkeyboardsdl.cpp @@ -1,6 +1,5 @@  /** - * @file llkeyboardsdl.cpp - * @brief Handler for assignable key bindings + * @author This module has many fathers, and it shows.   *   * $LicenseInfo:firstyear=2001&license=viewerlgpl$   * Second Life Viewer Source Code @@ -24,12 +23,11 @@   * $/LicenseInfo$   */ -#if LL_SDL -  #include "linden_common.h"  #include "llkeyboardsdl.h"  #include "llwindowcallbacks.h" -#include "SDL/SDL.h" +#include "SDL2/SDL.h" +#include "SDL2/SDL_keycode.h"  LLKeyboardSDL::LLKeyboardSDL()  { @@ -40,6 +38,10 @@ LLKeyboardSDL::LLKeyboardSDL()      // Virtual key mappings from SDL_keysym.h ...      // SDL maps the letter keys to the ASCII you'd expect, but it's lowercase... + +    // <FS:ND> Looks like we need to map those despite of SDL_TEXTINPUT handling most of this, but without +    // the translation lower->upper here accelerators will not work. +      U16 cur_char;      for (cur_char = 'A'; cur_char <= 'Z'; cur_char++)      { @@ -68,13 +70,12 @@ LLKeyboardSDL::LLKeyboardSDL()      //mTranslateKeyMap[SDLK_KP3] = KEY_PAGE_DOWN;      //mTranslateKeyMap[SDLK_KP0] = KEY_INSERT; -    mTranslateKeyMap[SDLK_SPACE] = ' '; +    mTranslateKeyMap[SDLK_SPACE] = ' ';     // <FS:ND/> Those are handled by SDL2 via text input, do not map them      mTranslateKeyMap[SDLK_RETURN] = KEY_RETURN;      mTranslateKeyMap[SDLK_LEFT] = KEY_LEFT;      mTranslateKeyMap[SDLK_RIGHT] = KEY_RIGHT;      mTranslateKeyMap[SDLK_UP] = KEY_UP;      mTranslateKeyMap[SDLK_DOWN] = KEY_DOWN; -    mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE;      mTranslateKeyMap[SDLK_KP_ENTER] = KEY_RETURN;      mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE;      mTranslateKeyMap[SDLK_BACKSPACE] = KEY_BACKSPACE; @@ -111,40 +112,39 @@ LLKeyboardSDL::LLKeyboardSDL()      mTranslateKeyMap[SDLK_F10] = KEY_F10;      mTranslateKeyMap[SDLK_F11] = KEY_F11;      mTranslateKeyMap[SDLK_F12] = KEY_F12; -    mTranslateKeyMap[SDLK_PLUS]   = '='; -    mTranslateKeyMap[SDLK_COMMA]  = ','; -    mTranslateKeyMap[SDLK_MINUS]  = '-'; -    mTranslateKeyMap[SDLK_PERIOD] = '.'; -    mTranslateKeyMap[SDLK_BACKQUOTE] = '`'; -    mTranslateKeyMap[SDLK_SLASH] = KEY_DIVIDE; -    mTranslateKeyMap[SDLK_SEMICOLON] = ';'; -    mTranslateKeyMap[SDLK_LEFTBRACKET] = '['; -    mTranslateKeyMap[SDLK_BACKSLASH] = '\\'; -    mTranslateKeyMap[SDLK_RIGHTBRACKET] = ']'; -    mTranslateKeyMap[SDLK_QUOTE] = '\''; +    mTranslateKeyMap[SDLK_PLUS]   = '='; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_COMMA]  = ','; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_MINUS]  = '-'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_PERIOD] = '.'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_BACKQUOTE] = '`'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_SLASH] = KEY_DIVIDE; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_SEMICOLON] = ';'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_LEFTBRACKET] = '['; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_BACKSLASH] = '\\'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_RIGHTBRACKET] = ']'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_QUOTE] = '\''; // <FS:ND/> Those are handled by SDL2 via text input, do not map them      // Build inverse map -    std::map<U16, KEY>::iterator iter; -    for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) +    for (auto iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++)      {          mInvTranslateKeyMap[iter->second] = iter->first;      }      // numpad map -    mTranslateNumpadMap[SDLK_KP0] = KEY_PAD_INS; -    mTranslateNumpadMap[SDLK_KP1] = KEY_PAD_END; -    mTranslateNumpadMap[SDLK_KP2] = KEY_PAD_DOWN; -    mTranslateNumpadMap[SDLK_KP3] = KEY_PAD_PGDN; -    mTranslateNumpadMap[SDLK_KP4] = KEY_PAD_LEFT; -    mTranslateNumpadMap[SDLK_KP5] = KEY_PAD_CENTER; -    mTranslateNumpadMap[SDLK_KP6] = KEY_PAD_RIGHT; -    mTranslateNumpadMap[SDLK_KP7] = KEY_PAD_HOME; -    mTranslateNumpadMap[SDLK_KP8] = KEY_PAD_UP; -    mTranslateNumpadMap[SDLK_KP9] = KEY_PAD_PGUP; +    mTranslateNumpadMap[SDLK_KP_0] = KEY_PAD_INS; +    mTranslateNumpadMap[SDLK_KP_1] = KEY_PAD_END; +    mTranslateNumpadMap[SDLK_KP_2] = KEY_PAD_DOWN; +    mTranslateNumpadMap[SDLK_KP_3] = KEY_PAD_PGDN; +    mTranslateNumpadMap[SDLK_KP_4] = KEY_PAD_LEFT; +    mTranslateNumpadMap[SDLK_KP_5] = KEY_PAD_CENTER; +    mTranslateNumpadMap[SDLK_KP_6] = KEY_PAD_RIGHT; +    mTranslateNumpadMap[SDLK_KP_7] = KEY_PAD_HOME; +    mTranslateNumpadMap[SDLK_KP_8] = KEY_PAD_UP; +    mTranslateNumpadMap[SDLK_KP_9] = KEY_PAD_PGUP;      mTranslateNumpadMap[SDLK_KP_PERIOD] = KEY_PAD_DEL;      // build inverse numpad map -    for (iter = mTranslateNumpadMap.begin(); +    for (auto iter = mTranslateNumpadMap.begin();           iter != mTranslateNumpadMap.end();           iter++)      { @@ -154,7 +154,7 @@ LLKeyboardSDL::LLKeyboardSDL()  void LLKeyboardSDL::resetMaskKeys()  { -    SDLMod mask = SDL_GetModState(); +    SDL_Keymod mask = SDL_GetModState();      // MBW -- XXX -- This mirrors the operation of the Windows version of resetMaskKeys().      //    It looks a bit suspicious, as it won't correct for keys that have been released. @@ -201,37 +201,37 @@ MASK LLKeyboardSDL::updateModifiers(const U32 mask)  } -static U16 adjustNativekeyFromUnhandledMask(const U16 key, const U32 mask) +static U32 adjustNativekeyFromUnhandledMask(const U32 key, const U32 mask)  {      // SDL doesn't automatically adjust the keysym according to      // whether NUMLOCK is engaged, so we massage the keysym manually. -    U16 rtn = key; +    U32 rtn = key;      if (!(mask & KMOD_NUM))      {          switch (key)          { -        case SDLK_KP_PERIOD: rtn = SDLK_DELETE; break; -        case SDLK_KP0: rtn = SDLK_INSERT; break; -        case SDLK_KP1: rtn = SDLK_END; break; -        case SDLK_KP2: rtn = SDLK_DOWN; break; -        case SDLK_KP3: rtn = SDLK_PAGEDOWN; break; -        case SDLK_KP4: rtn = SDLK_LEFT; break; -        case SDLK_KP6: rtn = SDLK_RIGHT; break; -        case SDLK_KP7: rtn = SDLK_HOME; break; -        case SDLK_KP8: rtn = SDLK_UP; break; -        case SDLK_KP9: rtn = SDLK_PAGEUP; break; +            case SDLK_KP_PERIOD: rtn = SDLK_DELETE; break; +            case SDLK_KP_0: rtn = SDLK_INSERT; break; +            case SDLK_KP_1: rtn = SDLK_END; break; +            case SDLK_KP_2: rtn = SDLK_DOWN; break; +            case SDLK_KP_3: rtn = SDLK_PAGEDOWN; break; +            case SDLK_KP_4: rtn = SDLK_LEFT; break; +            case SDLK_KP_6: rtn = SDLK_RIGHT; break; +            case SDLK_KP_7: rtn = SDLK_HOME; break; +            case SDLK_KP_8: rtn = SDLK_UP; break; +            case SDLK_KP_9: rtn = SDLK_PAGEUP; break;          }      }      return rtn;  } -BOOL LLKeyboardSDL::handleKeyDown(const U16 key, const U32 mask) +BOOL LLKeyboardSDL::handleKeyDown(const U32 key, const U32 mask)  { -    U16     adjusted_nativekey; +    U32 adjusted_nativekey;      KEY translated_key = 0;      U32 translated_mask = MASK_NONE; -    BOOL    handled = FALSE; +    BOOL handled = FALSE;      adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); @@ -246,12 +246,12 @@ BOOL LLKeyboardSDL::handleKeyDown(const U16 key, const U32 mask)  } -BOOL LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask) +BOOL LLKeyboardSDL::handleKeyUp(const U32 key, const U32 mask)  { -    U16     adjusted_nativekey; +    U32 adjusted_nativekey;      KEY translated_key = 0;      U32 translated_mask = MASK_NONE; -    BOOL    handled = FALSE; +    BOOL handled = FALSE;      adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); @@ -268,16 +268,20 @@ BOOL LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask)  MASK LLKeyboardSDL::currentMask(BOOL for_mouse_event)  {      MASK result = MASK_NONE; -    SDLMod mask = SDL_GetModState(); +    SDL_Keymod mask = SDL_GetModState(); -    if (mask & KMOD_SHIFT)          result |= MASK_SHIFT; -    if (mask & KMOD_CTRL)           result |= MASK_CONTROL; -    if (mask & KMOD_ALT)            result |= MASK_ALT; +    if (mask & KMOD_SHIFT) +        result |= MASK_SHIFT; +    if (mask & KMOD_CTRL) +        result |= MASK_CONTROL; +    if (mask & KMOD_ALT) +        result |= MASK_ALT;      // For keyboard events, consider Meta keys equivalent to Control      if (!for_mouse_event)      { -        if (mask & KMOD_META) result |= MASK_CONTROL; +        if (mask & KMOD_GUI) +            result |= MASK_CONTROL;      }      return result; @@ -310,7 +314,7 @@ void LLKeyboardSDL::scanKeyboard()  } -BOOL LLKeyboardSDL::translateNumpadKey( const U16 os_key, KEY *translated_key) +BOOL LLKeyboardSDL::translateNumpadKey( const U32 os_key, KEY *translated_key)  {      return translateKey(os_key, translated_key);  } @@ -320,5 +324,338 @@ U16 LLKeyboardSDL::inverseTranslateNumpadKey(const KEY translated_key)      return inverseTranslateKey(translated_key);  } -#endif +enum class WindowsVK : U32 +{ +    VK_UNKNOWN = 0, +    VK_CANCEL = 0x03, +    VK_BACK = 0x08, +    VK_TAB = 0x09, +    VK_CLEAR = 0x0C, +    VK_RETURN = 0x0D, +    VK_SHIFT = 0x10, +    VK_CONTROL = 0x11, +    VK_MENU = 0x12, +    VK_PAUSE = 0x13, +    VK_CAPITAL = 0x14, +    VK_KANA = 0x15, +    VK_HANGUL = 0x15, +    VK_JUNJA = 0x17, +    VK_FINAL = 0x18, +    VK_HANJA = 0x19, +    VK_KANJI = 0x19, +    VK_ESCAPE = 0x1B, +    VK_CONVERT = 0x1C, +    VK_NONCONVERT = 0x1D, +    VK_ACCEPT = 0x1E, +    VK_MODECHANGE = 0x1F, +    VK_SPACE = 0x20, +    VK_PRIOR = 0x21, +    VK_NEXT = 0x22, +    VK_END = 0x23, +    VK_HOME = 0x24, +    VK_LEFT = 0x25, +    VK_UP = 0x26, +    VK_RIGHT = 0x27, +    VK_DOWN = 0x28, +    VK_SELECT = 0x29, +    VK_PRINT = 0x2A, +    VK_EXECUTE = 0x2B, +    VK_SNAPSHOT = 0x2C, +    VK_INSERT = 0x2D, +    VK_DELETE = 0x2E, +    VK_HELP = 0x2F, +    VK_0 = 0x30, +    VK_1 = 0x31, +    VK_2 = 0x32, +    VK_3 = 0x33, +    VK_4 = 0x34, +    VK_5 = 0x35, +    VK_6 = 0x36, +    VK_7 = 0x37, +    VK_8 = 0x38, +    VK_9 = 0x39, +    VK_A = 0x41, +    VK_B = 0x42, +    VK_C = 0x43, +    VK_D = 0x44, +    VK_E = 0x45, +    VK_F = 0x46, +    VK_G = 0x47, +    VK_H = 0x48, +    VK_I = 0x49, +    VK_J = 0x4A, +    VK_K = 0x4B, +    VK_L = 0x4C, +    VK_M = 0x4D, +    VK_N = 0x4E, +    VK_O = 0x4F, +    VK_P = 0x50, +    VK_Q = 0x51, +    VK_R = 0x52, +    VK_S = 0x53, +    VK_T = 0x54, +    VK_U = 0x55, +    VK_V = 0x56, +    VK_W = 0x57, +    VK_X = 0x58, +    VK_Y = 0x59, +    VK_Z = 0x5A, +    VK_LWIN = 0x5B, +    VK_RWIN = 0x5C, +    VK_APPS = 0x5D, +    VK_SLEEP = 0x5F, +    VK_NUMPAD0 = 0x60, +    VK_NUMPAD1 = 0x61, +    VK_NUMPAD2 = 0x62, +    VK_NUMPAD3 = 0x63, +    VK_NUMPAD4 = 0x64, +    VK_NUMPAD5 = 0x65, +    VK_NUMPAD6 = 0x66, +    VK_NUMPAD7 = 0x67, +    VK_NUMPAD8 = 0x68, +    VK_NUMPAD9 = 0x69, +    VK_MULTIPLY = 0x6A, +    VK_ADD = 0x6B, +    VK_SEPARATOR = 0x6C, +    VK_SUBTRACT = 0x6D, +    VK_DECIMAL = 0x6E, +    VK_DIVIDE = 0x6F, +    VK_F1 = 0x70, +    VK_F2 = 0x71, +    VK_F3 = 0x72, +    VK_F4 = 0x73, +    VK_F5 = 0x74, +    VK_F6 = 0x75, +    VK_F7 = 0x76, +    VK_F8 = 0x77, +    VK_F9 = 0x78, +    VK_F10 = 0x79, +    VK_F11 = 0x7A, +    VK_F12 = 0x7B, +    VK_F13 = 0x7C, +    VK_F14 = 0x7D, +    VK_F15 = 0x7E, +    VK_F16 = 0x7F, +    VK_F17 = 0x80, +    VK_F18 = 0x81, +    VK_F19 = 0x82, +    VK_F20 = 0x83, +    VK_F21 = 0x84, +    VK_F22 = 0x85, +    VK_F23 = 0x86, +    VK_F24 = 0x87, +    VK_NUMLOCK = 0x90, +    VK_SCROLL = 0x91, +    VK_LSHIFT = 0xA0, +    VK_RSHIFT = 0xA1, +    VK_LCONTROL = 0xA2, +    VK_RCONTROL = 0xA3, +    VK_LMENU = 0xA4, +    VK_RMENU = 0xA5, +    VK_BROWSER_BACK = 0xA6, +    VK_BROWSER_FORWARD = 0xA7, +    VK_BROWSER_REFRESH = 0xA8, +    VK_BROWSER_STOP = 0xA9, +    VK_BROWSER_SEARCH = 0xAA, +    VK_BROWSER_FAVORITES = 0xAB, +    VK_BROWSER_HOME = 0xAC, +    VK_VOLUME_MUTE = 0xAD, +    VK_VOLUME_DOWN = 0xAE, +    VK_VOLUME_UP = 0xAF, +    VK_MEDIA_NEXT_TRACK = 0xB0, +    VK_MEDIA_PREV_TRACK = 0xB1, +    VK_MEDIA_STOP = 0xB2, +    VK_MEDIA_PLAY_PAUSE = 0xB3, +    VK_MEDIA_LAUNCH_MAIL = 0xB4, +    VK_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5, +    VK_MEDIA_LAUNCH_APP1 = 0xB6, +    VK_MEDIA_LAUNCH_APP2 = 0xB7, +    VK_OEM_1 = 0xBA, +    VK_OEM_PLUS = 0xBB, +    VK_OEM_COMMA = 0xBC, +    VK_OEM_MINUS = 0xBD, +    VK_OEM_PERIOD = 0xBE, +    VK_OEM_2 = 0xBF, +    VK_OEM_3 = 0xC0, +    VK_OEM_4 = 0xDB, +    VK_OEM_5 = 0xDC, +    VK_OEM_6 = 0xDD, +    VK_OEM_7 = 0xDE, +    VK_OEM_8 = 0xDF, +    VK_OEM_102 = 0xE2, +    VK_PROCESSKEY = 0xE5, +    VK_PACKET = 0xE7, +    VK_ATTN = 0xF6, +    VK_CRSEL = 0xF7, +    VK_EXSEL = 0xF8, +    VK_EREOF = 0xF9, +    VK_PLAY = 0xFA, +    VK_ZOOM = 0xFB, +    VK_NONAME = 0xFC, +    VK_PA1 = 0xFD, +    VK_OEM_CLEAR = 0xFE, +}; + +std::map< U32, U32 > mSDL2_to_Win; +std::set< U32 > mIgnoreSDL2Keys; + +U32 LLKeyboardSDL::mapSDL2toWin( U32 aSymbol ) +{ +    // <FS:ND> Map SDLK_ virtual keys to Windows VK_ virtual keys. +    // Text is handled via unicode input (SDL_TEXTINPUT event) and does not need to be translated into VK_ values as those match already. +    if( mSDL2_to_Win.empty() ) +    { + +        mSDL2_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::VK_BACK; +        mSDL2_to_Win[ SDLK_TAB ] = (U32)WindowsVK::VK_TAB; +        mSDL2_to_Win[ 12 ] = (U32)WindowsVK::VK_CLEAR; +        mSDL2_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::VK_RETURN; +        mSDL2_to_Win[ 19 ] = (U32)WindowsVK::VK_PAUSE; +        mSDL2_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::VK_ESCAPE; +        mSDL2_to_Win[ SDLK_SPACE ] = (U32)WindowsVK::VK_SPACE; +        mSDL2_to_Win[ SDLK_QUOTE ] = (U32)WindowsVK::VK_OEM_7; +        mSDL2_to_Win[ SDLK_COMMA ] = (U32)WindowsVK::VK_OEM_COMMA; +        mSDL2_to_Win[ SDLK_MINUS ] = (U32)WindowsVK::VK_OEM_MINUS; +        mSDL2_to_Win[ SDLK_PERIOD ] = (U32)WindowsVK::VK_OEM_PERIOD; +        mSDL2_to_Win[ SDLK_SLASH ] = (U32)WindowsVK::VK_OEM_2; + +        mSDL2_to_Win[ SDLK_0 ] = (U32)WindowsVK::VK_0; +        mSDL2_to_Win[ SDLK_1 ] = (U32)WindowsVK::VK_1; +        mSDL2_to_Win[ SDLK_2 ] = (U32)WindowsVK::VK_2; +        mSDL2_to_Win[ SDLK_3 ] = (U32)WindowsVK::VK_3; +        mSDL2_to_Win[ SDLK_4 ] = (U32)WindowsVK::VK_4; +        mSDL2_to_Win[ SDLK_5 ] = (U32)WindowsVK::VK_5; +        mSDL2_to_Win[ SDLK_6 ] = (U32)WindowsVK::VK_6; +        mSDL2_to_Win[ SDLK_7 ] = (U32)WindowsVK::VK_7; +        mSDL2_to_Win[ SDLK_8 ] = (U32)WindowsVK::VK_8; +        mSDL2_to_Win[ SDLK_9 ] = (U32)WindowsVK::VK_9; + +        mSDL2_to_Win[ SDLK_SEMICOLON ] = (U32)WindowsVK::VK_OEM_1; +        mSDL2_to_Win[ SDLK_LESS ] = (U32)WindowsVK::VK_OEM_102; +        mSDL2_to_Win[ SDLK_EQUALS ] = (U32)WindowsVK::VK_OEM_PLUS; +        mSDL2_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::VK_OEM_PLUS; + +        mSDL2_to_Win[ SDLK_LEFTBRACKET ] = (U32)WindowsVK::VK_OEM_4; +        mSDL2_to_Win[ SDLK_BACKSLASH ] = (U32)WindowsVK::VK_OEM_5; +        mSDL2_to_Win[ SDLK_RIGHTBRACKET ] = (U32)WindowsVK::VK_OEM_6; +        mSDL2_to_Win[ SDLK_BACKQUOTE ] = (U32)WindowsVK::VK_OEM_8; + +        mSDL2_to_Win[ SDLK_a ] = (U32)WindowsVK::VK_A; +        mSDL2_to_Win[ SDLK_b ] = (U32)WindowsVK::VK_B; +        mSDL2_to_Win[ SDLK_c ] = (U32)WindowsVK::VK_C; +        mSDL2_to_Win[ SDLK_d ] = (U32)WindowsVK::VK_D; +        mSDL2_to_Win[ SDLK_e ] = (U32)WindowsVK::VK_E; +        mSDL2_to_Win[ SDLK_f ] = (U32)WindowsVK::VK_F; +        mSDL2_to_Win[ SDLK_g ] = (U32)WindowsVK::VK_G; +        mSDL2_to_Win[ SDLK_h ] = (U32)WindowsVK::VK_H; +        mSDL2_to_Win[ SDLK_i ] = (U32)WindowsVK::VK_I; +        mSDL2_to_Win[ SDLK_j ] = (U32)WindowsVK::VK_J; +        mSDL2_to_Win[ SDLK_k ] = (U32)WindowsVK::VK_K; +        mSDL2_to_Win[ SDLK_l ] = (U32)WindowsVK::VK_L; +        mSDL2_to_Win[ SDLK_m ] = (U32)WindowsVK::VK_M; +        mSDL2_to_Win[ SDLK_n ] = (U32)WindowsVK::VK_N; +        mSDL2_to_Win[ SDLK_o ] = (U32)WindowsVK::VK_O; +        mSDL2_to_Win[ SDLK_p ] = (U32)WindowsVK::VK_P; +        mSDL2_to_Win[ SDLK_q ] = (U32)WindowsVK::VK_Q; +        mSDL2_to_Win[ SDLK_r ] = (U32)WindowsVK::VK_R; +        mSDL2_to_Win[ SDLK_s ] = (U32)WindowsVK::VK_S; +        mSDL2_to_Win[ SDLK_t ] = (U32)WindowsVK::VK_T; +        mSDL2_to_Win[ SDLK_u ] = (U32)WindowsVK::VK_U; +        mSDL2_to_Win[ SDLK_v ] = (U32)WindowsVK::VK_V; +        mSDL2_to_Win[ SDLK_w ] = (U32)WindowsVK::VK_W; +        mSDL2_to_Win[ SDLK_x ] = (U32)WindowsVK::VK_X; +        mSDL2_to_Win[ SDLK_y ] = (U32)WindowsVK::VK_Y; +        mSDL2_to_Win[ SDLK_z ] = (U32)WindowsVK::VK_Z; + +        mSDL2_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::VK_DELETE; + + +        mSDL2_to_Win[ SDLK_NUMLOCKCLEAR ] = (U32)WindowsVK::VK_NUMLOCK; +        mSDL2_to_Win[ SDLK_SCROLLLOCK ] = (U32)WindowsVK::VK_SCROLL; + +        mSDL2_to_Win[ SDLK_HELP ] = (U32)WindowsVK::VK_HELP; +        mSDL2_to_Win[ SDLK_PRINTSCREEN ] = (U32)WindowsVK::VK_SNAPSHOT; +        mSDL2_to_Win[ SDLK_CANCEL ] = (U32)WindowsVK::VK_CANCEL; +        mSDL2_to_Win[ SDLK_APPLICATION ] = (U32)WindowsVK::VK_APPS; + +        mSDL2_to_Win[ SDLK_UNKNOWN    ] = (U32)WindowsVK::VK_UNKNOWN; +        mSDL2_to_Win[ SDLK_BACKSPACE  ] = (U32)WindowsVK::VK_BACK; +        mSDL2_to_Win[ SDLK_TAB        ] = (U32)WindowsVK::VK_TAB; +        mSDL2_to_Win[ SDLK_CLEAR      ] = (U32)WindowsVK::VK_CLEAR; +        mSDL2_to_Win[ SDLK_RETURN     ] = (U32)WindowsVK::VK_RETURN; +        mSDL2_to_Win[ SDLK_PAUSE      ] = (U32)WindowsVK::VK_PAUSE; +        mSDL2_to_Win[ SDLK_ESCAPE     ] = (U32)WindowsVK::VK_ESCAPE; +        mSDL2_to_Win[ SDLK_DELETE     ] = (U32)WindowsVK::VK_DELETE; + +        mSDL2_to_Win[ SDLK_KP_PERIOD  ] = (U32)WindowsVK::VK_OEM_PERIOD; // VK_DECIMAL? +        mSDL2_to_Win[ SDLK_KP_DIVIDE  ] = (U32)WindowsVK::VK_DIVIDE; +        mSDL2_to_Win[ SDLK_KP_MULTIPLY] = (U32)WindowsVK::VK_MULTIPLY; +        mSDL2_to_Win[ SDLK_KP_MINUS   ] = (U32)WindowsVK::VK_OEM_MINUS; // VK_SUBSTRACT? +        mSDL2_to_Win[ SDLK_KP_PLUS    ] = (U32)WindowsVK::VK_OEM_PLUS;  // VK_ADD? +        mSDL2_to_Win[ SDLK_KP_ENTER   ] = (U32)WindowsVK::VK_RETURN; +        mSDL2_to_Win[ SDLK_KP_0 ] = (U32)WindowsVK::VK_NUMPAD0; +        mSDL2_to_Win[ SDLK_KP_1 ] = (U32)WindowsVK::VK_NUMPAD1; +        mSDL2_to_Win[ SDLK_KP_2 ] = (U32)WindowsVK::VK_NUMPAD2; +        mSDL2_to_Win[ SDLK_KP_3 ] = (U32)WindowsVK::VK_NUMPAD3; +        mSDL2_to_Win[ SDLK_KP_4 ] = (U32)WindowsVK::VK_NUMPAD4; +        mSDL2_to_Win[ SDLK_KP_5 ] = (U32)WindowsVK::VK_NUMPAD5; +        mSDL2_to_Win[ SDLK_KP_6 ] = (U32)WindowsVK::VK_NUMPAD6; +        mSDL2_to_Win[ SDLK_KP_7 ] = (U32)WindowsVK::VK_NUMPAD7; +        mSDL2_to_Win[ SDLK_KP_8 ] = (U32)WindowsVK::VK_NUMPAD8; +        mSDL2_to_Win[ SDLK_KP_9 ] = (U32)WindowsVK::VK_NUMPAD9; + +        // ? + +        mSDL2_to_Win[ SDLK_UP         ] = (U32)WindowsVK::VK_UP; +        mSDL2_to_Win[ SDLK_DOWN       ] = (U32)WindowsVK::VK_DOWN; +        mSDL2_to_Win[ SDLK_RIGHT      ] = (U32)WindowsVK::VK_RIGHT; +        mSDL2_to_Win[ SDLK_LEFT       ] = (U32)WindowsVK::VK_LEFT; +        mSDL2_to_Win[ SDLK_INSERT     ] = (U32)WindowsVK::VK_INSERT; +        mSDL2_to_Win[ SDLK_HOME       ] = (U32)WindowsVK::VK_HOME; +        mSDL2_to_Win[ SDLK_END        ] = (U32)WindowsVK::VK_END; +        mSDL2_to_Win[ SDLK_PAGEUP     ] = (U32)WindowsVK::VK_PRIOR; +        mSDL2_to_Win[ SDLK_PAGEDOWN   ] = (U32)WindowsVK::VK_NEXT; +        mSDL2_to_Win[ SDLK_F1         ] = (U32)WindowsVK::VK_F1; +        mSDL2_to_Win[ SDLK_F2         ] = (U32)WindowsVK::VK_F2; +        mSDL2_to_Win[ SDLK_F3         ] = (U32)WindowsVK::VK_F3; +        mSDL2_to_Win[ SDLK_F4         ] = (U32)WindowsVK::VK_F4; +        mSDL2_to_Win[ SDLK_F5         ] = (U32)WindowsVK::VK_F5; +        mSDL2_to_Win[ SDLK_F6         ] = (U32)WindowsVK::VK_F6; +        mSDL2_to_Win[ SDLK_F7         ] = (U32)WindowsVK::VK_F7; +        mSDL2_to_Win[ SDLK_F8         ] = (U32)WindowsVK::VK_F8; +        mSDL2_to_Win[ SDLK_F9         ] = (U32)WindowsVK::VK_F9; +        mSDL2_to_Win[ SDLK_F10        ] = (U32)WindowsVK::VK_F10; +        mSDL2_to_Win[ SDLK_F11        ] = (U32)WindowsVK::VK_F11; +        mSDL2_to_Win[ SDLK_F12        ] = (U32)WindowsVK::VK_F12; +        mSDL2_to_Win[ SDLK_F13        ] = (U32)WindowsVK::VK_F13; +        mSDL2_to_Win[ SDLK_F14        ] = (U32)WindowsVK::VK_F14; +        mSDL2_to_Win[ SDLK_F15        ] = (U32)WindowsVK::VK_F15; +        mSDL2_to_Win[ SDLK_CAPSLOCK   ] = (U32)WindowsVK::VK_CAPITAL; +        mSDL2_to_Win[ SDLK_RSHIFT     ] = (U32)WindowsVK::VK_SHIFT; +        mSDL2_to_Win[ SDLK_LSHIFT     ] = (U32)WindowsVK::VK_SHIFT; +        mSDL2_to_Win[ SDLK_RCTRL      ] = (U32)WindowsVK::VK_CONTROL; +        mSDL2_to_Win[ SDLK_LCTRL      ] = (U32)WindowsVK::VK_CONTROL; +        mSDL2_to_Win[ SDLK_RALT       ] = (U32)WindowsVK::VK_MENU; +        mSDL2_to_Win[ SDLK_LALT       ] = (U32)WindowsVK::VK_MENU; + +        mSDL2_to_Win[ SDLK_MENU       ] = (U32)WindowsVK::VK_MENU; + +        // VK_MODECHANGE ? +        // mSDL2_to_Win[ SDLK_MODE       ] = (U32)WindowsVK::VK_MODE; + +        // ? +        // mSDL2_to_Win[ SDLK_SYSREQ     ] = (U32)WindowsVK::VK_SYSREQ; +        // mSDL2_to_Win[ SDLK_POWER      ] = (U32)WindowsVK::VK_POWER; +        // mSDL2_to_Win[ SDLK_UNDO       ] = (U32)WindowsVK::VK_UNDO; +        // mSDL2_to_Win[ SDLK_KP_EQUALS  ] = (U32)WindowsVK::VK_EQUALS; +        // mSDL2_to_Win[ 311 ] = (U32)WindowsVK::VK_LWIN; +        // mSDL2_to_Win[ 312 ] = (U32)WindowsVK::VK_RWIN; +        // mSDL2_to_Win[ SDLK_COLON ] = ? +    } +    auto itr = mSDL2_to_Win.find( aSymbol ); +    if( itr != mSDL2_to_Win.end() ) +        return itr->second; + +    return aSymbol; +} diff --git a/indra/llwindow/llkeyboardsdl.h b/indra/llwindow/llkeyboardsdl.h index 620f83e9b4..727bac2690 100644 --- a/indra/llwindow/llkeyboardsdl.h +++ b/indra/llwindow/llkeyboardsdl.h @@ -1,8 +1,7 @@  /** - * @file llkeyboardsdl.h - * @brief Handler for assignable key bindings + * @author This module has many fathers, and it shows.   * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * $LicenseInfo:firstyear=2001&license=viewerlgpl$   * Second Life Viewer Source Code   * Copyright (C) 2010, Linden Research, Inc.   * @@ -24,11 +23,11 @@   * $/LicenseInfo$   */ -#ifndef LL_LLKEYBOARDSDL_H -#define LL_LLKEYBOARDSDL_H +#ifndef LL_LLKEYBOARDSDL2_H +#define LL_LLKEYBOARDSDL2_H  #include "llkeyboard.h" -#include "SDL/SDL.h" +#include "SDL2/SDL.h"  class LLKeyboardSDL : public LLKeyboard  { @@ -36,8 +35,8 @@ public:      LLKeyboardSDL();      /*virtual*/ ~LLKeyboardSDL() {}; -    /*virtual*/ BOOL    handleKeyUp(const U16 key, MASK mask); -    /*virtual*/ BOOL    handleKeyDown(const U16 key, MASK mask); +    /*virtual*/ BOOL    handleKeyUp(const U32 key, MASK mask); +    /*virtual*/ BOOL    handleKeyDown(const U32 key, MASK mask);      /*virtual*/ void    resetMaskKeys();      /*virtual*/ MASK    currentMask(BOOL for_mouse_event);      /*virtual*/ void    scanKeyboard(); @@ -45,11 +44,14 @@ public:  protected:      MASK    updateModifiers(const U32 mask);      void    setModifierKeyLevel( KEY key, BOOL new_state ); -    BOOL    translateNumpadKey( const U16 os_key, KEY *translated_key ); +    BOOL    translateNumpadKey( const U32 os_key, KEY *translated_key );      U16 inverseTranslateNumpadKey(const KEY translated_key);  private: -    std::map<U16, KEY> mTranslateNumpadMap;  // special map for translating OS keys to numpad keys -    std::map<KEY, U16> mInvTranslateNumpadMap; // inverse of the above +    std::map<U32, KEY> mTranslateNumpadMap;  // special map for translating OS keys to numpad keys +    std::map<KEY, U32> mInvTranslateNumpadMap; // inverse of the above + +public: +    static U32 mapSDL2toWin( U32 );  };  #endif diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index df8b2ba5ab..218f953c7f 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -25,8 +25,6 @@   * $/LicenseInfo$   */ -#if LL_SDL -  #include "linden_common.h"  #include "llwindowsdl.h" @@ -40,12 +38,9 @@  #include "lldir.h"  #include "llfindlocale.h" -#if LL_GTK -extern "C" { -# include "gtk/gtk.h" -} -#include <locale.h> -#endif // LL_GTK +#ifdef LL_GLIB +#include <glib.h> +#endif  extern "C" {  # include "fontconfig/fontconfig.h" @@ -57,6 +52,7 @@ extern "C" {  # include <unistd.h>  # include <sys/types.h>  # include <sys/wait.h> +# include <stdio.h>  #endif // LL_LINUX  extern BOOL gDebugWindowProc; @@ -97,100 +93,278 @@ void maybe_unlock_display(void)  } -#if LL_GTK -// Lazily initialize and check the runtime GTK version for goodness. +#if LL_X11  // static -bool LLWindowSDL::ll_try_gtk_init(void) +Window LLWindowSDL::get_SDL_XWindowID(void)  { -    static BOOL done_gtk_diag = FALSE; -    static BOOL gtk_is_good = FALSE; -    static BOOL done_setlocale = FALSE; -    static BOOL tried_gtk_init = FALSE; +    if (gWindowImplementation) { +        return gWindowImplementation->mSDL_XWindowID; +    } +    return None; +} -    if (!done_setlocale) +//static +Display* LLWindowSDL::get_SDL_Display(void) +{ +    if (gWindowImplementation) { +        return gWindowImplementation->mSDL_Display; +    } +    return NULL; +} +#endif // LL_X11 + +#if LL_X11 + +// Clipboard handing via native X11, base on the implementation in Cool VL by Henri Beauchamp + +namespace +{ +    std::array<Atom, 3> gSupportedAtoms; + +    Atom XA_CLIPBOARD; +    Atom XA_TARGETS; +    Atom PVT_PASTE_BUFFER; +    long const MAX_PASTE_BUFFER_SIZE = 16383; + +    void filterSelectionRequest( XEvent aEvent )      { -        LL_INFOS() << "Starting GTK Initialization." << LL_ENDL; -        maybe_lock_display(); -        gtk_disable_setlocale(); -        maybe_unlock_display(); -        done_setlocale = TRUE; +        auto *display = LLWindowSDL::getSDLDisplay(); +        auto &request = aEvent.xselectionrequest; + +        XSelectionEvent reply { SelectionNotify, aEvent.xany.serial, aEvent.xany.send_event, display, +                                request.requestor, request.selection, request.target, +                                request.property,request.time }; + +        if (request.target == XA_TARGETS) +        { +            XChangeProperty(display, request.requestor, request.property, +                            XA_ATOM, 32, PropModeReplace, +                            (unsigned char *) &gSupportedAtoms.front(), gSupportedAtoms.size()); +        } +        else if (std::find(gSupportedAtoms.begin(), gSupportedAtoms.end(), request.target) != +                 gSupportedAtoms.end()) +        { +            std::string utf8; +            if (request.selection == XA_PRIMARY) +                utf8 = wstring_to_utf8str(gWindowImplementation->getPrimaryText()); +            else +                utf8 = wstring_to_utf8str(gWindowImplementation->getSecondaryText()); + +            XChangeProperty(display, request.requestor, request.property, +                            request.target, 8, PropModeReplace, +                            (unsigned char *) utf8.c_str(), utf8.length()); +        } +        else if (request.selection == XA_CLIPBOARD) +        { +            // Did not have what they wanted, so no property set +            reply.property = None; +        } +        else +            return; + +        XSendEvent(request.display, request.requestor, False, NoEventMask, (XEvent *) &reply); +        XSync(display, False);      } -    if (!tried_gtk_init) +    void filterSelectionClearRequest( XEvent aEvent )      { -        tried_gtk_init = TRUE; -        if (!g_thread_supported ()) g_thread_init (NULL); -        maybe_lock_display(); -        gtk_is_good = gtk_init_check(NULL, NULL); -        maybe_unlock_display(); -        if (!gtk_is_good) -            LL_WARNS() << "GTK Initialization failed." << LL_ENDL; +        auto &request = aEvent.xselectionrequest; +        if (request.selection == XA_PRIMARY) +            gWindowImplementation->clearPrimaryText(); +        else if (request.selection == XA_CLIPBOARD) +            gWindowImplementation->clearSecondaryText(); +    } + +    int x11_clipboard_filter(void*, SDL_Event *evt) +    { +        Display *display = LLWindowSDL::getSDLDisplay(); +        if (!display) +            return 1; + +        if (evt->type != SDL_SYSWMEVENT) +            return 1; + +        auto xevent = evt->syswm.msg->msg.x11.event; + +        if (xevent.type == SelectionRequest) +            filterSelectionRequest( xevent ); +        else if (xevent.type == SelectionClear) +            filterSelectionClearRequest( xevent ); +        return 1;      } -    if (gtk_is_good && !done_gtk_diag) +    bool grab_property(Display* display, Window window, Atom selection, Atom target)      { -        LL_INFOS() << "GTK Initialized." << LL_ENDL; -        LL_INFOS() << "- Compiled against GTK version " -            << GTK_MAJOR_VERSION << "." -            << GTK_MINOR_VERSION << "." -            << GTK_MICRO_VERSION << LL_ENDL; -        LL_INFOS() << "- Running against GTK version " -            << gtk_major_version << "." -            << gtk_minor_version << "." -            << gtk_micro_version << LL_ENDL; +        if( !display ) +            return false; +          maybe_lock_display(); -        const gchar* gtk_warning = gtk_check_version( -            GTK_MAJOR_VERSION, -            GTK_MINOR_VERSION, -            GTK_MICRO_VERSION); + +        XDeleteProperty(display, window, PVT_PASTE_BUFFER); +        XFlush(display); + +        XConvertSelection(display, selection, target, PVT_PASTE_BUFFER, window,  CurrentTime); + +        // Unlock the connection so that the SDL event loop may function          maybe_unlock_display(); -        if (gtk_warning) + +        const auto start{ SDL_GetTicks() }; +        const auto end{ start + 1000 }; + +        XEvent xevent {}; +        bool response = false; + +        do          { -            LL_WARNS() << "- GTK COMPATIBILITY WARNING: " << -                gtk_warning << LL_ENDL; -            gtk_is_good = FALSE; -        } else { -            LL_INFOS() << "- GTK version is good." << LL_ENDL; -        } +            SDL_Event event {}; + +            // Wait for an event +            SDL_WaitEvent(&event); + +            // If the event is a window manager event +            if (event.type == SDL_SYSWMEVENT) +            { +                xevent = event.syswm.msg->msg.x11.event; -        done_gtk_diag = TRUE; +                if (xevent.type == SelectionNotify && xevent.xselection.requestor == window) +                    response = true; +            } +        } while (!response && SDL_GetTicks() < end ); + +        return response && xevent.xselection.property != None;      } +} + +void LLWindowSDL::initialiseX11Clipboard() +{ +    if (!mSDL_Display) +        return; -    return gtk_is_good; +    SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); +    SDL_SetEventFilter(x11_clipboard_filter, nullptr); + +    maybe_lock_display(); + +    XA_CLIPBOARD = XInternAtom(mSDL_Display, "CLIPBOARD", False); + +    gSupportedAtoms[0] = XInternAtom(mSDL_Display, "UTF8_STRING", False); +    gSupportedAtoms[1] = XInternAtom(mSDL_Display, "COMPOUND_TEXT", False); +    gSupportedAtoms[2] = XA_STRING; + +    // TARGETS atom +    XA_TARGETS = XInternAtom(mSDL_Display, "TARGETS", False); + +    // SL_PASTE_BUFFER atom +    PVT_PASTE_BUFFER = XInternAtom(mSDL_Display, "FS_PASTE_BUFFER", False); + +    maybe_unlock_display();  } -#endif // LL_GTK +bool LLWindowSDL::getSelectionText( Atom aSelection, Atom aType, LLWString &text ) +{ +    if( !mSDL_Display ) +        return false; + +    if( !grab_property(mSDL_Display, mSDL_XWindowID, aSelection,aType ) ) +        return false; -#if LL_X11 -// static -Window LLWindowSDL::get_SDL_XWindowID(void) +    maybe_lock_display(); + +    Atom type; +    int format{}; +    unsigned long len{},remaining {}; +    unsigned char* data = nullptr; +    int res = XGetWindowProperty(mSDL_Display, mSDL_XWindowID, +                                 PVT_PASTE_BUFFER, 0, MAX_PASTE_BUFFER_SIZE, False, +                                 AnyPropertyType, &type, &format, &len, +                                 &remaining, &data); +    if (data && len) +    { +        text = LLWString( +                utf8str_to_wstring(reinterpret_cast< char const *>( data ) ) +        ); +        XFree(data); +    } + +    maybe_unlock_display(); +    return res == Success; +} + +bool LLWindowSDL::getSelectionText(Atom selection, LLWString& text)  { -    if (gWindowImplementation) { -        return gWindowImplementation->mSDL_XWindowID; +    if (!mSDL_Display) +        return false; + +    maybe_lock_display(); + +    Window owner = XGetSelectionOwner(mSDL_Display, selection); +    if (owner == None) +    { +        if (selection == XA_PRIMARY) +        { +            owner = DefaultRootWindow(mSDL_Display); +            selection = XA_CUT_BUFFER0; +        } +        else +        { +            maybe_unlock_display(); +            return false; +        }      } -    return None; + +    maybe_unlock_display(); + +    for( Atom atom : gSupportedAtoms ) +    { +        if(getSelectionText(selection, atom, text ) ) +            return true; +    } + +    return false;  } -//static -Display* LLWindowSDL::get_SDL_Display(void) +bool LLWindowSDL::setSelectionText(Atom selection, const LLWString& text)  { -    if (gWindowImplementation) { -        return gWindowImplementation->mSDL_Display; +    maybe_lock_display(); + +    if (selection == XA_PRIMARY) +    { +        std::string utf8 = wstring_to_utf8str(text); +        XStoreBytes(mSDL_Display, utf8.c_str(), utf8.length() + 1); +        mPrimaryClipboard = text;      } -    return NULL; +    else +        mSecondaryClipboard = text; + +    XSetSelectionOwner(mSDL_Display, selection, mSDL_XWindowID, CurrentTime); + +    auto owner = XGetSelectionOwner(mSDL_Display, selection); + +    maybe_unlock_display(); + +    return owner == mSDL_XWindowID; +} + +Display* LLWindowSDL::getSDLDisplay() +{ +    if (gWindowImplementation) +        return gWindowImplementation->mSDL_Display; +    return nullptr;  } -#endif // LL_X11 + +#endif  LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, -             const std::string& title, S32 x, S32 y, S32 width, -             S32 height, U32 flags, -             BOOL fullscreen, BOOL clearBg, -             BOOL disable_vsync, BOOL use_gl, -             BOOL ignore_pixel_depth, U32 fsaa_samples) -    : LLWindow(callbacks, fullscreen, flags), -      Lock_Display(NULL), -      Unlock_Display(NULL), mGamma(1.0f) +                         const std::string& title, S32 x, S32 y, S32 width, +                         S32 height, U32 flags, +                         BOOL fullscreen, BOOL clearBg, +                         BOOL disable_vsync, BOOL use_gl, +                         BOOL ignore_pixel_depth, U32 fsaa_samples) +        : LLWindow(callbacks, fullscreen, flags), +        Lock_Display(NULL), +        //Unlock_Display(NULL), mGamma(1.0f) +        Unlock_Display(NULL), mGamma(1.0f)  {      // Initialize the keyboard      gKeyboard = new LLKeyboardSDL(); @@ -199,6 +373,7 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks,      // Ignore use_gl for now, only used for drones on PC      mWindow = NULL; +    mContext = {};      mNeedsResize = FALSE;      mOverrideAspectRatio = 0.f;      mGrabbyKeyFlags = 0; @@ -212,13 +387,6 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks,      mSDL_Display = NULL;  #endif // LL_X11 -#if LL_GTK -    // We MUST be the first to initialize GTK so that GTK doesn't get badly -    // initialized with a non-C locale and cause lots of serious random -    // weirdness. -    ll_try_gtk_init(); -#endif // LL_GTK -      // Assume 4:3 aspect ratio until we know better      mOriginalAspectRatio = 1024.0 / 768.0; @@ -244,9 +412,9 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks,  #if LL_X11      mFlashing = FALSE; +    initialiseX11Clipboard();  #endif // LL_X11 -    mKeyScanCode = 0;      mKeyVirtualKey = 0;      mKeyModifiers = KMOD_NONE;  } @@ -258,10 +426,10 @@ static SDL_Surface *Load_BMP_Resource(const char *basename)      // Figure out where our BMP is living on the disk      snprintf(path_buffer, PATH_BUFFER_SIZE-1, "%s%sres-sdl%s%s", -         gDirUtilp->getAppRODataDir().c_str(), -         gDirUtilp->getDirDelimiter().c_str(), -         gDirUtilp->getDirDelimiter().c_str(), -         basename); +             gDirUtilp->getAppRODataDir().c_str(), +             gDirUtilp->getDirDelimiter().c_str(), +             gDirUtilp->getDirDelimiter().c_str(), +             basename);      path_buffer[PATH_BUFFER_SIZE-1] = '\0';      return SDL_LoadBMP(path_buffer); @@ -348,7 +516,7 @@ static int x11_detect_VRAM_kb()      if (fp)      {          LL_INFOS() << "Looking in " << fname -            << " for VRAM info..." << LL_ENDL; +                   << " for VRAM info..." << LL_ENDL;          rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: ");          fclose(fp);          if (0 == rtn) @@ -373,7 +541,7 @@ static int x11_detect_VRAM_kb()      else      {          LL_INFOS() << "Could not open " << fname -            << " - skipped." << LL_ENDL; +                   << " - skipped." << LL_ENDL;          // Try old XFree86 log otherwise          fname = x_log_location;          fname += "XFree86."; @@ -383,7 +551,7 @@ static int x11_detect_VRAM_kb()          if (fp)          {              LL_INFOS() << "Looking in " << fname -                << " for VRAM info..." << LL_ENDL; +                       << " for VRAM info..." << LL_ENDL;              rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: ");              fclose(fp);              if (0 == rtn) @@ -399,95 +567,160 @@ static int x11_detect_VRAM_kb()          else          {              LL_INFOS() << "Could not open " << fname -                << " - skipped." << LL_ENDL; +                       << " - skipped." << LL_ENDL;          }      }      return rtn;  }  #endif // LL_X11 +void LLWindowSDL::setTitle(const std::string title) +{ +    SDL_SetWindowTitle( mWindow, title.c_str() ); +} + +void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) +{ +    LL_INFOS() << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL; + +    // If the requested width or height is 0, find the best default for the monitor. +    if((width == 0) || (height == 0)) +    { +        // Scan through the list of modes, looking for one which has: +        //      height between 700 and 800 +        //      aspect ratio closest to the user's original mode +        S32 resolutionCount = 0; +        LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount); + +        if(resolutionList != NULL) +        { +            F32 closestAspect = 0; +            U32 closestHeight = 0; +            U32 closestWidth = 0; +            int i; + +            LL_INFOS() << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << LL_ENDL; + +            for(i=0; i < resolutionCount; i++) +            { +                F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight; + +                LL_INFOS() << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << LL_ENDL; + +                if( (resolutionList[i].mHeight >= 700) && (resolutionList[i].mHeight <= 800) && +                    (fabs(aspect - mOriginalAspectRatio) < fabs(closestAspect - mOriginalAspectRatio))) +                { +                    LL_INFOS() << " (new closest mode) " << LL_ENDL; + +                    // This is the closest mode we've seen yet. +                    closestWidth = resolutionList[i].mWidth; +                    closestHeight = resolutionList[i].mHeight; +                    closestAspect = aspect; +                } +            } + +            width = closestWidth; +            height = closestHeight; +        } +    } + +    if((width == 0) || (height == 0)) +    { +        // Mode search failed for some reason.  Use the old-school default. +        width = 1024; +        height = 768; +    } +} +  BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync)  {      //bool          glneedsinit = false;      LL_INFOS() << "createContext, fullscreen=" << fullscreen << -        " size=" << width << "x" << height << LL_ENDL; +               " size=" << width << "x" << height << LL_ENDL;      // captures don't survive contexts      mGrabbyKeyFlags = 0;      mReallyCapturedCount = 0; -    if (SDL_Init(SDL_INIT_VIDEO) < 0) +    std::initializer_list<std::tuple< char const*, char const * > > hintList = +            { +                    {SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR,"0"}, +                    {SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH,"1"}, +                    {SDL_HINT_IME_INTERNAL_EDITING,"1"} +            }; + +    for( auto hint: hintList )      { -        LL_INFOS() << "sdl_init() failed! " << SDL_GetError() << LL_ENDL; -        setupFailure("sdl_init() failure,  window creation error", "error", OSMB_OK); -        return false; +        SDL_SetHint( std::get<0>(hint), std::get<1>(hint)); +    } + +    std::initializer_list<std::tuple<uint32_t, char const*, bool>> initList= +            { {SDL_INIT_VIDEO,"SDL_INIT_VIDEO", true}, +              {SDL_INIT_AUDIO,"SDL_INIT_AUDIO", false}, +              {SDL_INIT_GAMECONTROLLER,"SDL_INIT_GAMECONTROLLER", false}, +              {SDL_INIT_SENSOR,"SDL_INIT_SENSOR", false} +            }; + +    for( auto subSystem : initList) +    { +        if( SDL_InitSubSystem( std::get<0>(subSystem) ) < 0 ) +        { +            LL_WARNS() << "SDL_InitSubSystem for " << std::get<1>(subSystem) << " failed " << SDL_GetError() << LL_ENDL; + +            if( std::get<2>(subSystem)) +                setupFailure("SDL_Init() failure", "error", OSMB_OK); + +        }      }      SDL_version c_sdl_version;      SDL_VERSION(&c_sdl_version);      LL_INFOS() << "Compiled against SDL " -        << int(c_sdl_version.major) << "." -        << int(c_sdl_version.minor) << "." -        << int(c_sdl_version.patch) << LL_ENDL; -    const SDL_version *r_sdl_version; -    r_sdl_version = SDL_Linked_Version(); +               << int(c_sdl_version.major) << "." +               << int(c_sdl_version.minor) << "." +               << int(c_sdl_version.patch) << LL_ENDL; +    SDL_version r_sdl_version; +    SDL_GetVersion(&r_sdl_version);      LL_INFOS() << " Running against SDL " -        << int(r_sdl_version->major) << "." -        << int(r_sdl_version->minor) << "." -        << int(r_sdl_version->patch) << LL_ENDL; +               << int(r_sdl_version.major) << "." +               << int(r_sdl_version.minor) << "." +               << int(r_sdl_version.patch) << LL_ENDL; -    const SDL_VideoInfo *video_info = SDL_GetVideoInfo( ); -    if (!video_info) -    { -        LL_INFOS() << "SDL_GetVideoInfo() failed! " << SDL_GetError() << LL_ENDL; -        setupFailure("SDL_GetVideoInfo() failed, Window creation error", "Error", OSMB_OK); -        return FALSE; -    } +    if (width == 0) +        width = 1024; +    if (height == 0) +        width = 768; -    if (video_info->current_h > 0) -    { -        mOriginalAspectRatio = (float)video_info->current_w / (float)video_info->current_h; -        LL_INFOS() << "Original aspect ratio was " << video_info->current_w << ":" << video_info->current_h << "=" << mOriginalAspectRatio << LL_ENDL; -    } +    mFullscreen = fullscreen; -    SDL_EnableUNICODE(1); -    SDL_WM_SetCaption(mWindowTitle.c_str(), mWindowTitle.c_str()); +    int sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; -    // Set the application icon. -    SDL_Surface *bmpsurface; -    bmpsurface = Load_BMP_Resource("ll_icon.BMP"); -    if (bmpsurface) +    if( mFullscreen )      { -        // This attempts to give a black-keyed mask to the icon. -        SDL_SetColorKey(bmpsurface, -                SDL_SRCCOLORKEY, -                SDL_MapRGB(bmpsurface->format, 0,0,0) ); -        SDL_WM_SetIcon(bmpsurface, NULL); -        // The SDL examples cheerfully avoid freeing the icon -        // surface, but I'm betting that's leaky. -        SDL_FreeSurface(bmpsurface); -        bmpsurface = NULL; +        sdlflags |= SDL_WINDOW_FULLSCREEN; +        tryFindFullscreenSize( width, height );      } -    // note: these SetAttributes make Tom's 9600-on-AMD64 fail to -    // get a visual, but it's broken anyway when it does, and without -    // these SetAttributes we might easily get an avoidable substandard -    // visual to work with on most other machines. -    SDL_GL_SetAttribute(SDL_GL_RED_SIZE,  8); -    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8); -    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); -    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, (bits <= 16) ? 16 : 24); -    // We need stencil support for a few (minor) things. -    if (!getenv("LL_GL_NO_STENCIL")) -        SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); -        SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, (bits <= 16) ? 1 : 8); +    mSDLFlags = sdlflags; -        // *FIX: try to toggle vsync here? +    GLint redBits{8}, greenBits{8}, blueBits{8}, alphaBits{8}; -    mFullscreen = fullscreen; +    GLint depthBits{(bits <= 16) ? 16 : 24}, stencilBits{8}; -    int sdlflags = SDL_OPENGL | SDL_RESIZABLE | SDL_ANYFORMAT; +    if (getenv("LL_GL_NO_STENCIL")) +        stencilBits = 0; + +    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, alphaBits); +    SDL_GL_SetAttribute(SDL_GL_RED_SIZE,   redBits); +    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, greenBits); +    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,  blueBits); +    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depthBits ); + +    // We need stencil support for a few (minor) things. +    if (stencilBits) +        SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, stencilBits); +    // *FIX: try to toggle vsync here?      SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); @@ -497,80 +730,39 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B          SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, mFSAASamples);      } -        mSDLFlags = sdlflags; +    SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); +    mWindow = SDL_CreateWindow( mWindowTitle.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, mSDLFlags ); -    if (mFullscreen) +    if( mWindow )      { -        LL_INFOS() << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL; - -        // If the requested width or height is 0, find the best default for the monitor. -        if((width == 0) || (height == 0)) -        { -            // Scan through the list of modes, looking for one which has: -            //      height between 700 and 800 -            //      aspect ratio closest to the user's original mode -            S32 resolutionCount = 0; -            LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount); - -            if(resolutionList != NULL) -            { -                F32 closestAspect = 0; -                U32 closestHeight = 0; -                U32 closestWidth = 0; -                int i; - -                LL_INFOS() << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << LL_ENDL; - -                for(i=0; i < resolutionCount; i++) -                { -                    F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight; - -                    LL_INFOS() << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << LL_ENDL; - -                    if( (resolutionList[i].mHeight >= 700) && (resolutionList[i].mHeight <= 800) && -                        (fabs(aspect - mOriginalAspectRatio) < fabs(closestAspect - mOriginalAspectRatio))) -                    { -                        LL_INFOS() << " (new closest mode) " << LL_ENDL; - -                        // This is the closest mode we've seen yet. -                        closestWidth = resolutionList[i].mWidth; -                        closestHeight = resolutionList[i].mHeight; -                        closestAspect = aspect; -                    } -                } - -                width = closestWidth; -                height = closestHeight; -            } -        } +        mContext = SDL_GL_CreateContext( mWindow ); -        if((width == 0) || (height == 0)) +        if( mContext == 0 )          { -            // Mode search failed for some reason.  Use the old-school default. -            width = 1024; -            height = 768; +            LL_WARNS() << "Cannot create GL context " << SDL_GetError() << LL_ENDL; +            setupFailure("GL Context creation error creation error", "Error", OSMB_OK); +            return FALSE;          } +        // SDL_GL_SetSwapInterval(1); +        mSurface = SDL_GetWindowSurface( mWindow ); +    } -        mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN); -        if (!mWindow && bits > 16) -        { -            SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); -            mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN); -        } -        if (mWindow) +    if( mFullscreen ) +    { +        if (mSurface)          {              mFullscreen = TRUE; -            mFullscreenWidth   = mWindow->w; -            mFullscreenHeight  = mWindow->h; -            mFullscreenBits    = mWindow->format->BitsPerPixel; +            mFullscreenWidth = mSurface->w; +            mFullscreenHeight = mSurface->h; +            mFullscreenBits    = mSurface->format->BitsPerPixel;              mFullscreenRefresh = -1;              LL_INFOS() << "Running at " << mFullscreenWidth -                << "x"   << mFullscreenHeight -                << "x"   << mFullscreenBits -                << " @ " << mFullscreenRefresh -                << LL_ENDL; +                       << "x"   << mFullscreenHeight +                       << "x"   << mFullscreenBits +                       << " @ " << mFullscreenRefresh +                       << LL_ENDL;          }          else          { @@ -584,33 +776,27 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B              std::string error = llformat("Unable to run fullscreen at %d x %d.\nRunning in window.", width, height);              OSMessageBox(error, "Error", OSMB_OK); +            return FALSE;          }      } - -    if(!mFullscreen && (mWindow == NULL)) +    else      { -        if (width == 0) -            width = 1024; -        if (height == 0) -            width = 768; - -        LL_INFOS() << "createContext: creating window " << width << "x" << height << "x" << bits << LL_ENDL; -        mWindow = SDL_SetVideoMode(width, height, bits, sdlflags); -        if (!mWindow && bits > 16) -        { -            SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); -            mWindow = SDL_SetVideoMode(width, height, bits, sdlflags); -        } -          if (!mWindow)          {              LL_WARNS() << "createContext: window creation failure. SDL: " << SDL_GetError() << LL_ENDL;              setupFailure("Window creation error", "Error", OSMB_OK);              return FALSE;          } -    } else if (!mFullscreen && (mWindow != NULL)) +    } + +    // Set the application icon. +    SDL_Surface *bmpsurface; +    bmpsurface = Load_BMP_Resource("ll_icon.BMP"); +    if (bmpsurface)      { -        LL_INFOS() << "createContext: SKIPPING - !fullscreen, but +mWindow " << width << "x" << height << "x" << bits << LL_ENDL; +        SDL_SetWindowIcon(mWindow, bmpsurface); +        SDL_FreeSurface(bmpsurface); +        bmpsurface = NULL;      }      // Detect video memory size. @@ -625,7 +811,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B          // fallback to letting SDL detect VRAM.          // note: I've not seen SDL's detection ever actually find          // VRAM != 0, but if SDL *does* detect it then that's a bonus. -        gGLManager.mVRAM = video_info->video_mem / 1024; +        gGLManager.mVRAM = 0;          if (gGLManager.mVRAM != 0)          {              LL_INFOS() << "SDL detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; @@ -637,22 +823,20 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B      // explicitly unsupported cards.      //const char* RENDERER = (const char*) glGetString(GL_RENDERER); -    GLint depthBits, stencilBits, redBits, greenBits, blueBits, alphaBits; - -    glGetIntegerv(GL_RED_BITS, &redBits); -    glGetIntegerv(GL_GREEN_BITS, &greenBits); -    glGetIntegerv(GL_BLUE_BITS, &blueBits); -    glGetIntegerv(GL_ALPHA_BITS, &alphaBits); -    glGetIntegerv(GL_DEPTH_BITS, &depthBits); -    glGetIntegerv(GL_STENCIL_BITS, &stencilBits); +    SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &redBits); +    SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &greenBits); +    SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &blueBits); +    SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &alphaBits); +    SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depthBits); +    SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencilBits);      LL_INFOS() << "GL buffer:" << LL_ENDL; -        LL_INFOS() << "  Red Bits " << S32(redBits) << LL_ENDL; -        LL_INFOS() << "  Green Bits " << S32(greenBits) << LL_ENDL; -        LL_INFOS() << "  Blue Bits " << S32(blueBits) << LL_ENDL; -    LL_INFOS()  << "  Alpha Bits " << S32(alphaBits) << LL_ENDL; -    LL_INFOS()  << "  Depth Bits " << S32(depthBits) << LL_ENDL; -    LL_INFOS()  << "  Stencil Bits " << S32(stencilBits) << LL_ENDL; +    LL_INFOS() << "  Red Bits " << S32(redBits) << LL_ENDL; +    LL_INFOS() << "  Green Bits " << S32(greenBits) << LL_ENDL; +    LL_INFOS() << "  Blue Bits " << S32(blueBits) << LL_ENDL; +    LL_INFOS() << "  Alpha Bits " << S32(alphaBits) << LL_ENDL; +    LL_INFOS() << "  Depth Bits " << S32(depthBits) << LL_ENDL; +    LL_INFOS() << "  Stencil Bits " << S32(stencilBits) << LL_ENDL;      GLint colorBits = redBits + greenBits + blueBits + alphaBits;      // fixme: actually, it's REALLY important for picking that we get at @@ -662,69 +846,46 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B      {          close();          setupFailure( -            "Second Life requires True Color (32-bit) to run in a window.\n" -            "Please go to Control Panels -> Display -> Settings and\n" -            "set the screen to 32-bit color.\n" -            "Alternately, if you choose to run fullscreen, Second Life\n" -            "will automatically adjust the screen each time it runs.", -            "Error", -            OSMB_OK); -        return FALSE; -    } - -#if 0  // *FIX: we're going to brave it for now... -    if (alphaBits < 8) -    { -        close(); -        setupFailure( -            "Second Life is unable to run because it can't get an 8 bit alpha\n" -            "channel.  Usually this is due to video card driver issues.\n" -            "Please make sure you have the latest video card drivers installed.\n" -            "Also be sure your monitor is set to True Color (32-bit) in\n" -            "Control Panels -> Display -> Settings.\n" -            "If you continue to receive this message, contact customer service.", -            "Error", -            OSMB_OK); +                "Second Life requires True Color (32-bit) to run in a window.\n" +                "Please go to Control Panels -> Display -> Settings and\n" +                "set the screen to 32-bit color.\n" +                "Alternately, if you choose to run fullscreen, Second Life\n" +                "will automatically adjust the screen each time it runs.", +                "Error", +                OSMB_OK);          return FALSE;      } -#endif  #if LL_X11      /* Grab the window manager specific information */      SDL_SysWMinfo info;      SDL_VERSION(&info.version); -    if ( SDL_GetWMInfo(&info) ) +    if ( SDL_GetWindowWMInfo(mWindow, &info) )      {          /* Save the information for later use */          if ( info.subsystem == SDL_SYSWM_X11 )          {              mSDL_Display = info.info.x11.display; -            mSDL_XWindowID = info.info.x11.wmwindow; -            Lock_Display = info.info.x11.lock_func; -            Unlock_Display = info.info.x11.unlock_func; +            mSDL_XWindowID = info.info.x11.window;          }          else          {              LL_WARNS() << "We're not running under X11?  Wild." -                << LL_ENDL; +                       << LL_ENDL;          }      }      else      {          LL_WARNS() << "We're not running under any known WM.  Wild." -            << LL_ENDL; +                   << LL_ENDL;      }  #endif // LL_X11 +    SDL_StartTextInput();      //make sure multisampling is disabled by default      glDisable(GL_MULTISAMPLE_ARB); -    // We need to do this here, once video is init'd -    if (-1 == SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, -                      SDL_DEFAULT_REPEAT_INTERVAL)) -        LL_WARNS() << "Couldn't enable key-repeat: " << SDL_GetError() <<LL_ENDL; -      // Don't need to get the current gamma, since there's a call that restores it to the system defaults.      return TRUE;  } @@ -761,6 +922,7 @@ void LLWindowSDL::destroyContext()  {      LL_INFOS() << "destroyContext begins" << LL_ENDL; +    SDL_StopTextInput();  #if LL_X11      mSDL_Display = NULL;      mSDL_XWindowID = None; @@ -894,11 +1056,11 @@ BOOL LLWindowSDL::getPosition(LLCoordScreen *position)  BOOL LLWindowSDL::getSize(LLCoordScreen *size)  { -    if (mWindow) +    if (mSurface)      { -        size->mX = mWindow->w; -        size->mY = mWindow->h; -    return (TRUE); +        size->mX = mSurface->w; +        size->mY = mSurface->h; +        return (TRUE);      }      return (FALSE); @@ -906,11 +1068,11 @@ BOOL LLWindowSDL::getSize(LLCoordScreen *size)  BOOL LLWindowSDL::getSize(LLCoordWindow *size)  { -    if (mWindow) +    if (mSurface)      { -        size->mX = mWindow->w; -        size->mY = mWindow->h; -    return (TRUE); +        size->mX = mSurface->w; +        size->mY = mSurface->h; +        return (TRUE);      }      return (FALSE); @@ -927,40 +1089,37 @@ BOOL LLWindowSDL::setPosition(const LLCoordScreen position)      return TRUE;  } -BOOL LLWindowSDL::setSizeImpl(const LLCoordScreen size) +template< typename T > bool setSizeImpl( const T& newSize, SDL_Window *pWin )  { -    if(mWindow) -    { -        // Push a resize event onto SDL's queue - we'll handle it -        // when it comes out again. -        SDL_Event event; -        event.type = SDL_VIDEORESIZE; -        event.resize.w = size.mX; -        event.resize.h = size.mY; -        SDL_PushEvent(&event); // copied into queue +    if( !pWin ) +        return false; -        return TRUE; -    } +    auto nFlags = SDL_GetWindowFlags( pWin ); -    return FALSE; +    if( nFlags & SDL_WINDOW_MAXIMIZED ) +        SDL_RestoreWindow( pWin ); + + +    SDL_SetWindowSize( pWin, newSize.mX, newSize.mY ); +    SDL_Event event; +    event.type = SDL_WINDOWEVENT; +    event.window.event = SDL_WINDOWEVENT_RESIZED; +    event.window.windowID = SDL_GetWindowID( pWin ); +    event.window.data1 = newSize.mX; +    event.window.data2 = newSize.mY; +    SDL_PushEvent( &event ); + +    return true;  } -BOOL LLWindowSDL::setSizeImpl(const LLCoordWindow size) +BOOL LLWindowSDL::setSizeImpl(const LLCoordScreen size)  { -    if(mWindow) -    { -        // Push a resize event onto SDL's queue - we'll handle it -        // when it comes out again. -        SDL_Event event; -        event.type = SDL_VIDEORESIZE; -        event.resize.w = size.mX; -        event.resize.h = size.mY; -        SDL_PushEvent(&event); // copied into queue - -        return TRUE; -    } +    return ::setSizeImpl( size, mWindow ); +} -    return FALSE; +BOOL LLWindowSDL::setSizeImpl(const LLCoordWindow size) +{ +    return ::setSizeImpl( size, mWindow );  } @@ -968,7 +1127,7 @@ void LLWindowSDL::swapBuffers()  {      if (mWindow)      { -        SDL_GL_SwapBuffers(); +        SDL_GL_SwapWindow( mWindow );      }  } @@ -990,7 +1149,7 @@ F32 LLWindowSDL::getGamma()  BOOL LLWindowSDL::restoreGamma()  {      //CGDisplayRestoreColorSyncSettings(); -    SDL_SetGamma(1.0f, 1.0f, 1.0f); +    // SDL_SetGamma(1.0f, 1.0f, 1.0f);      return true;  } @@ -999,7 +1158,7 @@ BOOL LLWindowSDL::setGamma(const F32 gamma)      mGamma = gamma;      if (mGamma == 0) mGamma = 0.1f;      mGamma = 1/mGamma; -    SDL_SetGamma(mGamma, mGamma, mGamma); +    // SDL_SetGamma(mGamma, mGamma, mGamma);      return true;  } @@ -1048,7 +1207,7 @@ BOOL LLWindowSDL::setCursorPosition(const LLCoordWindow position)      //LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL;      // do the actual forced cursor move. -    SDL_WarpMouse(screen_pos.mX, screen_pos.mY); +    SDL_WarpMouseInWindow(mWindow, screen_pos.mX, screen_pos.mY);      //LL_INFOS() << llformat("llcw %d,%d -> scr %d,%d", position.mX, position.mY, screen_pos.mX, screen_pos.mY) << LL_ENDL; @@ -1073,18 +1232,6 @@ BOOL LLWindowSDL::getCursorPosition(LLCoordWindow *position)  F32 LLWindowSDL::getNativeAspectRatio()  { -#if 0 -    // RN: this hack presumes that the largest supported resolution is monitor-limited -    // and that pixels in that mode are square, therefore defining the native aspect ratio -    // of the monitor...this seems to work to a close approximation for most CRTs/LCDs -    S32 num_resolutions; -    LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); - - -    return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); -    //rn: AC -#endif -      // MBW -- there are a couple of bad assumptions here.  One is that the display list won't include      //      ridiculous resolutions nobody would ever use.  The other is that the list is in order. @@ -1146,7 +1293,7 @@ void LLWindowSDL::beforeDialog()              // it only works in X11              if (running_x11 && mWindow)              { -                SDL_WM_ToggleFullScreen(mWindow); +                SDL_SetWindowFullscreen( mWindow, 0 );              }          }      } @@ -1162,12 +1309,6 @@ void LLWindowSDL::beforeDialog()      }  #endif // LL_X11 -#if LL_GTK -    // this is a good time to grab some GTK version information for -    // diagnostics, if not already done. -    ll_try_gtk_init(); -#endif // LL_GTK -      maybe_lock_display();  } @@ -1188,7 +1329,7 @@ void LLWindowSDL::afterDialog()          // in X11          if (running_x11 && mWindow)          { -            SDL_WM_ToggleFullScreen(mWindow); +            SDL_SetWindowFullscreen( mWindow, 0 );          }      }  } @@ -1224,143 +1365,56 @@ void LLWindowSDL::x11_set_urgent(BOOL urgent)  void LLWindowSDL::flashIcon(F32 seconds)  { +    if (getMinimized()) +    {  #if !LL_X11 -    LL_INFOS() << "Stub LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; +        LL_INFOS() << "Stub LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL;  #else -    LL_INFOS() << "X11 LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; +        LL_INFOS() << "X11 LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; -    F32 remaining_time = mFlashTimer.getRemainingTimeF32(); -    if (remaining_time < seconds) -        remaining_time = seconds; -    mFlashTimer.reset(); -    mFlashTimer.setTimerExpirySec(remaining_time); +        F32 remaining_time = mFlashTimer.getRemainingTimeF32(); +        if (remaining_time < seconds) +            remaining_time = seconds; +        mFlashTimer.reset(); +        mFlashTimer.setTimerExpirySec(remaining_time); -    x11_set_urgent(TRUE); -    mFlashing = TRUE; +        x11_set_urgent(TRUE); +        mFlashing = TRUE;  #endif // LL_X11 -} - - -#if LL_GTK -BOOL LLWindowSDL::isClipboardTextAvailable() -{ -    if (ll_try_gtk_init()) -    { -        GtkClipboard * const clipboard = -            gtk_clipboard_get(GDK_NONE); -        return gtk_clipboard_wait_is_text_available(clipboard) ? -            TRUE : FALSE;      } -    return FALSE; // failure  } -BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &text) -{ -    if (ll_try_gtk_init()) -    { -        GtkClipboard * const clipboard = -            gtk_clipboard_get(GDK_NONE); -        gchar * const data = gtk_clipboard_wait_for_text(clipboard); -        if (data) -        { -            text = LLWString(utf8str_to_wstring(data)); -            g_free(data); -            return TRUE; -        } -    } -    return FALSE; // failure -} - -BOOL LLWindowSDL::copyTextToClipboard(const LLWString &text) -{ -    if (ll_try_gtk_init()) -    { -        const std::string utf8 = wstring_to_utf8str(text); -        GtkClipboard * const clipboard = -            gtk_clipboard_get(GDK_NONE); -        gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); -        return TRUE; -    } -    return FALSE; // failure -} - - -BOOL LLWindowSDL::isPrimaryTextAvailable() -{ -    if (ll_try_gtk_init()) -    { -        GtkClipboard * const clipboard = -            gtk_clipboard_get(GDK_SELECTION_PRIMARY); -        return gtk_clipboard_wait_is_text_available(clipboard) ? -            TRUE : FALSE; -    } -    return FALSE; // failure -} - -BOOL LLWindowSDL::pasteTextFromPrimary(LLWString &text) -{ -    if (ll_try_gtk_init()) -    { -        GtkClipboard * const clipboard = -            gtk_clipboard_get(GDK_SELECTION_PRIMARY); -        gchar * const data = gtk_clipboard_wait_for_text(clipboard); -        if (data) -        { -            text = LLWString(utf8str_to_wstring(data)); -            g_free(data); -            return TRUE; -        } -    } -    return FALSE; // failure -} - -BOOL LLWindowSDL::copyTextToPrimary(const LLWString &text) -{ -    if (ll_try_gtk_init()) -    { -        const std::string utf8 = wstring_to_utf8str(text); -        GtkClipboard * const clipboard = -            gtk_clipboard_get(GDK_SELECTION_PRIMARY); -        gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); -        return TRUE; -    } -    return FALSE; // failure -} - -#else -  BOOL LLWindowSDL::isClipboardTextAvailable()  { -    return FALSE; // unsupported +    return mSDL_Display && XGetSelectionOwner(mSDL_Display, XA_CLIPBOARD) != None;  }  BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &dst)  { -    return FALSE; // unsupported +    return getSelectionText(XA_CLIPBOARD, dst);  }  BOOL LLWindowSDL::copyTextToClipboard(const LLWString &s)  { -    return FALSE;  // unsupported +    return setSelectionText(XA_CLIPBOARD, s);  }  BOOL LLWindowSDL::isPrimaryTextAvailable()  { -    return FALSE; // unsupported +    LLWString text; +    return getSelectionText(XA_PRIMARY, text) && !text.empty();  }  BOOL LLWindowSDL::pasteTextFromPrimary(LLWString &dst)  { -    return FALSE; // unsupported +    return getSelectionText(XA_PRIMARY, dst);  }  BOOL LLWindowSDL::copyTextToPrimary(const LLWString &s)  { -    return FALSE;  // unsupported +    return setSelectionText(XA_PRIMARY, s);  } -#endif // LL_GTK -  LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_resolutions)  {      if (!mSupportedResolutions) @@ -1368,33 +1422,30 @@ LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_reso          mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS];          mNumSupportedResolutions = 0; -        SDL_Rect **modes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN); -        if ( (modes != NULL) && (modes != ((SDL_Rect **) -1)) ) +        // <FS:ND> Use display no from mWindow/mSurface here? +        int max = SDL_GetNumDisplayModes(0); +        max = llclamp( max, 0, MAX_NUM_RESOLUTIONS ); + +        for( int i =0; i < max; ++i )          { -            int count = 0; -            while (*modes && count<MAX_NUM_RESOLUTIONS)  // they're sorted biggest to smallest, so find end... +            SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 }; +            if (SDL_GetDisplayMode( 0 , i, &mode) != 0)              { -                modes++; -                count++; +                continue;              } -            while (count--) +            int w = mode.w; +            int h = mode.h; +            if ((w >= 800) && (h >= 600))              { -                modes--; -                SDL_Rect *r = *modes; -                int w = r->w; -                int h = r->h; -                if ((w >= 800) && (h >= 600)) +                // make sure we don't add the same resolution multiple times! +                if ( (mNumSupportedResolutions == 0) || +                     ((mSupportedResolutions[mNumSupportedResolutions-1].mWidth != w) && +                      (mSupportedResolutions[mNumSupportedResolutions-1].mHeight != h)) )                  { -                    // make sure we don't add the same resolution multiple times! -                    if ( (mNumSupportedResolutions == 0) || -                         ((mSupportedResolutions[mNumSupportedResolutions-1].mWidth != w) && -                          (mSupportedResolutions[mNumSupportedResolutions-1].mHeight != h)) ) -                    { -                        mSupportedResolutions[mNumSupportedResolutions].mWidth = w; -                        mSupportedResolutions[mNumSupportedResolutions].mHeight = h; -                        mNumSupportedResolutions++; -                    } +                    mSupportedResolutions[mNumSupportedResolutions].mWidth = w; +                    mSupportedResolutions[mNumSupportedResolutions].mHeight = h; +                    mNumSupportedResolutions++;                  }              }          } @@ -1410,7 +1461,7 @@ BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to)          return FALSE;      to->mX = from.mX; -    to->mY = mWindow->h - from.mY - 1; +    to->mY = mSurface->h - from.mY - 1;      return TRUE;  } @@ -1421,7 +1472,7 @@ BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to)          return FALSE;      to->mX = from.mX; -    to->mY = mWindow->h - from.mY - 1; +    to->mY = mSurface->h - from.mY - 1;      return TRUE;  } @@ -1482,13 +1533,13 @@ BOOL LLWindowSDL::SDLReallyCaptureInput(BOOL capture)      else          mReallyCapturedCount = 0; -    SDL_GrabMode wantmode, newmode; +    bool wantGrab;      if (mReallyCapturedCount <= 0) // uncapture      { -        wantmode = SDL_GRAB_OFF; +        wantGrab = false;      } else // capture      { -        wantmode = SDL_GRAB_ON; +        wantGrab = true;      }      if (mReallyCapturedCount < 0) // yuck, imbalance. @@ -1497,9 +1548,11 @@ BOOL LLWindowSDL::SDLReallyCaptureInput(BOOL capture)          LL_WARNS() << "ReallyCapture count was < 0" << LL_ENDL;      } +    bool newGrab = wantGrab; + +#if LL_X11      if (!mFullscreen) /* only bother if we're windowed anyway */      { -#if LL_X11          if (mSDL_Display)          {              /* we dirtily mix raw X11 with SDL so that our pointer @@ -1512,49 +1565,37 @@ BOOL LLWindowSDL::SDLReallyCaptureInput(BOOL capture)                 *keyboard* input from the window manager, which was                 frustrating users. */              int result; -            if (wantmode == SDL_GRAB_ON) +            if (wantGrab == true)              { -                //LL_INFOS() << "X11 POINTER GRABBY" << LL_ENDL; -                //newmode = SDL_WM_GrabInput(wantmode);                  maybe_lock_display();                  result = XGrabPointer(mSDL_Display, mSDL_XWindowID, -                              True, 0, GrabModeAsync, -                              GrabModeAsync, -                              None, None, CurrentTime); +                                      True, 0, GrabModeAsync, +                                      GrabModeAsync, +                                      None, None, CurrentTime);                  maybe_unlock_display();                  if (GrabSuccess == result) -                    newmode = SDL_GRAB_ON; +                    newGrab = true;                  else -                    newmode = SDL_GRAB_OFF; -            } else if (wantmode == SDL_GRAB_OFF) +                    newGrab = false; +            } +            else              { -                //LL_INFOS() << "X11 POINTER UNGRABBY" << LL_ENDL; -                newmode = SDL_GRAB_OFF; -                //newmode = SDL_WM_GrabInput(SDL_GRAB_OFF); +                newGrab = false;                  maybe_lock_display();                  XUngrabPointer(mSDL_Display, CurrentTime);                  // Make sure the ungrab happens RIGHT NOW.                  XSync(mSDL_Display, False);                  maybe_unlock_display(); -            } else -            { -                newmode = SDL_GRAB_QUERY; // neutral              } -        } else // not actually running on X11, for some reason -            newmode = wantmode; -#endif // LL_X11 -    } else { -        // pretend we got what we wanted, when really we don't care. -        newmode = wantmode; +        }      } - +#endif // LL_X11      // return boolean success for whether we ended up in the desired state -    return (capture && SDL_GRAB_ON==newmode) || -        (!capture && SDL_GRAB_OFF==newmode); +    return capture == newGrab;  } -U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, BOOL gain) +U32 LLWindowSDL::SDLCheckGrabbyKeys(U32 keysym, BOOL gain)  {      /* part of the fix for SL-13243: Some popular window managers like         to totally eat alt-drag for the purposes of moving windows.  We @@ -1572,16 +1613,16 @@ U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, BOOL gain)      U32 mask = 0;      switch (keysym)      { -    case SDLK_LALT: -        mask = 1U << 0; break; -    case SDLK_RALT: -        mask = 1U << 1; break; -    case SDLK_LCTRL: -        mask = 1U << 2; break; -    case SDLK_RCTRL: -        mask = 1U << 3; break; -    default: -        break; +        case SDLK_LALT: +            mask = 1U << 0; break; +        case SDLK_RALT: +            mask = 1U << 1; break; +        case SDLK_LCTRL: +            mask = 1U << 2; break; +        case SDLK_RCTRL: +            mask = 1U << 3; break; +        default: +            break;      }      if (gain) @@ -1679,7 +1720,7 @@ void check_vm_bloat()          last_rss_size = this_rss_size;          last_vm_size = this_vm_size; -finally: +        finally:          if (NULL != ptr)          {              free(ptr); @@ -1694,33 +1735,17 @@ finally:  // virtual  void LLWindowSDL::processMiscNativeEvents()  { -#if LL_GTK -    // Pump GTK events to avoid starvation for: -    // * DBUS servicing -    // * Anything else which quietly hooks into the default glib/GTK loop -    if (ll_try_gtk_init()) -    { -        // Yuck, Mozilla's GTK callbacks play with the locale - push/pop -        // the locale to protect it, as exotic/non-C locales -        // causes our code lots of general critical weirdness -        // and crashness. (SL-35450) -        static std::string saved_locale; -        saved_locale = ll_safe_string(setlocale(LC_ALL, NULL)); - -        // Pump until we've nothing left to do or passed 1/15th of a -        // second pumping for this frame. -        static LLTimer pump_timer; -        pump_timer.reset(); -        pump_timer.setTimerExpirySec(1.0f / 15.0f); -        do { -             // Always do at least one non-blocking pump -            gtk_main_iteration_do(FALSE); -        } while (gtk_events_pending() && -             !pump_timer.hasExpired()); - -        setlocale(LC_ALL, saved_locale.c_str() ); -    } -#endif // LL_GTK +#if LL_GLIB +    // Pump until we've nothing left to do or passed 1/15th of a +    // second pumping for this frame. +    static LLTimer pump_timer; +    pump_timer.reset(); +    pump_timer.setTimerExpirySec(1.0f / 15.0f); +    do +    { +        g_main_context_iteration(g_main_context_default(), FALSE); +    } while( g_main_context_pending(g_main_context_default()) && !pump_timer.hasExpired()); +#endif      // hack - doesn't belong here - but this is just for debugging      if (getenv("LL_DEBUG_BLOAT")) @@ -1743,6 +1768,11 @@ void LLWindowSDL::gatherInput()      {          switch (event.type)          { +            case SDL_MOUSEWHEEL: +                if( event.wheel.y != 0 ) +                    mCallbacks->handleScrollWheel(this, -event.wheel.y); +                break; +              case SDL_MOUSEMOTION:              {                  LLCoordWindow winCoord(event.button.x, event.button.y); @@ -1753,33 +1783,68 @@ void LLWindowSDL::gatherInput()                  break;              } +            case SDL_TEXTINPUT: +            { +                auto string = utf8str_to_utf16str( event.text.text ); +                mKeyModifiers = gKeyboard->currentMask( FALSE ); +                mInputType = "textinput"; +                for( auto key: string ) +                { +                    mKeyVirtualKey = key; + +                    if( (MASK_CONTROL|MASK_ALT)&mKeyModifiers ) +                        gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers ); +                    else +                        handleUnicodeUTF16( key, mKeyModifiers ); +                } +                break; +            } +              case SDL_KEYDOWN: -            mKeyScanCode = event.key.keysym.scancode; -            mKeyVirtualKey = event.key.keysym.unicode; -            mKeyModifiers = event.key.keysym.mod; +                mKeyVirtualKey = event.key.keysym.sym; +                mKeyModifiers = event.key.keysym.mod; +                mInputType = "keydown"; -            gKeyboard->handleKeyDown(event.key.keysym.sym, event.key.keysym.mod); -            // part of the fix for SL-13243 -            if (SDLCheckGrabbyKeys(event.key.keysym.sym, TRUE) != 0) -                SDLReallyCaptureInput(TRUE); +                // treat all possible Enter/Return keys the same +                if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) +                { +                    mKeyVirtualKey = SDLK_RETURN; +                } + +                gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers ); + +                // <FS:ND> Slightly hacky :| To make the viewer honor enter (eg to accept form input) we've to not only send handleKeyDown but also send a +                // invoke handleUnicodeUTF16 in case the user hits return. +                // Note that we cannot blindly use handleUnicodeUTF16 for each SDL_KEYDOWN. Doing so will create bogus keyboard input (like % for cursor left). +                if( mKeyVirtualKey == SDLK_RETURN ) +                { +                    // fix return key not working when capslock, scrolllock or numlock are enabled +                    mKeyModifiers &= (~(KMOD_NUM | KMOD_CAPS | KMOD_MODE | KMOD_SCROLL)); +                    handleUnicodeUTF16( mKeyVirtualKey, mKeyModifiers ); +                } + +                // part of the fix for SL-13243 +                if (SDLCheckGrabbyKeys(event.key.keysym.sym, TRUE) != 0) +                    SDLReallyCaptureInput(TRUE); -            if (event.key.keysym.unicode) -            { -                handleUnicodeUTF16(event.key.keysym.unicode, -                           gKeyboard->currentMask(FALSE)); -            }                  break;              case SDL_KEYUP: -            mKeyScanCode = event.key.keysym.scancode; -            mKeyVirtualKey = event.key.keysym.unicode; -            mKeyModifiers = event.key.keysym.mod; +                mKeyVirtualKey = event.key.keysym.sym; +                mKeyModifiers = event.key.keysym.mod; +                mInputType = "keyup"; -            if (SDLCheckGrabbyKeys(event.key.keysym.sym, FALSE) == 0) -                SDLReallyCaptureInput(FALSE); // part of the fix for SL-13243 +                // treat all possible Enter/Return keys the same +                if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) +                { +                    mKeyVirtualKey = SDLK_RETURN; +                } -            gKeyboard->handleKeyUp(event.key.keysym.sym, event.key.keysym.mod); -            break; +                if (SDLCheckGrabbyKeys(mKeyVirtualKey, FALSE) == 0) +                    SDLReallyCaptureInput(FALSE); // part of the fix for SL-13243 + +                gKeyboard->handleKeyUp(mKeyVirtualKey,mKeyModifiers); +                break;              case SDL_MOUSEBUTTONDOWN:              { @@ -1787,7 +1852,7 @@ void LLWindowSDL::gatherInput()                  LLCoordWindow winCoord(event.button.x, event.button.y);                  LLCoordGL openGlCoord;                  convertCoords(winCoord, &openGlCoord); -        MASK mask = gKeyboard->currentMask(TRUE); +                MASK mask = gKeyboard->currentMask(TRUE);                  if (event.button.button == SDL_BUTTON_LEFT)   // SDL doesn't manage double clicking...                  { @@ -1799,7 +1864,7 @@ void LLWindowSDL::gatherInput()                          if (++leftClick >= 2)                          {                              leftClick = 0; -                isDoubleClick = true; +                            isDoubleClick = true;                          }                      }                      lastLeftDown = now; @@ -1830,7 +1895,7 @@ void LLWindowSDL::gatherInput()                  else if (event.button.button == SDL_BUTTON_RIGHT)  // right                  { -            mCallbacks->handleRightMouseDown(this, openGlCoord, mask); +                    mCallbacks->handleRightMouseDown(this, openGlCoord, mask);                  }                  else if (event.button.button == SDL_BUTTON_MIDDLE)  // middle @@ -1850,86 +1915,69 @@ void LLWindowSDL::gatherInput()                  LLCoordWindow winCoord(event.button.x, event.button.y);                  LLCoordGL openGlCoord;                  convertCoords(winCoord, &openGlCoord); -        MASK mask = gKeyboard->currentMask(TRUE); +                MASK mask = gKeyboard->currentMask(TRUE);                  if (event.button.button == SDL_BUTTON_LEFT)  // left -            mCallbacks->handleMouseUp(this, openGlCoord, mask); +                    mCallbacks->handleMouseUp(this, openGlCoord, mask);                  else if (event.button.button == SDL_BUTTON_RIGHT)  // right -            mCallbacks->handleRightMouseUp(this, openGlCoord, mask); +                    mCallbacks->handleRightMouseUp(this, openGlCoord, mask);                  else if (event.button.button == SDL_BUTTON_MIDDLE)  // middle -            mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask); +                    mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask);                  // don't handle mousewheel here...                  break;              } -            case SDL_VIDEOEXPOSE:  // VIDEOEXPOSE doesn't specify the damage, but hey, it's OpenGL...repaint the whole thing! -                mCallbacks->handlePaint(this, 0, 0, mWindow->w, mWindow->h); -                break; - -            case SDL_VIDEORESIZE:  // *FIX: handle this? +            case SDL_WINDOWEVENT:  // *FIX: handle this?              { -        LL_INFOS() << "Handling a resize event: " << event.resize.w << -            "x" << event.resize.h << LL_ENDL; +                if( event.window.event == SDL_WINDOWEVENT_RESIZED +                    /* || event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED*/ ) // <FS:ND> SDL_WINDOWEVENT_SIZE_CHANGED is followed by SDL_WINDOWEVENT_RESIZED, so handling one shall be enough +                { +                    LL_INFOS() << "Handling a resize event: " << event.window.data1 << "x" << event.window.data2 << LL_ENDL; -        S32 width = llmax(event.resize.w, (S32)mMinWindowWidth); -        S32 height = llmax(event.resize.h, (S32)mMinWindowHeight); +                    S32 width = llmax(event.window.data1, (S32)mMinWindowWidth); +                    S32 height = llmax(event.window.data2, (S32)mMinWindowHeight); +                    mSurface = SDL_GetWindowSurface( mWindow ); -        // *FIX: I'm not sure this is necessary! -        mWindow = SDL_SetVideoMode(width, height, 32, mSDLFlags); -        if (!mWindow) -        { -            // *FIX: More informative dialog? -            LL_INFOS() << "Could not recreate context after resize! Quitting..." << LL_ENDL; -            if(mCallbacks->handleCloseRequest(this)) -                { -                    // Get the app to initiate cleanup. -                    mCallbacks->handleQuit(this); -                    // The app is responsible for calling destroyWindow when done with GL -                } -                break; -        } +                    // *FIX: I'm not sure this is necessary! +                    // <FS:ND> I think is is not +                    // SDL_SetWindowSize(mWindow, width, height); +                    // -        mCallbacks->handleResize(this, width, height); -                break; -            } -            case SDL_ACTIVEEVENT: -                if (event.active.state & SDL_APPINPUTFOCUS) +                    mCallbacks->handleResize(this, width, height); +                } +                else if( event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED ) // <FS:ND> What about SDL_WINDOWEVENT_ENTER (mouse focus)                  { -            // Note that for SDL (particularly on X11), keyboard -            // and mouse focus are independent things.  Here we are -            // tracking keyboard focus state changes. - -            // We have to do our own state massaging because SDL -            // can send us two unfocus events in a row for example, -            // which confuses the focus code [SL-24071]. -            if (event.active.gain != mHaveInputFocus) -            { -                mHaveInputFocus = !!event.active.gain; +                    // We have to do our own state massaging because SDL +                    // can send us two unfocus events in a row for example, +                    // which confuses the focus code [SL-24071]. +                    mHaveInputFocus = true; -                if (mHaveInputFocus)                      mCallbacks->handleFocus(this); -                else +                } +                else if( event.window.event == SDL_WINDOWEVENT_FOCUS_LOST ) // <FS:ND> What about SDL_WINDOWEVENT_LEAVE (mouse focus) +                { +                    // We have to do our own state massaging because SDL +                    // can send us two unfocus events in a row for example, +                    // which confuses the focus code [SL-24071]. +                    mHaveInputFocus = false; +                      mCallbacks->handleFocusLost(this); -            }                  } -                if (event.active.state & SDL_APPACTIVE) +                else if( event.window.event == SDL_WINDOWEVENT_MINIMIZED || +                         event.window.event == SDL_WINDOWEVENT_MAXIMIZED || +                         event.window.event == SDL_WINDOWEVENT_RESTORED || +                         event.window.event == SDL_WINDOWEVENT_EXPOSED || +                         event.window.event == SDL_WINDOWEVENT_SHOWN )                  { -            // Change in iconification/minimization state. -            if ((!event.active.gain) != mIsMinimized) -            { -                mIsMinimized = (!event.active.gain); +                    mIsMinimized = (event.window.event == SDL_WINDOWEVENT_MINIMIZED); -                mCallbacks->handleActivate(this, !mIsMinimized); -                LL_INFOS() << "SDL deiconification state switched to " << BOOL(event.active.gain) << LL_ENDL; -            } -            else -            { -                LL_INFOS() << "Ignored bogus redundant SDL deiconification state switch to " << BOOL(event.active.gain) << LL_ENDL; -            } +                    mCallbacks->handleActivate(this, !mIsMinimized); +                    LL_INFOS() << "SDL deiconification state switched to " << mIsMinimized << LL_ENDL;                  } -                break; +                break; +            }              case SDL_QUIT:                  if(mCallbacks->handleCloseRequest(this))                  { @@ -1938,9 +1986,9 @@ void LLWindowSDL::gatherInput()                      // The app is responsible for calling destroyWindow when done with GL                  }                  break; -    default: -        //LL_INFOS() << "Unhandled SDL event type " << event.type << LL_ENDL; -        break; +            default: +                //LL_INFOS() << "Unhandled SDL event type " << event.type << LL_ENDL; +                break;          }      } @@ -1968,21 +2016,21 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty      {          SDL_Surface *cursurface;          LL_DEBUGS() << "Loaded cursor file " << filename << " " -             << bmpsurface->w << "x" << bmpsurface->h << LL_ENDL; +                    << bmpsurface->w << "x" << bmpsurface->h << LL_ENDL;          cursurface = SDL_CreateRGBSurface (SDL_SWSURFACE, -                           bmpsurface->w, -                           bmpsurface->h, -                           32, -                           SDL_SwapLE32(0xFFU), -                           SDL_SwapLE32(0xFF00U), -                           SDL_SwapLE32(0xFF0000U), -                           SDL_SwapLE32(0xFF000000U)); +                                           bmpsurface->w, +                                           bmpsurface->h, +                                           32, +                                           SDL_SwapLE32(0xFFU), +                                           SDL_SwapLE32(0xFF00U), +                                           SDL_SwapLE32(0xFF0000U), +                                           SDL_SwapLE32(0xFF000000U));          SDL_FillRect(cursurface, NULL, SDL_SwapLE32(0x00000000U));          // Blit the cursor pixel data onto a 32-bit RGBA surface so we          // only have to cope with processing one type of pixel format.          if (0 == SDL_BlitSurface(bmpsurface, NULL, -                     cursurface, NULL)) +                                 cursurface, NULL))          {              // n.b. we already checked that width is a multiple of 8.              const int bitmap_bytes = (cursurface->w * cursurface->h) / 8; @@ -1997,26 +2045,26 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty              for (i=0; i<cursurface->h; ++i) {                  for (j=0; j<cursurface->w; ++j) {                      U8 *pixelp = -                        ((U8*)cursurface->pixels) -                        + cursurface->pitch * i -                        + j*cursurface->format->BytesPerPixel; +                            ((U8*)cursurface->pixels) +                            + cursurface->pitch * i +                            + j*cursurface->format->BytesPerPixel;                      U8 srcred = pixelp[0];                      U8 srcgreen = pixelp[1];                      U8 srcblue = pixelp[2];                      BOOL mask_bit = (srcred != 200) -                        || (srcgreen != 200) -                        || (srcblue != 200); +                                    || (srcgreen != 200) +                                    || (srcblue != 200);                      BOOL data_bit = mask_bit && (srcgreen <= 80);//not 0x80                      unsigned char bit_offset = (cursurface->w/8) * i -                        + j/8; +                                               + j/8;                      cursor_data[bit_offset] |= (data_bit) << (7 - (j&7));                      cursor_mask[bit_offset] |= (mask_bit) << (7 - (j&7));                  }              }              sdlcursor = SDL_CreateCursor((Uint8*)cursor_data, -                             (Uint8*)cursor_mask, -                             cursurface->w, cursurface->h, -                             hotx, hoty); +                                         (Uint8*)cursor_mask, +                                         cursurface->w, cursurface->h, +                                         hotx, hoty);              delete[] cursor_data;              delete[] cursor_mask;          } else { @@ -2207,8 +2255,6 @@ void LLWindowSDL::hideCursorUntilMouseMove()      }  } - -  //  // LLSplashScreenSDL - I don't think we'll bother to implement this; it's  // fairly obsolete at this point. @@ -2233,133 +2279,51 @@ void LLSplashScreenSDL::hideImpl()  {  } - - -#if LL_GTK -static void response_callback (GtkDialog *dialog, -                   gint       arg1, -                   gpointer   user_data) -{ -    gint *response = (gint*)user_data; -    *response = arg1; -    gtk_widget_destroy(GTK_WIDGET(dialog)); -    gtk_main_quit(); -} -  S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type)  { -    S32 rtn = OSBTN_CANCEL; +    SDL_MessageBoxData oData = { SDL_MESSAGEBOX_INFORMATION, nullptr, caption.c_str(), text.c_str(), 0, nullptr, nullptr }; +    SDL_MessageBoxButtonData btnOk[] = {{SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, OSBTN_OK, "OK" }}; +    SDL_MessageBoxButtonData btnOkCancel [] =  {{SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, OSBTN_OK, "OK" }, {SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, OSBTN_CANCEL, "Cancel"} }; +    SDL_MessageBoxButtonData btnYesNo[] = { {SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, OSBTN_YES, "Yes" }, {SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, OSBTN_NO, "No"} }; -    if(gWindowImplementation != NULL) -        gWindowImplementation->beforeDialog(); - -    if (LLWindowSDL::ll_try_gtk_init()) +    switch (type)      { -        GtkWidget *win = NULL; - -        LL_INFOS() << "Creating a dialog because we're in windowed mode and GTK is happy." << LL_ENDL; - -        GtkDialogFlags flags = GTK_DIALOG_MODAL; -        GtkMessageType messagetype; -        GtkButtonsType buttons; -        switch (type) -        {          default:          case OSMB_OK: -            messagetype = GTK_MESSAGE_WARNING; -            buttons = GTK_BUTTONS_OK; +            oData.flags = SDL_MESSAGEBOX_WARNING; +            oData.buttons = btnOk; +            oData.numbuttons = 1;              break;          case OSMB_OKCANCEL: -            messagetype = GTK_MESSAGE_QUESTION; -            buttons = GTK_BUTTONS_OK_CANCEL; +            oData.flags = SDL_MESSAGEBOX_INFORMATION; +            oData.buttons = btnOkCancel; +            oData.numbuttons = 2;              break;          case OSMB_YESNO: -            messagetype = GTK_MESSAGE_QUESTION; -            buttons = GTK_BUTTONS_YES_NO; +            oData.flags = SDL_MESSAGEBOX_INFORMATION; +            oData.buttons = btnYesNo; +            oData.numbuttons = 2;              break; -        } -        win = gtk_message_dialog_new(NULL, flags, messagetype, buttons, "%s", -                                     text.c_str()); - -# if LL_X11 -        // Make GTK tell the window manager to associate this -        // dialog with our non-GTK SDL window, which should try -        // to keep it on top etc. -        if (gWindowImplementation && -            gWindowImplementation->mSDL_XWindowID != None) -        { -            gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin -            GdkWindow *gdkwin = gdk_window_foreign_new(gWindowImplementation->mSDL_XWindowID); -            gdk_window_set_transient_for(GTK_WIDGET(win)->window, -                             gdkwin); -        } -# endif //LL_X11 - -        gtk_window_set_position(GTK_WINDOW(win), -                    GTK_WIN_POS_CENTER_ON_PARENT); - -        gtk_window_set_type_hint(GTK_WINDOW(win), -                     GDK_WINDOW_TYPE_HINT_DIALOG); - -        if (!caption.empty()) -            gtk_window_set_title(GTK_WINDOW(win), caption.c_str()); - -        gint response = GTK_RESPONSE_NONE; -        g_signal_connect (win, -                  "response", -                  G_CALLBACK (response_callback), -                  &response); - -        // we should be able to use a gtk_dialog_run(), but it's -        // apparently not written to exist in a world without a higher -        // gtk_main(), so we manage its signal/destruction outselves. -        gtk_widget_show_all (win); -        gtk_main(); - -        //LL_INFOS() << "response: " << response << LL_ENDL; -        switch (response) -        { -        case GTK_RESPONSE_OK:     rtn = OSBTN_OK; break; -        case GTK_RESPONSE_YES:    rtn = OSBTN_YES; break; -        case GTK_RESPONSE_NO:     rtn = OSBTN_NO; break; -        case GTK_RESPONSE_APPLY:  rtn = OSBTN_OK; break; -        case GTK_RESPONSE_NONE: -        case GTK_RESPONSE_CANCEL: -        case GTK_RESPONSE_CLOSE: -        case GTK_RESPONSE_DELETE_EVENT: -        default: rtn = OSBTN_CANCEL; -        }      } -    else -    { -        LL_INFOS() << "MSGBOX: " << caption << ": " << text << LL_ENDL; -        LL_INFOS() << "Skipping dialog because we're in fullscreen mode or GTK is not happy." << LL_ENDL; -        rtn = OSBTN_OK; -    } - -    if(gWindowImplementation != NULL) -        gWindowImplementation->afterDialog(); -    return rtn; +    int btn{0}; +    if( 0 == SDL_ShowMessageBox( &oData, &btn ) ) +        return btn; +    return OSBTN_CANCEL;  } -static void color_changed_callback(GtkWidget *widget, -                   gpointer user_data) +BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b)  { -    GtkColorSelection *colorsel = GTK_COLOR_SELECTION(widget); -    GdkColor *colorp = (GdkColor*)user_data; - -    gtk_color_selection_get_current_color(colorsel, colorp); +    return (FALSE);  } -  /*          Make the raw keyboard data available - used to poke through to LLQtWebKit so          that Qt/Webkit has access to the virtual keycodes etc. that it needs  */  LLSD LLWindowSDL::getNativeKeyData()  { -        LLSD result = LLSD::emptyMap(); +    LLSD result = LLSD::emptyMap();      U32 modifiers = 0; // pretend-native modifiers... oh what a tangled web we weave! @@ -2377,99 +2341,14 @@ LLSD LLWindowSDL::getNativeKeyData()      // *todo: test ALTs - I don't have a case for testing these.  Do you?      // *todo: NUM? - I don't care enough right now (and it's not a GDK modifier). -        result["scan_code"] = (S32)mKeyScanCode; -        result["virtual_key"] = (S32)mKeyVirtualKey; +    result["virtual_key"] = (S32)mKeyVirtualKey; +    result["virtual_key_win"] = (S32)LLKeyboardSDL::mapSDL2toWin( mKeyVirtualKey );      result["modifiers"] = (S32)modifiers; - -        return result; -} - - -BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ -    BOOL rtn = FALSE; - -    beforeDialog(); - -    if (ll_try_gtk_init()) -    { -        GtkWidget *win = NULL; - -        win = gtk_color_selection_dialog_new(NULL); - -# if LL_X11 -        // Get GTK to tell the window manager to associate this -        // dialog with our non-GTK SDL window, which should try -        // to keep it on top etc. -        if (mSDL_XWindowID != None) -        { -            gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin -            GdkWindow *gdkwin = gdk_window_foreign_new(mSDL_XWindowID); -            gdk_window_set_transient_for(GTK_WIDGET(win)->window, -                             gdkwin); -        } -# endif //LL_X11 - -        GtkColorSelection *colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG(win)->colorsel); - -        GdkColor color, orig_color; -        orig_color.pixel = 0; -        orig_color.red = guint16(65535 * *r); -        orig_color.green= guint16(65535 * *g); -        orig_color.blue = guint16(65535 * *b); -        color = orig_color; - -        gtk_color_selection_set_previous_color (colorsel, &color); -        gtk_color_selection_set_current_color (colorsel, &color); -        gtk_color_selection_set_has_palette (colorsel, TRUE); -        gtk_color_selection_set_has_opacity_control(colorsel, FALSE); - -        gint response = GTK_RESPONSE_NONE; -        g_signal_connect (win, -                  "response", -                  G_CALLBACK (response_callback), -                  &response); - -        g_signal_connect (G_OBJECT (colorsel), "color_changed", -                  G_CALLBACK (color_changed_callback), -                  &color); - -        gtk_window_set_modal(GTK_WINDOW(win), TRUE); -        gtk_widget_show_all(win); -        // hide the help button - we don't service it. -        gtk_widget_hide(GTK_COLOR_SELECTION_DIALOG(win)->help_button); -        gtk_main(); - -        if (response == GTK_RESPONSE_OK && -            (orig_color.red != color.red -             || orig_color.green != color.green -             || orig_color.blue != color.blue) ) -        { -            *r = color.red / 65535.0f; -            *g = color.green / 65535.0f; -            *b = color.blue / 65535.0f; -            rtn = TRUE; -        } -    } - -    afterDialog(); - -    return rtn; -} -#else -S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type) -{ -    LL_INFOS() << "MSGBOX: " << caption << ": " << text << LL_ENDL; -    return 0; -} - -BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ -    return (FALSE); +    result["input_type"] = mInputType; +    return result;  } -#endif // LL_GTK -#if LL_LINUX +#if LL_LINUX || LL_SOLARIS  // extracted from spawnWebBrowser for clarity and to eliminate  //  compiler confusion regarding close(int fd) vs. LLWindow::close()  void exec_cmd(const std::string& cmd, const std::string& arg) @@ -2481,9 +2360,32 @@ void exec_cmd(const std::string& cmd, const std::string& arg)      { // child          // disconnect from stdin/stdout/stderr, or child will          // keep our output pipe undesirably alive if it outlives us. -        close(0); -        close(1); -        close(2); +        // close(0); +        // close(1); +        // close(2); +        // <FS:TS> Reopen stdin, stdout, and stderr to /dev/null. +        //         It's good practice to always have those file +        //         descriptors open to something, lest the exec'd +        //         program actually try to use them. +        FILE *result; +        result = freopen("/dev/null","r",stdin); +        if (result == NULL) +        { +            LL_WARNS() << "Error reopening stdin for web browser: " +                       << strerror(errno) << LL_ENDL; +        } +        result = freopen("/dev/null","w",stdout); +        if (result == NULL) +        { +            LL_WARNS() << "Error reopening stdout for web browser: " +                       << strerror(errno) << LL_ENDL; +        } +        result = freopen("/dev/null","w",stderr); +        if (result == NULL) +        { +            LL_WARNS() << "Error reopening stderr for web browser: " +                       << strerror(errno) << LL_ENDL; +        }          // end ourself by running the command          execv(cmd.c_str(), argv);   /* Flawfinder: ignore */          // if execv returns at all, there was a problem. @@ -2549,31 +2451,13 @@ void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async)      LL_INFOS() << "spawn_web_browser returning." << LL_ENDL;  } +void LLWindowSDL::openFile(const std::string& file_name) +{ +    spawnWebBrowser("file://"+file_name,TRUE); +}  void *LLWindowSDL::getPlatformWindow()  { -#if LL_GTK && LL_LLMOZLIB_ENABLED -    if (LLWindowSDL::ll_try_gtk_init()) -    { -        maybe_lock_display(); - -        GtkWidget *owin = gtk_window_new(GTK_WINDOW_POPUP); -        // Why a layout widget?  A MozContainer would be ideal, but -        // it involves exposing Mozilla headers to mozlib-using apps. -        // A layout widget with a GtkWindow parent has the desired -        // properties of being plain GTK, having a window, and being -        // derived from a GtkContainer. -        GtkWidget *rtnw = gtk_layout_new(NULL, NULL); -        gtk_container_add(GTK_CONTAINER(owin), rtnw); -        gtk_widget_realize(rtnw); -        GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(rtnw), GTK_NO_WINDOW); - -        maybe_unlock_display(); - -        return rtnw; -    } -#endif // LL_GTK && LL_LLMOZLIB_ENABLED -    // Unixoid mozilla really needs GTK.      return NULL;  } @@ -2634,10 +2518,10 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()              LL_INFOS("AppInit") << "Variant " << locale->variant << LL_ENDL;              LL_INFOS() << "Preferring fonts of language: " -                << locale->lang -                << LL_ENDL; +                       << locale->lang +                       << LL_ENDL;              sort_order = "lang=" + std::string(locale->lang) + ":" -                + sort_order; +                         + sort_order;          }      }      FL_FreeLocale(&locale); @@ -2655,7 +2539,7 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()          // Sort the list of system fonts from most-to-least-desirable.          FcResult result;          fs = FcFontSort(NULL, sortpat, elide_unicode_coverage, -                NULL, &result); +                        NULL, &result);          FcPatternDestroy(sortpat);      } @@ -2669,8 +2553,8 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()          {              FcChar8 *filename;              if (FcResultMatch == FcPatternGetString(fs->fonts[i], -                                FC_FILE, 0, -                                &filename) +                                                    FC_FILE, 0, +                                                    &filename)                  && filename)              {                  rtns.push_back(std::string((const char*)filename)); @@ -2694,4 +2578,59 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()      return rtns;  } -#endif // LL_SDL + +void* LLWindowSDL::createSharedContext() +{ +    auto *pContext = SDL_GL_CreateContext(mWindow); +    if ( pContext) +    { +        SDL_GL_SetSwapInterval(0); +        SDL_GL_MakeCurrent(mWindow, mContext); + +        LLCoordScreen size; +        if (getSize(&size)) +            setSize(size); + +        LL_DEBUGS() << "Creating shared OpenGL context successful!" << LL_ENDL; + +        return (void*)pContext; +    } + +    LL_WARNS() << "Creating shared OpenGL context failed!" << LL_ENDL; + +    return nullptr; +} + +void LLWindowSDL::makeContextCurrent(void* contextPtr) +{ +    LL_PROFILER_GPU_CONTEXT; +    SDL_GL_MakeCurrent( mWindow, contextPtr ); +} + +void LLWindowSDL::destroySharedContext(void* contextPtr) +{ +    SDL_GL_DeleteContext( contextPtr ); +} + +void LLWindowSDL::toggleVSync(bool enable_vsync) +{ +} + +U32 LLWindowSDL::getAvailableVRAMMegabytes() +{ +    return 4096; +} + +void LLWindowSDL::setLanguageTextInput(const LLCoordGL& position) +{ +    LLCoordWindow win_pos; +    convertCoords( position, &win_pos ); + +    SDL_Rect r; +    r.x = win_pos.mX; +    r.y = win_pos.mY; +    r.w = 500; +    r.h = 16; + +    SDL_SetTextInputRect(&r); +} diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h index e96fce92f5..d24739cbda 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -24,20 +24,20 @@   * $/LicenseInfo$   */ -#ifndef LL_LLWINDOWSDL_H -#define LL_LLWINDOWSDL_H +#ifndef LL_LLWINDOWSDL2_H +#define LL_LLWINDOWSDL2_H  // Simple Directmedia Layer (http://libsdl.org/) implementation of LLWindow class  #include "llwindow.h"  #include "lltimer.h" -#include "SDL/SDL.h" -#include "SDL/SDL_endian.h" +#include "SDL2/SDL.h" +#include "SDL2/SDL_endian.h"  #if LL_X11  // get X11-specific headers for use in low-level stuff like copy-and-paste support -#include "SDL/SDL_syswm.h" +#include "SDL2/SDL_syswm.h"  #endif  // AssertMacros.h does bad things. @@ -46,83 +46,139 @@  #undef require -class LLWindowSDL : public LLWindow -{ +class LLWindowSDL : public LLWindow {  public: -    /*virtual*/ void show(); -    /*virtual*/ void hide(); -    /*virtual*/ void close(); -    /*virtual*/ BOOL getVisible(); -    /*virtual*/ BOOL getMinimized(); -    /*virtual*/ BOOL getMaximized(); -    /*virtual*/ BOOL maximize(); -    /*virtual*/ void minimize(); -    /*virtual*/ void restore(); -    /*virtual*/ BOOL getFullscreen(); -    /*virtual*/ BOOL getPosition(LLCoordScreen *position); -    /*virtual*/ BOOL getSize(LLCoordScreen *size); -    /*virtual*/ BOOL getSize(LLCoordWindow *size); -    /*virtual*/ BOOL setPosition(LLCoordScreen position); -    /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); -    /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); -    /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL); -    /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); -    /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); -    /*virtual*/ void showCursor(); -    /*virtual*/ void hideCursor(); -    /*virtual*/ void showCursorFromMouseMove(); -    /*virtual*/ void hideCursorUntilMouseMove(); -    /*virtual*/ BOOL isCursorHidden(); -    /*virtual*/ void updateCursor(); -    /*virtual*/ void captureMouse(); -    /*virtual*/ void releaseMouse(); -    /*virtual*/ void setMouseClipping( BOOL b ); -    /*virtual*/ void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); - -    /*virtual*/ BOOL isClipboardTextAvailable(); -    /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst); -    /*virtual*/ BOOL copyTextToClipboard(const LLWString & src); - -    /*virtual*/ BOOL isPrimaryTextAvailable(); -    /*virtual*/ BOOL pasteTextFromPrimary(LLWString &dst); -    /*virtual*/ BOOL copyTextToPrimary(const LLWString & src); - -    /*virtual*/ void flashIcon(F32 seconds); -    /*virtual*/ F32 getGamma(); -    /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma -    /*virtual*/ U32 getFSAASamples(); -    /*virtual*/ void setFSAASamples(const U32 samples); -    /*virtual*/ BOOL restoreGamma();            // Restore original gamma table (before updating gamma) -    /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } -    /*virtual*/ void processMiscNativeEvents(); -    /*virtual*/ void gatherInput(); -    /*virtual*/ void swapBuffers(); -    /*virtual*/ void restoreGLContext() {}; - -    /*virtual*/ void delayInputProcessing() { }; +    void show() override; + +    void hide() override; + +    void close() override; + +    BOOL getVisible() override; + +    BOOL getMinimized() override; + +    BOOL getMaximized() override; + +    BOOL maximize() override; + +    void minimize() override; + +    void restore() override; + +    BOOL getFullscreen(); + +    BOOL getPosition(LLCoordScreen *position) override; + +    BOOL getSize(LLCoordScreen *size) override; + +    BOOL getSize(LLCoordWindow *size) override; + +    BOOL setPosition(LLCoordScreen position) override; + +    BOOL setSizeImpl(LLCoordScreen size) override; + +    BOOL setSizeImpl(LLCoordWindow size) override; + +    BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, +                                   const LLCoordScreen *const posp = NULL) override; + +    BOOL setCursorPosition(LLCoordWindow position) override; + +    BOOL getCursorPosition(LLCoordWindow *position) override; + +    void showCursor() override; + +    void hideCursor() override; + +    void showCursorFromMouseMove() override; + +    void hideCursorUntilMouseMove() override; + +    BOOL isCursorHidden() override; + +    void updateCursor() override; + +    void captureMouse() override; + +    void releaseMouse() override; + +    void setMouseClipping(BOOL b) override; + +       void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true) override; + +    BOOL isClipboardTextAvailable() override; + +    BOOL pasteTextFromClipboard(LLWString &dst) override; + +    BOOL copyTextToClipboard(const LLWString &src) override; + +    BOOL isPrimaryTextAvailable() override; + +    BOOL pasteTextFromPrimary(LLWString &dst) override; + +    BOOL copyTextToPrimary(const LLWString &src) override; + +    void flashIcon(F32 seconds) override; + +    F32 getGamma() override; + +    BOOL setGamma(const F32 gamma) override; // Set the gamma +    U32 getFSAASamples() override; + +    void setFSAASamples(const U32 samples) override; + +    BOOL restoreGamma() override;            // Restore original gamma table (before updating gamma) +    ESwapMethod getSwapMethod()  override { return mSwapMethod; } + +    void processMiscNativeEvents() override; + +    void gatherInput() override; + +    void swapBuffers() override; + +    void restoreGLContext() {}; + +    void delayInputProcessing()  override {};      // handy coordinate space conversion routines -    /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to); -    /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to); -    /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to); -    /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to); -    /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to); -    /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to); +    BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) override; + +    BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) override; + +    BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) override; + +    BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) override; + +    BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) override; -    /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); -    /*virtual*/ F32 getNativeAspectRatio(); -    /*virtual*/ F32 getPixelAspectRatio(); -    /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } +    BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) override; -    /*virtual*/ void beforeDialog(); -    /*virtual*/ void afterDialog(); +    LLWindowResolution *getSupportedResolutions(S32 &num_resolutions) override; -    /*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b); +    F32 getNativeAspectRatio() override; -    /*virtual*/ void *getPlatformWindow(); -    /*virtual*/ void bringToFront(); +    F32 getPixelAspectRatio() override; -    /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); +    void setNativeAspectRatio(F32 ratio)  override { mOverrideAspectRatio = ratio; } + +    void beforeDialog() override; + +    void afterDialog() override; + +    BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b) override; + +    void *getPlatformWindow() override; + +    void bringToFront() override; +     +    void setLanguageTextInput(const LLCoordGL& pos) override; + +    void spawnWebBrowser(const std::string &escaped_url, bool async) override; + +    void openFile(const std::string &file_name); + +    void setTitle(const std::string title) override;      static std::vector<std::string> getDynamicFallbackFontList(); @@ -132,40 +188,54 @@ public:      Window mSDL_XWindowID;      Display *mSDL_Display;  #endif +      void (*Lock_Display)(void); -    void (*Unlock_Display)(void); -#if LL_GTK -    // Lazily initialize and check the runtime GTK version for goodness. -    static bool ll_try_gtk_init(void); -#endif // LL_GTK +    void (*Unlock_Display)(void);  #if LL_X11 +      static Window get_SDL_XWindowID(void); -    static Display* get_SDL_Display(void); + +    static Display *get_SDL_Display(void); +  #endif // LL_X11 +    void *createSharedContext() override; + +    void makeContextCurrent(void *context) override; + +    void destroySharedContext(void *context) override; + +    void toggleVSync(bool enable_vsync) override; + +    U32 getAvailableVRAMMegabytes() override; +  protected: -    LLWindowSDL(LLWindowCallbacks* callbacks, -        const std::string& title, int x, int y, int width, int height, U32 flags, -        BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl, -        BOOL ignore_pixel_depth, U32 fsaa_samples); +    LLWindowSDL(LLWindowCallbacks *callbacks, +                const std::string &title, int x, int y, int width, int height, U32 flags, +                BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl, +                BOOL ignore_pixel_depth, U32 fsaa_samples); +      ~LLWindowSDL(); -    /*virtual*/ BOOL    isValid(); -    /*virtual*/ LLSD    getNativeKeyData(); +    BOOL isValid() override; + +    LLSD getNativeKeyData() override; + +    void initCursors(); -    void    initCursors(); -    void    quitCursors(); -    void    moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); +    void quitCursors(); + +    void moveWindow(const LLCoordScreen &position, const LLCoordScreen &size);      // Changes display resolution. Returns true if successful -    BOOL    setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); +    BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh);      // Go back to last fullscreen display resolution. -    BOOL    setFullscreenResolution(); +    BOOL setFullscreenResolution(); -    BOOL    shouldPostQuit() { return mPostQuit; } +    BOOL shouldPostQuit() { return mPostQuit; }  protected:      // @@ -174,46 +244,84 @@ protected:      // create or re-create the GL context/window.  Called from the constructor and switchContext().      BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync); +      void destroyContext(); -    void setupFailure(const std::string& text, const std::string& caption, U32 type); + +    void setupFailure(const std::string &text, const std::string &caption, U32 type); +      void fixWindowSize(void); -    U32 SDLCheckGrabbyKeys(SDLKey keysym, BOOL gain); + +    U32 SDLCheckGrabbyKeys(U32 keysym, BOOL gain); +      BOOL SDLReallyCaptureInput(BOOL capture);      //      // Platform specific variables      // -    U32             mGrabbyKeyFlags; -    int         mReallyCapturedCount; -    SDL_Surface *   mWindow; +    U32 mGrabbyKeyFlags; +    int mReallyCapturedCount; + +    SDL_Window *mWindow; +    SDL_Surface *mSurface; +    SDL_GLContext mContext; +    SDL_Cursor *mSDLCursors[UI_CURSOR_COUNT]; +      std::string mWindowTitle; -    double      mOriginalAspectRatio; -    BOOL        mNeedsResize;       // Constructor figured out the window is too big, it needs a resize. -    LLCoordScreen   mNeedsResizeSize; -    F32         mOverrideAspectRatio; -    F32     mGamma; -    U32     mFSAASamples; +    double mOriginalAspectRatio; +    BOOL mNeedsResize;        // Constructor figured out the window is too big, it needs a resize. +    LLCoordScreen mNeedsResizeSize; +    F32 mOverrideAspectRatio; +    F32 mGamma; +    U32 mFSAASamples; -    int     mSDLFlags; +    int mSDLFlags; -    SDL_Cursor* mSDLCursors[UI_CURSOR_COUNT]; -    int             mHaveInputFocus; /* 0=no, 1=yes, else unknown */ -    int             mIsMinimized; /* 0=no, 1=yes, else unknown */ +    int mHaveInputFocus; /* 0=no, 1=yes, else unknown */ +    int mIsMinimized; /* 0=no, 1=yes, else unknown */      friend class LLWindowManager;  private:  #if LL_X11 +      void x11_set_urgent(BOOL urgent); +      BOOL mFlashing;      LLTimer mFlashTimer;  #endif //LL_X11 -    U32 mKeyScanCode; -        U32 mKeyVirtualKey; -    SDLMod mKeyModifiers; -}; +    U32 mKeyVirtualKey; +    U32 mKeyModifiers; +    std::string mInputType; + +public: +#if LL_X11 + +    static Display *getSDLDisplay(); +    LLWString const &getPrimaryText() const { return mPrimaryClipboard; } + +    LLWString const &getSecondaryText() const { return mSecondaryClipboard; } + +    void clearPrimaryText() { mPrimaryClipboard.clear(); } + +    void clearSecondaryText() { mSecondaryClipboard.clear(); } + +private: +    void tryFindFullscreenSize(int &aWidth, int &aHeight); + +    void initialiseX11Clipboard(); + +    bool getSelectionText(Atom selection, LLWString &text); + +    bool getSelectionText(Atom selection, Atom type, LLWString &text); + +    bool setSelectionText(Atom selection, const LLWString &text); + +#endif +    LLWString mPrimaryClipboard; +    LLWString mSecondaryClipboard; +};  class LLSplashScreenSDL : public LLSplashScreen  { @@ -221,9 +329,9 @@ public:      LLSplashScreenSDL();      virtual ~LLSplashScreenSDL(); -    /*virtual*/ void showImpl(); -    /*virtual*/ void updateImpl(const std::string& mesg); -    /*virtual*/ void hideImpl(); +    void showImpl(); +    void updateImpl(const std::string& mesg); +    void hideImpl();  };  S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index d6b93b93d9..12cd5320b8 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -163,18 +163,7 @@ HGLRC SafeCreateContext(HDC &hdc)  GLuint SafeChoosePixelFormat(HDC &hdc, const PIXELFORMATDESCRIPTOR *ppfd)  { -    __try -    { -        return ChoosePixelFormat(hdc, ppfd); -    } -    __except (EXCEPTION_EXECUTE_HANDLER) -    { -        // convert to C++ styled exception -        // C exception don't allow classes, so it's a regular char array -        char integer_string[32]; -        sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); -        throw std::exception(integer_string); -    } +    return LL::seh::catcher([hdc, ppfd]{ return ChoosePixelFormat(hdc, ppfd); });  }  //static diff --git a/indra/llxml/llxmltree.cpp b/indra/llxml/llxmltree.cpp index baf2e6a951..cd41aa6f2d 100644 --- a/indra/llxml/llxmltree.cpp +++ b/indra/llxml/llxmltree.cpp @@ -108,14 +108,17 @@ LLXmlTreeNode::LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LL  LLXmlTreeNode::~LLXmlTreeNode()  { -    attribute_map_t::iterator iter; -    for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++) -        delete iter->second; -        for(LLXmlTreeNode* node : mChildren) -        { -            delete node; -        } -        mChildren.clear(); +    for (auto& attr : mAttributes) +    { +        delete attr.second; +    } +    mAttributes.clear(); + +    for (auto& child : mChildren) +    { +        delete child; +    } +    mChildren.clear();  }  void LLXmlTreeNode::dump( const std::string& prefix ) diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt index 972bb7dd2d..86c46cb476 100644 --- a/indra/media_plugins/CMakeLists.txt +++ b/indra/media_plugins/CMakeLists.txt @@ -3,8 +3,9 @@  add_subdirectory(base)  if (LINUX) -    #add_subdirectory(gstreamer010) +    add_subdirectory(cef)      add_subdirectory(example) +    add_subdirectory(gstreamer10)  endif (LINUX)  if (DARWIN) diff --git a/indra/media_plugins/base/CMakeLists.txt b/indra/media_plugins/base/CMakeLists.txt index 64b6a4228d..5e635c6ca3 100644 --- a/indra/media_plugins/base/CMakeLists.txt +++ b/indra/media_plugins/base/CMakeLists.txt @@ -12,13 +12,6 @@ include(PluginAPI)  ### media_plugin_base -if(NOT ADDRESS_SIZE EQUAL 32) -  if(WINDOWS) -    ##add_definitions(/FIXED:NO) -  else(WINDOWS) # not windows therefore gcc LINUX and DARWIN -    add_definitions(-fPIC) -  endif(WINDOWS) -endif(NOT ADDRESS_SIZE EQUAL 32)  set(media_plugin_base_SOURCE_FILES      media_plugin_base.cpp diff --git a/indra/media_plugins/base/media_plugin_base.cpp b/indra/media_plugins/base/media_plugin_base.cpp index 545eee25a9..b21f29ac32 100644 --- a/indra/media_plugins/base/media_plugin_base.cpp +++ b/indra/media_plugins/base/media_plugin_base.cpp @@ -167,6 +167,56 @@ void MediaPluginBase::sendStatus()      sendMessage(message);  } +#if LL_LINUX + +size_t SymbolGrabber::registerSymbol( SymbolToGrab aSymbol ) +{ +    gSymbolsToGrab.emplace_back(aSymbol); +    return gSymbolsToGrab.size(); +} + +bool SymbolGrabber::grabSymbols(std::vector< std::string > const &aDSONames) +{ +    std::cerr << "SYMBOLS: " << gSymbolsToGrab.size() << std::endl; + +    if (sSymsGrabbed) +        return true; + +    //attempt to load the shared libraries +    apr_pool_create(&sSymDSOMemoryPool, nullptr); + +    for( std::vector< std::string >::const_iterator itr = aDSONames.begin(); itr != aDSONames.end(); ++itr ) +    { +        apr_dso_handle_t *pDSO(NULL); +        std::string strDSO{ *itr }; +        if( APR_SUCCESS == apr_dso_load( &pDSO, strDSO.c_str(), sSymDSOMemoryPool )) +            sLoadedLibraries.push_back( pDSO ); + +        for( auto i = 0; i < gSymbolsToGrab.size(); ++i ) +        { +            if( !*gSymbolsToGrab[i].mPPFunc ) +                apr_dso_sym( gSymbolsToGrab[i].mPPFunc, pDSO, gSymbolsToGrab[i].mName ); +        } +    } + +    bool sym_error = false; + +    for( auto i = 0; i < gSymbolsToGrab.size(); ++i ) +    { +        if( gSymbolsToGrab[ i ].mRequired && ! *gSymbolsToGrab[ i ].mPPFunc ) +            sym_error = true; +    } + +    sSymsGrabbed = !sym_error; +    return sSymsGrabbed; +} + +void SymbolGrabber::ungrabSymbols() +{ + +} +#endif +  #if LL_WINDOWS  # define LLSYMEXPORT __declspec(dllexport) @@ -204,3 +254,50 @@ int WINAPI DllEntryPoint( HINSTANCE hInstance, unsigned long reason, void* param      return 1;  }  #endif + +#if LL_LINUX +pid_t getParentPid( pid_t aPid ) +{ +    std::stringstream strm; +    strm << "/proc/" << aPid << "/status"; +    std::ifstream in{ strm.str() }; + +    if( !in.is_open() ) +        return 0; + +    pid_t res {0}; +    while( !in.eof() && res == 0 ) +    { +        std::string line; +        line.resize( 1024, 0 ); +        in.getline( &line[0], line.length() );	 + +        auto i = line.find( "PPid:"  ); +         +        if( i == std::string::npos ) +            continue; +         +        char const *pIn = line.c_str() + 5; // Skip over pid; +        while( *pIn != 0 && isspace( *pIn ) ) +               ++pIn; + +        if( *pIn ) +            res = atoll( pIn ); +    } +     return res; +} + +bool isPluginPid( pid_t aPid ) +{ +    auto myPid = getpid(); + +    do +    { +        if( aPid == myPid ) +            return true; +        aPid = getParentPid( aPid ); +    } while( aPid > 1 ); + +    return false; +} +#endif diff --git a/indra/media_plugins/base/media_plugin_base.h b/indra/media_plugins/base/media_plugin_base.h index f65c712a66..a084fc9834 100644 --- a/indra/media_plugins/base/media_plugin_base.h +++ b/indra/media_plugins/base/media_plugin_base.h @@ -32,6 +32,41 @@  #include "llpluginmessage.h"  #include "llpluginmessageclasses.h" +#if LL_LINUX + +struct SymbolToGrab +{ +    bool mRequired; +    char const *mName; +    apr_dso_handle_sym_t *mPPFunc; +}; + +class SymbolGrabber +{ +public: +    size_t registerSymbol( SymbolToGrab aSymbol ); +    bool grabSymbols(std::vector< std::string > const &aDSONames); +    void ungrabSymbols(); + +private: +    std::vector< SymbolToGrab > gSymbolsToGrab; + +    bool sSymsGrabbed = false; +    apr_pool_t *sSymDSOMemoryPool = nullptr; +    std::vector<apr_dso_handle_t *> sLoadedLibraries; +}; + +extern SymbolGrabber gSymbolGrabber; + +// extern SymbolGrabber gSymbolGrabber; + +#define LL_GRAB_SYM(SYMBOL_GRABBER, REQUIRED, SYMBOL_NAME, RETURN, ...) \ +    RETURN (*ll##SYMBOL_NAME)(__VA_ARGS__) = nullptr; \ +    size_t gRegistered##SYMBOL_NAME = SYMBOL_GRABBER.registerSymbol( \ +        { REQUIRED, #SYMBOL_NAME , (apr_dso_handle_sym_t*)&ll##SYMBOL_NAME} \ +    ); + +#endif  class MediaPluginBase  { @@ -46,7 +81,6 @@ public:      static void staticReceiveMessage(const char *message_string, void **user_data);  protected: -     /** Plugin status. */      typedef enum      { @@ -126,4 +160,7 @@ int init_media_plugin(      LLPluginInstance::sendMessageFunction *plugin_send_func,      void **plugin_user_data); - +#if LL_LINUX +pid_t getParentPid(pid_t aPid); +bool isPluginPid(pid_t aPid); +#endif diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt index 410778114d..2c4ccd46d7 100644 --- a/indra/media_plugins/cef/CMakeLists.txt +++ b/indra/media_plugins/cef/CMakeLists.txt @@ -10,18 +10,10 @@ include(Linking)  include(PluginAPI)  include(CEFPlugin) - +include(GLIB)  ### media_plugin_cef -if(NOT ADDRESS_SIZE EQUAL 32) -  if(WINDOWS) -    ##add_definitions(/FIXED:NO) -  else(WINDOWS) # not windows therefore gcc LINUX and DARWIN -    add_definitions(-fPIC) -  endif(WINDOWS) -endif(NOT ADDRESS_SIZE EQUAL 32) -  set(media_plugin_cef_SOURCE_FILES      media_plugin_cef.cpp      ) @@ -32,10 +24,36 @@ set(media_plugin_cef_HEADER_FILES  # Select which VolumeCatcher implementation to use  if (LINUX) -  message(FATAL_ERROR "CEF plugin has been enabled for a Linux compile.\n" -    "  Please create a volume_catcher implementation for this platform.") +  foreach( PULSE_FILE pulse/introspect.h pulse/context.h pulse/subscribe.h pulse/glib-mainloop.h ) +    find_path( PULSE_FILE_${PULSE_FILE}_FOUND ${PULSE_FILE} NO_CACHE) +    if( NOT PULSE_FILE_${PULSE_FILE}_FOUND ) +      message( "Looking for ${PULSE_FILE} ... not found") +      message( FATAL_ERROR "Pulse header not found" ) +    else() +      message( "Looking for ${PULSE_FILE} ... found") +    endif() +  endforeach() +   +  include(FindPipeWire) +  include_directories(SYSTEM ${PIPEWIRE_INCLUDE_DIRS} ${SPA_INCLUDE_DIRS}) +   +  message( "Building with Linux volume catcher for PipeWire and PulseAudio" ) + +  list(APPEND media_plugin_cef_HEADER_FILES +    linux/volume_catcher_linux.h +  ) + +  set(LINUX_VOLUME_CATCHER  +    linux/volume_catcher_linux.cpp  +    linux/volume_catcher_pulseaudio.cpp +    linux/volume_catcher_pipewire.cpp  +  ) + +  list(APPEND media_plugin_cef_SOURCE_FILES ${LINUX_VOLUME_CATCHER}) +  set(CMAKE_SHARED_LINKER_FLAGS  "-Wl,--build-id -Wl,-rpath,'$ORIGIN:$ORIGIN/../../lib'") +  list(APPEND media_plugin_cef_LINK_LIBRARIES llwindow )  elseif (DARWIN) -  list(APPEND media_plugin_cef_SOURCE_FILES mac_volume_catcher_null.cpp) +  list(APPEND media_plugin_cef_SOURCE_FILES volume_catcher_null.cpp)    find_library(CORESERVICES_LIBRARY CoreServices)    find_library(AUDIOUNIT_LIBRARY AudioUnit)    set( media_plugin_cef_LINK_LIBRARIES @@ -60,6 +78,7 @@ add_library(media_plugin_cef  target_link_libraries(media_plugin_cef          media_plugin_base          ll::cef +        ll::glib_headers  )  if (WINDOWS) diff --git a/indra/media_plugins/cef/linux/volume_catcher_linux.cpp b/indra/media_plugins/cef/linux/volume_catcher_linux.cpp new file mode 100644 index 0000000000..7d33242063 --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_linux.cpp @@ -0,0 +1,78 @@ +/** + * @file volume_catcher.cpp + * @brief Linux volume catcher which will pick an implementation to use + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + * @endcond + */ + +#include "volume_catcher_linux.h" + +VolumeCatcher::VolumeCatcher() +{ +} + +void VolumeCatcher::onEnablePipeWireVolumeCatcher(bool enable) +{ +    if (pimpl != nullptr) +        return; + +    if (enable) +    { +        LL_DEBUGS() << "volume catcher using pipewire" << LL_ENDL; +        pimpl = new VolumeCatcherPipeWire(); +    } +    else +    { +        LL_DEBUGS() << "volume catcher using pulseaudio" << LL_ENDL; +        pimpl = new VolumeCatcherPulseAudio(); +    } +} + +VolumeCatcher::~VolumeCatcher() +{ +    if (pimpl != nullptr) +    { +        delete pimpl; +        pimpl = nullptr; +    } +} + +void VolumeCatcher::setVolume(F32 volume) +{ +    if (pimpl != nullptr) { +        pimpl->setVolume(volume); +    } +} + +void VolumeCatcher::setPan(F32 pan) +{ +    if (pimpl != nullptr) +        pimpl->setPan(pan); +} + +void VolumeCatcher::pump() +{ +    if (pimpl != nullptr) +        pimpl->pump(); +} diff --git a/indra/media_plugins/cef/linux/volume_catcher_linux.h b/indra/media_plugins/cef/linux/volume_catcher_linux.h new file mode 100644 index 0000000000..505f9ffb31 --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_linux.h @@ -0,0 +1,149 @@ +/** + * @file volume_catcher_impl.h + * @brief + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + * @endcond + */ + +#ifndef VOLUME_CATCHER_LINUX_H +#define VOLUME_CATCHER_LINUX_H + +#include "linden_common.h" + +#include "../volume_catcher.h" + +#include <unordered_set> +#include <mutex> + +extern "C" { +// There's no special reason why we want the *glib* PA mainloop, but the generic polling implementation seems broken. +#include <pulse/glib-mainloop.h> +#include <pulse/context.h> + +#include <pipewire/pipewire.h> + +#include "apr_pools.h" +#include "apr_dso.h" +} + +#include "media_plugin_base.h" + +class VolumeCatcherImpl +{ +public: +    virtual ~VolumeCatcherImpl() = default; + +    virtual void setVolume(F32 volume) = 0; // 0.0 - 1.0 + +    // Set the left-right pan of audio sources +    // where -1.0 = left, 0 = center, and 1.0 = right +    virtual void setPan(F32 pan) = 0; + +    virtual void pump() = 0; // call this at least a few times a second if you can - it affects how quickly we can 'catch' a new audio source and adjust its volume +}; + +class VolumeCatcherPulseAudio : public VolumeCatcherImpl +{ +public: +    VolumeCatcherPulseAudio(); +    ~VolumeCatcherPulseAudio(); + +    void setVolume(F32 volume); +    void setPan(F32 pan); +    void pump(); + +    // for internal use - can't be private because used from our C callbacks + +    bool loadsyms(std::string pa_dso_name); +    void init(); +    void cleanup(); + +    void update_all_volumes(F32 volume); +    void update_index_volume(U32 index, F32 volume); +    void connected_okay(); + +    std::set<U32> mSinkInputIndices; +    std::map<U32,U32> mSinkInputNumChannels; +    F32 mDesiredVolume; +    pa_glib_mainloop *mMainloop; +    pa_context *mPAContext; +    bool mConnected; +    bool mGotSyms; +}; + +class VolumeCatcherPipeWire : public VolumeCatcherImpl +{ +public: +    VolumeCatcherPipeWire(); +    ~VolumeCatcherPipeWire(); + +    bool loadsyms(std::string pw_dso_name); +    void init(); +    void cleanup(); + +    // some of these should be private + +    void lock(); +    void unlock(); + +    void setVolume(F32 volume); +    void setPan(F32 pan); +    void pump(); + +    void handleRegistryEventGlobal( +        uint32_t id, uint32_t permissions, const char* type, +        uint32_t version, const struct spa_dict* props +    ); + +    class ChildNode +    { +    public: +        bool mActive = false; + +        pw_proxy* mProxy = nullptr; +        spa_hook mNodeListener {}; +        spa_hook mProxyListener {}; +        VolumeCatcherPipeWire* mImpl = nullptr; + +        void updateVolume(); +        void destroy(); +    }; + +    bool mGotSyms = false; + +    F32 mVolume = 1.0f; // max by default +    // F32 mPan = 0.0f; // center + +    pw_thread_loop* mThreadLoop = nullptr; +    pw_context* mContext = nullptr; +    pw_core* mCore = nullptr; +    pw_registry* mRegistry = nullptr; +    spa_hook mRegistryListener; + +    std::unordered_set<ChildNode*> mChildNodes; +    std::mutex mChildNodesMutex; +    std::mutex mCleanupMutex; +}; + +#endif // VOLUME_CATCHER_LINUX_H diff --git a/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp b/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp new file mode 100755 index 0000000000..27fea547c9 --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp @@ -0,0 +1,333 @@ +/**  + * @file volume_catcher_pipewire.cpp + * @brief A Linux-specific, PipeWire-specific hack to detect and volume-adjust new audio sources + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + * @endcond + */ + +/* +  The high-level design is as follows: +  1) Connect to the PipeWire daemon +  2) Find all existing and new audio nodes +  3) Examine PID and parent PID's to see if it belongs to our process +  4) If so, tell PipeWire to adjust the volume of that node +  5) Keep a list of all audio nodes and adjust when we setVolume() + */ + +#include "linden_common.h" + +#include "volume_catcher_linux.h" + +extern "C" { +#include <spa/pod/builder.h> +#include <spa/param/props.h> +} + +SymbolGrabber pwSymbolGrabber; + +#include "volume_catcher_pipewire_syms.inc" + +//////////////////////////////////////////////////// + +VolumeCatcherPipeWire::VolumeCatcherPipeWire() +{ +    init(); +} + +VolumeCatcherPipeWire::~VolumeCatcherPipeWire() +{ +    cleanup(); +} + +static void registryEventGlobal( +    void *data, uint32_t id, uint32_t permissions, const char *type, +    uint32_t version, const struct spa_dict *props) +{ +    static_cast<VolumeCatcherPipeWire*>(data)->handleRegistryEventGlobal( +        id, permissions, type, version, props +    ); +} + +static const struct pw_registry_events REGISTRY_EVENTS = { +    .version = PW_VERSION_REGISTRY_EVENTS, +    .global = registryEventGlobal, +}; + +bool VolumeCatcherPipeWire::loadsyms(std::string pw_dso_name) +{ +    return pwSymbolGrabber.grabSymbols({ pw_dso_name }); +} + +void VolumeCatcherPipeWire::init() +{ +    LL_DEBUGS() << "init" << LL_ENDL; + +    mGotSyms = loadsyms("libpipewire-0.3.so.0"); + +    if (!mGotSyms) +        return; + +    LL_DEBUGS() << "successfully got symbols" << LL_ENDL; + +    llpw_init(nullptr, nullptr); + +    mThreadLoop = llpw_thread_loop_new("SL Plugin Volume Adjuster", nullptr); + +    if (!mThreadLoop) +        return; + +    // i dont think we need to lock this early +    // std::lock_guard pwLock(*this); + +    mContext = llpw_context_new( +        llpw_thread_loop_get_loop(mThreadLoop), nullptr, 0 +    ); + +    if (!mContext) +        return; + +    mCore = llpw_context_connect(mContext, nullptr, 0); + +    if (!mCore) +        return; + +    mRegistry = pw_core_get_registry(mCore, PW_VERSION_REGISTRY, 0); + +    LL_DEBUGS() << "pw_core_get_registry: " <<  (mRegistry?"success":"nullptr") << LL_ENDL; + +    spa_zero(mRegistryListener); + +    pw_registry_add_listener( +        mRegistry, &mRegistryListener, ®ISTRY_EVENTS, this +    ); + +    llpw_thread_loop_start(mThreadLoop); + +    LL_DEBUGS() << "thread loop started" << LL_ENDL; +} + +void VolumeCatcherPipeWire::cleanup() +{ +    { +        std::unique_lock childNodesLock(mChildNodesMutex); +        for (auto *childNode: mChildNodes) +            childNode->destroy(); + +        mChildNodes.clear(); +    } + +    { +        std::unique_lock pwLock(mCleanupMutex); +        if (mRegistry) +            llpw_proxy_destroy((struct pw_proxy *) mRegistry); + +        spa_zero(mRegistryListener); + +        if (mCore) +            llpw_core_disconnect(mCore); +        if (mContext) +            llpw_context_destroy(mContext); +    } + +    if (!mThreadLoop) +        return; + +    llpw_thread_loop_stop(mThreadLoop); +    llpw_thread_loop_destroy(mThreadLoop); + +    LL_DEBUGS() << "cleanup done" << LL_ENDL; +} + +void VolumeCatcherPipeWire::lock() +{ +    if (!mThreadLoop) +        return; + +    llpw_thread_loop_lock(mThreadLoop); +} + +void VolumeCatcherPipeWire::unlock() +{ +    if (!mThreadLoop) +        return; + +    llpw_thread_loop_unlock(mThreadLoop); +} + +const uint32_t channels = 1; +const float resetVolumes[channels] = { 1.0f }; + +void VolumeCatcherPipeWire::ChildNode::updateVolume() +{ +    if (!mActive) +        return; + +    F32 volume = std::clamp(mImpl->mVolume, 0.0f, 1.0f); + +    const float volumes[channels] = { volume }; + +    uint8_t buffer[512]; + +    spa_pod_builder builder; +    spa_pod_builder_init(&builder, buffer, sizeof(buffer)); + +    spa_pod_frame frame; +    spa_pod_builder_push_object(&builder, &frame, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props); + +    // resets system-wide memorized volume for chromium (not google chrome) to 100% +    spa_pod_builder_prop(&builder, SPA_PROP_channelVolumes, 0); +    spa_pod_builder_array(&builder, sizeof(float), SPA_TYPE_Float, channels, resetVolumes); + +    // sets temporary volume +    spa_pod_builder_prop(&builder, SPA_PROP_softVolumes, 0); +    spa_pod_builder_array(&builder, sizeof(float), SPA_TYPE_Float, channels, volumes); + +    spa_pod* pod = static_cast<spa_pod*>(spa_pod_builder_pop(&builder, &frame)); + +    { +        std::lock_guard pwLock(*mImpl); +        pw_node_set_param(mProxy, SPA_PARAM_Props, 0, pod); +    } +} + +void VolumeCatcherPipeWire::ChildNode::destroy() +{ +    if (!mActive) +        return; + +    mActive = false; + +    { +        std::unique_lock childNodesLock(mImpl->mChildNodesMutex); +        mImpl->mChildNodes.erase(this); +    } + +    spa_hook_remove(&mNodeListener); +    spa_hook_remove(&mProxyListener); + +    { +        std::lock_guard pwLock(*mImpl); +        llpw_proxy_destroy(mProxy); +    } +} + +static void nodeEventInfo(void* data, const struct pw_node_info* info) +{ +    const char* processId = spa_dict_lookup(info->props, PW_KEY_APP_PROCESS_ID); + +    if (processId == nullptr) +        return; + +    pid_t pid = atoll(processId); + +    if (!isPluginPid(pid)) +        return; + +    const char* appName = spa_dict_lookup(info->props, PW_KEY_APP_NAME); +    LL_DEBUGS() << "got app: " << appName << LL_ENDL; + +    auto* const childNode = static_cast<VolumeCatcherPipeWire::ChildNode*>(data); +    LL_DEBUGS() << "init volume: " << childNode->mImpl->mVolume  << LL_ENDL; + +    childNode->updateVolume(); + +    { +        std::lock_guard childNodesLock(childNode->mImpl->mChildNodesMutex); +        childNode->mImpl->mChildNodes.insert(childNode); +    } +} + +static const struct pw_node_events NODE_EVENTS = { +    .version = PW_VERSION_CLIENT_EVENTS, +    .info = nodeEventInfo, +}; + +static void proxyEventDestroy(void* data) +{ +    auto* const childNode = static_cast<VolumeCatcherPipeWire::ChildNode*>(data); +    childNode->destroy(); +} + +static void proxyEventRemoved(void* data) +{ +    auto* const childNode = static_cast<VolumeCatcherPipeWire::ChildNode*>(data); +    childNode->destroy(); +} + +static const struct pw_proxy_events PROXY_EVENTS = { +    .version = PW_VERSION_PROXY_EVENTS, +    .destroy = proxyEventDestroy, +    .removed = proxyEventRemoved, +}; + +void VolumeCatcherPipeWire::handleRegistryEventGlobal( +    uint32_t id, uint32_t permissions, const char *type, uint32_t version, +    const struct spa_dict *props) +{ +    if (props == nullptr  || type == nullptr || strcmp(type, PW_TYPE_INTERFACE_Node) != 0) +        return; + +    const char* mediaClass = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS); + +    if (mediaClass == nullptr || strcmp(mediaClass, "Stream/Output/Audio") != 0) +        return; + +    pw_proxy* proxy = static_cast<pw_proxy*>( +        pw_registry_bind(mRegistry, id, type, PW_VERSION_CLIENT, sizeof(ChildNode)) +    ); + +    auto* const childNode = static_cast<ChildNode*>(llpw_proxy_get_user_data(proxy)); + +    childNode->mActive = true; +    childNode->mProxy = proxy; +    childNode->mImpl = this; + +    pw_node_add_listener(proxy, &childNode->mNodeListener, &NODE_EVENTS, childNode); +    llpw_proxy_add_listener(proxy, &childNode->mProxyListener, &PROXY_EVENTS, childNode); +} + +void VolumeCatcherPipeWire::setVolume(F32 volume) +{ +    LL_DEBUGS() << "setting volume to: " << volume << LL_ENDL; + +    mVolume = volume; + +    { +        std::unique_lock childNodeslock(mChildNodesMutex); +        std::unordered_set<ChildNode *> copyOfChildNodes(mChildNodes); + +        LL_DEBUGS() << "found " << copyOfChildNodes.size() << " child nodes" << LL_ENDL; + +        for (auto* childNode : copyOfChildNodes) +            childNode->updateVolume(); +    } +} + +void VolumeCatcherPipeWire::setPan(F32 pan) +{ +} + +void VolumeCatcherPipeWire::pump() +{ +} diff --git a/indra/media_plugins/cef/linux/volume_catcher_pipewire_syms.inc b/indra/media_plugins/cef/linux/volume_catcher_pipewire_syms.inc new file mode 100644 index 0000000000..dbc0f5f169 --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_pipewire_syms.inc @@ -0,0 +1,26 @@ +#define G pwSymbolGrabber + +// required symbols to grab +LL_GRAB_SYM(G, true, pw_init, void, int *argc, char **argv[]); +// LL_GRAB_SYM(G, true, pw_main_loop_new, struct pw_main_loop *, const struct spa_dict *props); +// LL_GRAB_SYM(G, true, pw_main_loop_get_loop, struct pw_loop *, struct pw_main_loop *loop); +// LL_GRAB_SYM(G, true, pw_main_loop_destroy, void, struct pw_main_loop *loop); +// LL_GRAB_SYM(G, true, pw_main_loop_run, void, struct pw_main_loop *loop); +LL_GRAB_SYM(G, true, pw_context_new, struct pw_context *, struct pw_loop *main_loop, struct pw_properties *props, size_t user_data_size); +LL_GRAB_SYM(G, true, pw_context_destroy, void, struct pw_context *context); +LL_GRAB_SYM(G, true, pw_context_connect, struct pw_core *, struct pw_context *context, struct pw_properties *properties, size_t user_data_size); +LL_GRAB_SYM(G, true, pw_thread_loop_new, struct pw_thread_loop *, const char *name, const struct spa_dict *props); +LL_GRAB_SYM(G, true, pw_thread_loop_destroy, void, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_get_loop, struct pw_loop *, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_start, int, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_stop, void, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_lock, void, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_unlock, void, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_proxy_add_listener, void, struct pw_proxy *proxy, struct spa_hook *listener, const struct pw_proxy_events *events, void *data); +LL_GRAB_SYM(G, true, pw_proxy_destroy, void, struct pw_proxy *proxy); +LL_GRAB_SYM(G, true, pw_proxy_get_user_data, void *, struct pw_proxy *proxy); +LL_GRAB_SYM(G, true, pw_core_disconnect, int, struct pw_core *core); + +// optional symbols to grab + +#undef G diff --git a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp new file mode 100755 index 0000000000..9417c49d38 --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp @@ -0,0 +1,322 @@ +/**  + * @file volume_catcher_pulseaudio.cpp + * @brief A Linux-specific, PulseAudio-specific hack to detect and volume-adjust new audio sources + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + * @endcond + */ + +/* +  The high-level design is as follows: +  1) Connect to the PulseAudio daemon +  2) Watch for the creation of new audio players connecting to the daemon (this includes ALSA clients running on the PulseAudio emulation layer, such as Flash plugins) +  3) Examine any new audio player's PID to see if it belongs to our own process +  4) If so, tell PA to adjust the volume of that audio player ('sink input' in PA parlance) +  5) Keep a list of all living audio players that we care about, adjust the volumes of all of them when we get a new setVolume() call + */ + +#include "linden_common.h" + +#include "volume_catcher_linux.h" + +extern "C" { +#include <glib.h> +#include <glib-object.h> + +#include <pulse/introspect.h> + +#include <pulse/subscribe.h> +} + +SymbolGrabber paSymbolGrabber; + +#include "volume_catcher_pulseaudio_syms.inc" +#include "volume_catcher_pulseaudio_glib_syms.inc" + +//////////////////////////////////////////////////// + +// PulseAudio requires a chain of callbacks with C linkage +extern "C" { +    void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *i, int eol, void *userdata); +    void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata); +    void callback_context_state(pa_context *context, void *userdata); +} + +VolumeCatcherPulseAudio::VolumeCatcherPulseAudio() +    : mDesiredVolume(0.0f), +      mMainloop(nullptr), +      mPAContext(nullptr), +      mConnected(false), +      mGotSyms(false) +{ +    init(); +} + +VolumeCatcherPulseAudio::~VolumeCatcherPulseAudio() +{ +    cleanup(); +} + +bool VolumeCatcherPulseAudio::loadsyms(std::string pulse_dso_name) +{ +    return paSymbolGrabber.grabSymbols({ pulse_dso_name }); +} + +void VolumeCatcherPulseAudio::init() +{ +    // try to be as defensive as possible because PA's interface is a +    // bit fragile and (for our purposes) we'd rather simply not function +    // than crash + +    // we cheat and rely upon libpulse-mainloop-glib.so.0 to pull-in +    // libpulse.so.0 - this isn't a great assumption, and the two DSOs should +    // probably be loaded separately.  Our Linux DSO framework needs refactoring, +    // we do this sort of thing a lot with practically identical logic... +    mGotSyms = loadsyms("libpulse-mainloop-glib.so.0"); + +    if (!mGotSyms) +        mGotSyms = loadsyms("libpulse.so.0"); + +    if (!mGotSyms) +        return; + +    mMainloop = llpa_glib_mainloop_new(g_main_context_default()); + +    if (mMainloop) +    { +        pa_mainloop_api *api = llpa_glib_mainloop_get_api(mMainloop); + +        if (api) +        { +            pa_proplist *proplist = llpa_proplist_new(); + +            if (proplist) +            { +                llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "multimedia-player"); +                llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.secondlife.viewer.mediaplugvoladjust"); +                llpa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "SL Plugin Volume Adjuster"); +                llpa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, "1"); + +                // plain old pa_context_new() is broken! +                mPAContext = llpa_context_new_with_proplist(api, nullptr, proplist); + +                llpa_proplist_free(proplist); +            } +        } +    } + +    // Now we've set up a PA context and mainloop, try connecting the +    // PA context to a PA daemon. +    if (mPAContext) +    { +        llpa_context_set_state_callback(mPAContext, callback_context_state, this); +        pa_context_flags_t cflags = (pa_context_flags)0; // maybe add PA_CONTEXT_NOAUTOSPAWN? +        if (llpa_context_connect(mPAContext, nullptr, cflags, nullptr) >= 0) +        { +            // Okay!  We haven't definitely connected, but we +            // haven't definitely failed yet. +        } +        else +        { +            // Failed to connect to PA manager... we'll leave +            // things like that.  Perhaps we should try again later. +        } +    } +} + +void VolumeCatcherPulseAudio::cleanup() +{ +    mConnected = false; + +    if (mGotSyms && mPAContext) +    { +        llpa_context_disconnect(mPAContext); +        llpa_context_unref(mPAContext); +    } + +    mPAContext = nullptr; + +    if (mGotSyms && mMainloop) +        llpa_glib_mainloop_free(mMainloop); + +    mMainloop = nullptr; +} + +void VolumeCatcherPulseAudio::setVolume(F32 volume) +{ +    mDesiredVolume = volume; + +    if (!mGotSyms) +        return; + +    if (mConnected && mPAContext) +    { +        update_all_volumes(mDesiredVolume); +    } + +    pump(); +} + +void VolumeCatcherPulseAudio::setPan(F32 pan) +{ +} + +void VolumeCatcherPulseAudio::pump() +{ +    gboolean may_block = FALSE; +    g_main_context_iteration(g_main_context_default(), may_block); +} + +void VolumeCatcherPulseAudio::connected_okay() +{ +    pa_operation *op; + +    // fetch global list of existing sinkinputs +    if ((op = llpa_context_get_sink_input_info_list(mPAContext, +                            callback_discovered_sinkinput, +                            this))) +    { +        llpa_operation_unref(op); +    } + +    // subscribe to future global sinkinput changes +    llpa_context_set_subscribe_callback(mPAContext, +                        callback_subscription_alert, +                        this); +    if ((op = llpa_context_subscribe(mPAContext, (pa_subscription_mask_t) +                     (PA_SUBSCRIPTION_MASK_SINK_INPUT), +                                     nullptr, nullptr))) +    { +        llpa_operation_unref(op); +    } +} + +void VolumeCatcherPulseAudio::update_all_volumes(F32 volume) +{ +    for (std::set<U32>::iterator it = mSinkInputIndices.begin(); +         it != mSinkInputIndices.end(); ++it) +    { +        update_index_volume(*it, volume); +    } +} + +void VolumeCatcherPulseAudio::update_index_volume(U32 index, F32 volume) +{ +    static pa_cvolume cvol; +    llpa_cvolume_set(&cvol, mSinkInputNumChannels[index], +             llpa_sw_volume_from_linear(volume)); + +    pa_context *c = mPAContext; +    uint32_t idx = index; +    const pa_cvolume *cvolumep = &cvol; +    pa_context_success_cb_t cb = nullptr; // okay as null +    void *userdata = nullptr; // okay as null + +    pa_operation *op; +    if ((op = llpa_context_set_sink_input_volume(c, idx, cvolumep, cb, userdata))) +        llpa_operation_unref(op); +} + +void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *sii, int eol, void *userdata) +{ +    VolumeCatcherPulseAudio *impl = dynamic_cast<VolumeCatcherPulseAudio*>((VolumeCatcherPulseAudio*)userdata); +    llassert(impl); + +    if (0 == eol) +    { +        pa_proplist *proplist = sii->proplist; +        pid_t sinkpid = atoll(llpa_proplist_gets(proplist, PA_PROP_APPLICATION_PROCESS_ID)); + +        if (isPluginPid( sinkpid )) // does the discovered sinkinput belong to this process? +        { +            bool is_new = (impl->mSinkInputIndices.find(sii->index) == impl->mSinkInputIndices.end()); + +            impl->mSinkInputIndices.insert(sii->index); +            impl->mSinkInputNumChannels[sii->index] = sii->channel_map.channels; + +            if (is_new) +            { +                // new! +                impl->update_index_volume(sii->index, impl->mDesiredVolume); +            } +            else +            { +                // seen it already, do nothing. +            } +        } +    } +} + +void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata) +{ +    VolumeCatcherPulseAudio *impl = dynamic_cast<VolumeCatcherPulseAudio*>((VolumeCatcherPulseAudio*)userdata); +    llassert(impl); + +    switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) +    { +        case PA_SUBSCRIPTION_EVENT_SINK_INPUT: +            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) ==  PA_SUBSCRIPTION_EVENT_REMOVE) +            { +                // forget this sinkinput, if we were caring about it +                impl->mSinkInputIndices.erase(index); +                impl->mSinkInputNumChannels.erase(index); +            } +            else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) +            { +                // ask for more info about this new sinkinput +                pa_operation *op; +                if ((op = llpa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl))) +                { +                    llpa_operation_unref(op); +                } +            } +            else +            { +                // property change on this sinkinput - we don't care. +            } +            break; + +        default:; +    } +} + +void callback_context_state(pa_context *context, void *userdata) +{ +    VolumeCatcherPulseAudio *impl = dynamic_cast<VolumeCatcherPulseAudio*>((VolumeCatcherPulseAudio*)userdata); +    llassert(impl); + +    switch (llpa_context_get_state(context)) +    { +    case PA_CONTEXT_READY: +        impl->mConnected = true; +        impl->connected_okay(); +        break; +    case PA_CONTEXT_TERMINATED: +        impl->mConnected = false; +        break; +    case PA_CONTEXT_FAILED: +        impl->mConnected = false; +        break; +    default:; +    } +} diff --git a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_glib_syms.inc b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_glib_syms.inc new file mode 100755 index 0000000000..e9b7196e51 --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_glib_syms.inc @@ -0,0 +1,10 @@ +#define G paSymbolGrabber + +// required symbols to grab +LL_GRAB_SYM(G, true, pa_glib_mainloop_free, void, pa_glib_mainloop* g) +LL_GRAB_SYM(G, true, pa_glib_mainloop_get_api, pa_mainloop_api*, pa_glib_mainloop* g) +LL_GRAB_SYM(G, true, pa_glib_mainloop_new, pa_glib_mainloop *, GMainContext *c) + +// optional symbols to grab + +#undef G diff --git a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_syms.inc b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_syms.inc new file mode 100755 index 0000000000..4859a34405 --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_syms.inc @@ -0,0 +1,29 @@ +#define G paSymbolGrabber + +// required symbols to grab +LL_GRAB_SYM(G, true, pa_context_connect, int, pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api) +LL_GRAB_SYM(G, true, pa_context_disconnect, void, pa_context *c) +LL_GRAB_SYM(G, true, pa_context_get_sink_input_info, pa_operation*, pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_get_sink_input_info_list, pa_operation*, pa_context *c, pa_sink_input_info_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_get_state, pa_context_state_t, pa_context *c) +LL_GRAB_SYM(G, true, pa_context_new_with_proplist, pa_context*, pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist) +LL_GRAB_SYM(G, true, pa_context_set_sink_input_volume, pa_operation*, pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_set_state_callback, void, pa_context *c, pa_context_notify_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_set_subscribe_callback, void, pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_subscribe, pa_operation*, pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_unref, void, pa_context *c) +LL_GRAB_SYM(G, true, pa_cvolume_set, pa_cvolume*, pa_cvolume *a, unsigned channels, pa_volume_t v) +LL_GRAB_SYM(G, true, pa_operation_unref, void, pa_operation *o) +LL_GRAB_SYM(G, true, pa_proplist_free, void, pa_proplist* p) +LL_GRAB_SYM(G, true, pa_proplist_gets, const char*, pa_proplist *p, const char *key) +LL_GRAB_SYM(G, true, pa_proplist_new, pa_proplist*, void) +LL_GRAB_SYM(G, true, pa_proplist_sets, int, pa_proplist *p, const char *key, const char *value) +LL_GRAB_SYM(G, true, pa_sw_volume_from_linear, pa_volume_t, double v) +// LL_GRAB_SYM(G, true, pa_mainloop_free, void, pa_mainloop *m) +// LL_GRAB_SYM(G, true, pa_mainloop_get_api, pa_mainloop_api *, pa_mainloop *m) +// LL_GRAB_SYM(G, true, pa_mainloop_iterate, int, pa_mainloop *m, int block, int *retval) +// LL_GRAB_SYM(G, true, pa_mainloop_new, pa_mainloop *, void) + +// optional symbols to grab + +#undef G diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index bcab0eea72..1346dd2a52 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -886,7 +886,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)                  keyEvent(key_event, native_key_data); -#elif LL_WINDOWS +#else                  std::string event = message_in.getValue("event");                  LLSD native_key_data = message_in.getValueLLSD("native_key_data"); @@ -908,6 +908,13 @@ void MediaPluginCEF::receiveMessage(const char* message_string)              {                  mEnableMediaPluginDebugging = message_in.getValueBoolean("enable");              } +#if LL_LINUX +            else if (message_name == "enable_pipewire_volume_catcher") +            { +                bool enable = message_in.getValueBoolean("enable"); +                mVolumeCatcher.onEnablePipeWireVolumeCatcher(enable); +            } +#endif              if (message_name == "pick_file_response")              {                  LLSD file_list_llsd = message_in.getValueLLSD("file_list"); @@ -1050,6 +1057,28 @@ void MediaPluginCEF::keyEvent(dullahan::EKeyEvent key_event, LLSD native_key_dat      mCEFLib->nativeKeyboardEventWin(msg, wparam, lparam);  #endif + +#if LL_LINUX + +    uint32_t native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());       // this is actually the SDL event.key.keysym.sym; +    uint32_t native_virtual_key_win = (uint32_t)(native_key_data["virtual_key_win"].asInteger()); +    uint32_t native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); + +    // only for non-printable keysyms, the actual text input is done in unicodeInput() below +    if (native_virtual_key <= 0x1b || native_virtual_key >= 0x7f) +    { +        // set keypad flag, not sure if this even does anything +        bool keypad = false; +        if (native_virtual_key_win >= 0x60 && native_virtual_key_win <= 0x6f) +        { +            keypad = true; +        } + +        // yes, we send native_virtual_key_win twice because native_virtual_key breaks it +        mCEFLib->nativeKeyboardEventSDL2(key_event, native_virtual_key, native_modifiers, keypad); +    } + +#endif // LL_LINUX  };  void MediaPluginCEF::unicodeInput(std::string event, LLSD native_key_data = LLSD::emptyMap()) @@ -1080,6 +1109,16 @@ void MediaPluginCEF::unicodeInput(std::string event, LLSD native_key_data = LLSD      U64 lparam = ll_U32_from_sd(native_key_data["l_param"]);      mCEFLib->nativeKeyboardEventWin(msg, wparam, lparam);  #endif + +#if LL_LINUX + +    uint32_t native_scan_code = (uint32_t)(native_key_data["sdl_sym"].asInteger()); +    uint32_t native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); +    uint32_t native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); + +    mCEFLib->nativeKeyboardEvent(dullahan::KE_KEY_DOWN, native_scan_code, native_virtual_key, native_modifiers); + +#endif // LL_LINUX  };  //////////////////////////////////////////////////////////////////////////////// diff --git a/indra/media_plugins/cef/volume_catcher.h b/indra/media_plugins/cef/volume_catcher.h index ea97a24947..6933854e8e 100644 --- a/indra/media_plugins/cef/volume_catcher.h +++ b/indra/media_plugins/cef/volume_catcher.h @@ -35,19 +35,20 @@ class VolumeCatcherImpl;  class VolumeCatcher  { - public: +public:      VolumeCatcher();      ~VolumeCatcher(); -    void setVolume(F32 volume); // 0.0 - 1.0 - -    // Set the left-right pan of audio sources -    // where -1.0 = left, 0 = center, and 1.0 = right +    void setVolume(F32 volume);      void setPan(F32 pan); -    void pump(); // call this at least a few times a second if you can - it affects how quickly we can 'catch' a new audio source and adjust its volume +    void pump(); + +#if LL_LINUX +    void onEnablePipeWireVolumeCatcher(bool enable); +#endif - private: +private:      VolumeCatcherImpl *pimpl;  }; diff --git a/indra/media_plugins/cef/mac_volume_catcher_null.cpp b/indra/media_plugins/cef/volume_catcher_null.cpp index c479e24a95..c6028da45b 100644 --- a/indra/media_plugins/cef/mac_volume_catcher_null.cpp +++ b/indra/media_plugins/cef/volume_catcher_null.cpp @@ -1,5 +1,5 @@ -/** - * @file windows_volume_catcher.cpp +/**  + * @file volume_catcher_null.cpp   * @brief A null implementation of volume level control of all audio channels opened by a process.   *        We are using this for the macOS version for now until we can understand how to make the   *        exitising mac_volume_catcher.cpp work without the (now, non-existant) QuickTime dependency @@ -29,67 +29,25 @@   */  #include "volume_catcher.h" -#include "llsingleton.h" -class VolumeCatcherImpl : public LLSingleton<VolumeCatcherImpl> -{ -    LLSINGLETON(VolumeCatcherImpl); -    // This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance. -    ~VolumeCatcherImpl(); - -public: - -    void setVolume(F32 volume); -    void setPan(F32 pan); - -private: -    F32     mVolume; -    F32     mPan; -    bool mSystemIsVistaOrHigher; -}; - -VolumeCatcherImpl::VolumeCatcherImpl() -:   mVolume(1.0f),          // default volume is max -    mPan(0.f)               // default pan is centered -{ -} - -VolumeCatcherImpl::~VolumeCatcherImpl() -{ -} - -void VolumeCatcherImpl::setVolume(F32 volume) -{ -    mVolume = volume; -} - -void VolumeCatcherImpl::setPan(F32 pan) -{   // remember pan for calculating individual channel levels later -    mPan = pan; -}  /////////////////////////////////////////////////////  VolumeCatcher::VolumeCatcher()  { -    pimpl = VolumeCatcherImpl::getInstance();  }  VolumeCatcher::~VolumeCatcher()  { -    // Let the instance persist until exit.  }  void VolumeCatcher::setVolume(F32 volume)  { -    pimpl->setVolume(volume);  }  void VolumeCatcher::setPan(F32 pan)  { -    pimpl->setPan(pan);  }  void VolumeCatcher::pump()  { -    // No periodic tasks are necessary for this implementation.  } diff --git a/indra/media_plugins/cef/windows_volume_catcher.cpp b/indra/media_plugins/cef/windows_volume_catcher.cpp index e7daeb5f74..1e52fee9de 100644 --- a/indra/media_plugins/cef/windows_volume_catcher.cpp +++ b/indra/media_plugins/cef/windows_volume_catcher.cpp @@ -44,7 +44,6 @@ public:  private:      F32     mVolume;      F32     mPan; -    bool mSystemIsVistaOrHigher;  };  VolumeCatcherImpl::VolumeCatcherImpl() diff --git a/indra/media_plugins/example/CMakeLists.txt b/indra/media_plugins/example/CMakeLists.txt index 7d3e7f663b..86e982fbb4 100644 --- a/indra/media_plugins/example/CMakeLists.txt +++ b/indra/media_plugins/example/CMakeLists.txt @@ -13,14 +13,6 @@ include(ExamplePlugin)  ### media_plugin_example -if(NOT ADDRESS_SIZE EQUAL 32) -  if(WINDOWS) -    ##add_definitions(/FIXED:NO) -  else(WINDOWS) # not windows therefore gcc LINUX and DARWIN -    add_definitions(-fPIC) -  endif(WINDOWS) -endif(NOT ADDRESS_SIZE EQUAL 32) -  set(media_plugin_example_SOURCE_FILES      media_plugin_example.cpp      ) diff --git a/indra/media_plugins/gstreamer010/CMakeLists.txt b/indra/media_plugins/gstreamer010/CMakeLists.txt deleted file mode 100644 index 38fc8201bf..0000000000 --- a/indra/media_plugins/gstreamer010/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -# -*- cmake -*- - -project(media_plugin_gstreamer010) - -include(00-Common) -include(LLCommon) -include(LLImage) -include(LLMath) -include(LLWindow) -include(Linking) -include(PluginAPI) -include(OpenGL) - -include(GStreamer010Plugin) - -### media_plugin_gstreamer010 - -if(NOT ADDRESS_SIZE EQUAL 32) -  if(WINDOWS) -    ##add_definitions(/FIXED:NO) -  else(WINDOWS) # not windows therefore gcc LINUX and DARWIN -    add_definitions(-fPIC) -  endif(WINDOWS) -endif(NOT ADDRESS_SIZE EQUAL 32) - -set(media_plugin_gstreamer010_SOURCE_FILES -    media_plugin_gstreamer010.cpp -    llmediaimplgstreamer_syms.cpp -    llmediaimplgstreamervidplug.cpp -    ) - -set(media_plugin_gstreamer010_HEADER_FILES -    llmediaimplgstreamervidplug.h -    llmediaimplgstreamer_syms.h -    llmediaimplgstreamertriviallogging.h -    ) - -add_library(media_plugin_gstreamer010 -    SHARED -    ${media_plugin_gstreamer010_SOURCE_FILES} -    ) - -target_link_libraries(media_plugin_gstreamer010 -        media_plugin_base -        ll::gstreamer -  ) diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp deleted file mode 100644 index dcc04b37e4..0000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/** - * @file llmediaimplgstreamer_syms.cpp - * @brief dynamic GStreamer symbol-grabbing code - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - * @endcond - */ - -#if LL_GSTREAMER010_ENABLED - -#include <string> - -extern "C" { -#include <gst/gst.h> - -#include "apr_pools.h" -#include "apr_dso.h" -} - -#include "llmediaimplgstreamertriviallogging.h" - -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL -#include "llmediaimplgstreamer_syms_raw.inc" -#include "llmediaimplgstreamer_syms_rawv.inc" -#undef LL_GST_SYM - -// a couple of stubs for disgusting reasons -GstDebugCategory* -ll_gst_debug_category_new(gchar *name, guint color, gchar *description) -{ -    static GstDebugCategory dummy; -    return &dummy; -} -void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname) -{ -} - -static bool sSymsGrabbed = false; -static apr_pool_t *sSymGSTDSOMemoryPool = NULL; -static apr_dso_handle_t *sSymGSTDSOHandleG = NULL; -static apr_dso_handle_t *sSymGSTDSOHandleV = NULL; - - -bool grab_gst_syms(std::string gst_dso_name, -           std::string gst_dso_name_vid) -{ -    if (sSymsGrabbed) -    { -        // already have grabbed good syms -        return TRUE; -    } - -    bool sym_error = false; -    bool rtn = false; -    apr_status_t rv; -    apr_dso_handle_t *sSymGSTDSOHandle = NULL; - -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##GSTSYM, sSymGSTDSOHandle, #GSTSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #GSTSYM); if (REQ) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #GSTSYM, (void*)ll##GSTSYM);}while(0) - -    //attempt to load the shared libraries -    apr_pool_create(&sSymGSTDSOMemoryPool, NULL); - -    if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle, -                           gst_dso_name.c_str(), -                           sSymGSTDSOMemoryPool) )) -    { -        INFOMSG("Found DSO: %s", gst_dso_name.c_str()); -#include "llmediaimplgstreamer_syms_raw.inc" - -        if ( sSymGSTDSOHandle ) -        { -            sSymGSTDSOHandleG = sSymGSTDSOHandle; -            sSymGSTDSOHandle = NULL; -        } - -        if ( APR_SUCCESS == -             (rv = apr_dso_load(&sSymGSTDSOHandle, -                    gst_dso_name_vid.c_str(), -                    sSymGSTDSOMemoryPool) )) -        { -            INFOMSG("Found DSO: %s", gst_dso_name_vid.c_str()); -#include "llmediaimplgstreamer_syms_rawv.inc" -            rtn = !sym_error; -        } -        else -        { -            INFOMSG("Couldn't load DSO: %s", gst_dso_name_vid.c_str()); -            rtn = false; // failure -        } -    } -    else -    { -        INFOMSG("Couldn't load DSO: %s", gst_dso_name.c_str()); -        rtn = false; // failure -    } - -    if (sym_error) -    { -        WARNMSG("Failed to find necessary symbols in GStreamer libraries."); -    } - -    if ( sSymGSTDSOHandle ) -    { -        sSymGSTDSOHandleV = sSymGSTDSOHandle; -        sSymGSTDSOHandle = NULL; -    } -#undef LL_GST_SYM - -    sSymsGrabbed = !!rtn; -    return rtn; -} - - -void ungrab_gst_syms() -{ -    // should be safe to call regardless of whether we've -    // actually grabbed syms. - -    if ( sSymGSTDSOHandleG ) -    { -        apr_dso_unload(sSymGSTDSOHandleG); -        sSymGSTDSOHandleG = NULL; -    } - -    if ( sSymGSTDSOHandleV ) -    { -        apr_dso_unload(sSymGSTDSOHandleV); -        sSymGSTDSOHandleV = NULL; -    } - -    if ( sSymGSTDSOMemoryPool ) -    { -        apr_pool_destroy(sSymGSTDSOMemoryPool); -        sSymGSTDSOMemoryPool = NULL; -    } - -    // NULL-out all of the symbols we'd grabbed -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{ll##GSTSYM = NULL;}while(0) -#include "llmediaimplgstreamer_syms_raw.inc" -#include "llmediaimplgstreamer_syms_rawv.inc" -#undef LL_GST_SYM - -    sSymsGrabbed = false; -} - - -#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h deleted file mode 100644 index 57d446c7df..0000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file llmediaimplgstreamer_syms.h - * @brief dynamic GStreamer symbol-grabbing code - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - * @endcond - */ - -#include "linden_common.h" - -#if LL_GSTREAMER010_ENABLED - -extern "C" { -#include <gst/gst.h> -} - -bool grab_gst_syms(std::string gst_dso_name, -           std::string gst_dso_name_vid); -void ungrab_gst_syms(); - -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) extern RTN (*ll##GSTSYM)(__VA_ARGS__) -#include "llmediaimplgstreamer_syms_raw.inc" -#include "llmediaimplgstreamer_syms_rawv.inc" -#undef LL_GST_SYM - -// regrettable hacks to give us better runtime compatibility with older systems -#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0) -#define llg_return_val_if_fail(COND,V) do{if (!(COND)) return V;}while(0) - -// regrettable hacks because GStreamer was not designed for runtime loading -#undef GST_TYPE_MESSAGE -#define GST_TYPE_MESSAGE (llgst_message_get_type()) -#undef GST_TYPE_OBJECT -#define GST_TYPE_OBJECT (llgst_object_get_type()) -#undef GST_TYPE_PIPELINE -#define GST_TYPE_PIPELINE (llgst_pipeline_get_type()) -#undef GST_TYPE_ELEMENT -#define GST_TYPE_ELEMENT (llgst_element_get_type()) -#undef GST_TYPE_VIDEO_SINK -#define GST_TYPE_VIDEO_SINK (llgst_video_sink_get_type()) -// more regrettable hacks to stub-out these .h-exposed GStreamer internals -void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname); -#undef _gst_debug_register_funcptr -#define _gst_debug_register_funcptr ll_gst_debug_register_funcptr -GstDebugCategory* ll_gst_debug_category_new(gchar *name, guint color, gchar *description); -#undef _gst_debug_category_new -#define _gst_debug_category_new ll_gst_debug_category_new -#undef __gst_debug_enabled -#define __gst_debug_enabled (0) - -// more hacks -#define LLGST_MESSAGE_TYPE_NAME(M) (llgst_message_type_get_name(GST_MESSAGE_TYPE(M))) - -#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc deleted file mode 100644 index b33e59363d..0000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc +++ /dev/null @@ -1,51 +0,0 @@ - -// required symbols to grab -LL_GST_SYM(true, gst_pad_peer_accept_caps, gboolean, GstPad *pad, GstCaps *caps); -LL_GST_SYM(true, gst_buffer_new, GstBuffer*, void); -LL_GST_SYM(true, gst_buffer_set_caps, void, GstBuffer*, GstCaps *); -LL_GST_SYM(true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*); -LL_GST_SYM(true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err); -LL_GST_SYM(true, gst_message_get_type, GType, void); -LL_GST_SYM(true, gst_message_type_get_name, const gchar*, GstMessageType type); -LL_GST_SYM(true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug); -LL_GST_SYM(true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug); -LL_GST_SYM(true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending); -LL_GST_SYM(true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state); -LL_GST_SYM(true, gst_object_unref, void, gpointer object); -LL_GST_SYM(true, gst_object_get_type, GType, void); -LL_GST_SYM(true, gst_pipeline_get_type, GType, void); -LL_GST_SYM(true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline); -LL_GST_SYM(true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data); -LL_GST_SYM(true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name); -LL_GST_SYM(true, gst_element_get_type, GType, void); -LL_GST_SYM(true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template); -LL_GST_SYM(true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp); -LL_GST_SYM(true, gst_element_class_set_details, void, GstElementClass *klass, const GstElementDetails *details); -LL_GST_SYM(true, gst_caps_unref, void, GstCaps* caps); -LL_GST_SYM(true, gst_caps_ref, GstCaps *, GstCaps* caps); -//LL_GST_SYM(true, gst_caps_is_empty, gboolean, const GstCaps *caps); -LL_GST_SYM(true, gst_caps_from_string, GstCaps *, const gchar *string); -LL_GST_SYM(true, gst_caps_replace, void, GstCaps **caps, GstCaps *newcaps); -LL_GST_SYM(true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index); -LL_GST_SYM(true, gst_caps_copy, GstCaps *, const GstCaps * caps); -//LL_GST_SYM(true, gst_caps_intersect, GstCaps *, const GstCaps *caps1, const GstCaps *caps2); -LL_GST_SYM(true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type); -LL_GST_SYM(true, _gst_plugin_register_static, void, GstPluginDesc *desc); -LL_GST_SYM(true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value); -LL_GST_SYM(true, gst_structure_get_value, G_CONST_RETURN GValue *, const GstStructure *structure, const gchar *fieldname); -LL_GST_SYM(true, gst_value_get_fraction_numerator, gint, const GValue *value); -LL_GST_SYM(true, gst_value_get_fraction_denominator, gint, const GValue *value); -LL_GST_SYM(true, gst_structure_get_name, G_CONST_RETURN gchar *, const GstStructure *structure); -LL_GST_SYM(true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64); - -// optional symbols to grab -LL_GST_SYM(false, gst_registry_fork_set_enabled, void, gboolean enabled); -LL_GST_SYM(false, gst_segtrap_set_enabled, void, gboolean enabled); -LL_GST_SYM(false, gst_message_parse_buffering, void, GstMessage *message, gint *percent); -LL_GST_SYM(false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug); -LL_GST_SYM(false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur); -LL_GST_SYM(false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano); - -// GStreamer 'internal' symbols which may not be visible in some runtimes but are still used in expanded GStreamer header macros - yuck!  We'll substitute our own stubs for these. -//LL_GST_SYM(true, _gst_debug_register_funcptr, void, GstDebugFuncPtr func, gchar* ptrname); -//LL_GST_SYM(true, _gst_debug_category_new, GstDebugCategory *, gchar *name, guint color, gchar *description); diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc deleted file mode 100644 index 14fbcb48b9..0000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc +++ /dev/null @@ -1,5 +0,0 @@ - -// required symbols to grab -LL_GST_SYM(true, gst_video_sink_get_type, GType, void); - -// optional symbols to grab diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h deleted file mode 100644 index 43ebad6744..0000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @file llmediaimplgstreamertriviallogging.h - * @brief minimal logging utilities. - * - * @cond - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - * @endcond - */ - -#ifndef __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ -#define __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ - -#include <cstdio> - -extern "C" { -#include <sys/types.h> -#include <unistd.h> -} - -///////////////////////////////////////////////////////////////////////// -// Debug/Info/Warning macros. -#define MSGMODULEFOO "(media plugin)" -#define STDERRMSG(...) do{\ -    fprintf(stderr, " pid:%d: ", (int)getpid());\ -    fprintf(stderr, MSGMODULEFOO " %s:%d: ", __FUNCTION__, __LINE__);\ -    fprintf(stderr, __VA_ARGS__);\ -    fputc('\n',stderr);\ -  }while(0) -#define NULLMSG(...) do{}while(0) - -#define DEBUGMSG NULLMSG -#define INFOMSG  STDERRMSG -#define WARNMSG  STDERRMSG -///////////////////////////////////////////////////////////////////////// - -#endif /* __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ */ diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp b/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp deleted file mode 100644 index acec0f2399..0000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp +++ /dev/null @@ -1,526 +0,0 @@ -/** - * @file llmediaimplgstreamervidplug.h - * @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - * @endcond - */ - -#if LL_GSTREAMER010_ENABLED - -#include "linden_common.h" - -#include <gst/gst.h> -#include <gst/video/video.h> -#include <gst/video/gstvideosink.h> - -#include "llmediaimplgstreamer_syms.h" -#include "llmediaimplgstreamertriviallogging.h" - -#include "llmediaimplgstreamervidplug.h" - - -GST_DEBUG_CATEGORY_STATIC (gst_slvideo_debug); -#define GST_CAT_DEFAULT gst_slvideo_debug - - -#define SLV_SIZECAPS ", width=(int)[1,2048], height=(int)[1,2048] " -#define SLV_ALLCAPS GST_VIDEO_CAPS_RGBx SLV_SIZECAPS - -static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( -    (gchar*)"sink", -    GST_PAD_SINK, -    GST_PAD_ALWAYS, -    GST_STATIC_CAPS (SLV_ALLCAPS) -    ); - -GST_BOILERPLATE (GstSLVideo, gst_slvideo, GstVideoSink, -    GST_TYPE_VIDEO_SINK); - -static void gst_slvideo_set_property (GObject * object, guint prop_id, -                      const GValue * value, -                      GParamSpec * pspec); -static void gst_slvideo_get_property (GObject * object, guint prop_id, -                      GValue * value, GParamSpec * pspec); - -static void -gst_slvideo_base_init (gpointer gclass) -{ -    static GstElementDetails element_details = { -        (gchar*)"PluginTemplate", -        (gchar*)"Generic/PluginTemplate", -        (gchar*)"Generic Template Element", -        (gchar*)"Linden Lab" -    }; -    GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); - -    llgst_element_class_add_pad_template (element_class, -                  llgst_static_pad_template_get (&sink_factory)); -    llgst_element_class_set_details (element_class, &element_details); -} - - -static void -gst_slvideo_finalize (GObject * object) -{ -    GstSLVideo *slvideo; -    slvideo = GST_SLVIDEO (object); -    if (slvideo->caps) -    { -        llgst_caps_unref(slvideo->caps); -    } - -    G_OBJECT_CLASS(parent_class)->finalize (object); -} - - -static GstFlowReturn -gst_slvideo_show_frame (GstBaseSink * bsink, GstBuffer * buf) -{ -    GstSLVideo *slvideo; -    llg_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); - -    slvideo = GST_SLVIDEO(bsink); - -    DEBUGMSG("transferring a frame of %dx%d <- %p (%d)", -         slvideo->width, slvideo->height, GST_BUFFER_DATA(buf), -         slvideo->format); - -    if (GST_BUFFER_DATA(buf)) -    { -        // copy frame and frame info into neutral territory -        GST_OBJECT_LOCK(slvideo); -        slvideo->retained_frame_ready = TRUE; -        slvideo->retained_frame_width = slvideo->width; -        slvideo->retained_frame_height = slvideo->height; -        slvideo->retained_frame_format = slvideo->format; -        int rowbytes = -            SLVPixelFormatBytes[slvideo->retained_frame_format] * -            slvideo->retained_frame_width; -        int needbytes = rowbytes * slvideo->retained_frame_width; -        // resize retained frame hunk only if necessary -        if (needbytes != slvideo->retained_frame_allocbytes) -        { -            delete[] slvideo->retained_frame_data; -            slvideo->retained_frame_data = new unsigned char[needbytes]; -            slvideo->retained_frame_allocbytes = needbytes; - -        } -        // copy the actual frame data to neutral territory - -        // flipped, for GL reasons -        for (int ypos=0; ypos<slvideo->height; ++ypos) -        { -            memcpy(&slvideo->retained_frame_data[(slvideo->height-1-ypos)*rowbytes], -                   &(((unsigned char*)GST_BUFFER_DATA(buf))[ypos*rowbytes]), -                   rowbytes); -        } -        // done with the shared data -        GST_OBJECT_UNLOCK(slvideo); -    } - -    return GST_FLOW_OK; -} - - -static GstStateChangeReturn -gst_slvideo_change_state(GstElement * element, GstStateChange transition) -{ -    GstSLVideo *slvideo; -    GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - -    slvideo = GST_SLVIDEO (element); - -    switch (transition) { -    case GST_STATE_CHANGE_NULL_TO_READY: -        break; -    case GST_STATE_CHANGE_READY_TO_PAUSED: -        break; -    case GST_STATE_CHANGE_PAUSED_TO_PLAYING: -        break; -    default: -        break; -    } - -    ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); -    if (ret == GST_STATE_CHANGE_FAILURE) -        return ret; - -    switch (transition) { -    case GST_STATE_CHANGE_PLAYING_TO_PAUSED: -        break; -    case GST_STATE_CHANGE_PAUSED_TO_READY: -        slvideo->fps_n = 0; -        slvideo->fps_d = 1; -        GST_VIDEO_SINK_WIDTH(slvideo) = 0; -        GST_VIDEO_SINK_HEIGHT(slvideo) = 0; -        break; -    case GST_STATE_CHANGE_READY_TO_NULL: -        break; -    default: -        break; -    } - -    return ret; -} - - -static GstCaps * -gst_slvideo_get_caps (GstBaseSink * bsink) -{ -    GstSLVideo *slvideo; -    slvideo = GST_SLVIDEO(bsink); - -    return llgst_caps_ref (slvideo->caps); -} - - -/* this function handles the link with other elements */ -static gboolean -gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps) -{ -    GstSLVideo *filter; -    GstStructure *structure; - -    GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps); - -    filter = GST_SLVIDEO(bsink); - -    int width, height; -    gboolean ret; -    const GValue *fps; -    const GValue *par; -    structure = llgst_caps_get_structure (caps, 0); -    ret = llgst_structure_get_int (structure, "width", &width); -    ret = ret && llgst_structure_get_int (structure, "height", &height); -    fps = llgst_structure_get_value (structure, "framerate"); -    ret = ret && (fps != NULL); -    par = llgst_structure_get_value (structure, "pixel-aspect-ratio"); -    if (!ret) -        return FALSE; - -    INFOMSG("** filter caps set with width=%d, height=%d", width, height); - -    GST_OBJECT_LOCK(filter); - -    filter->width = width; -    filter->height = height; - -    filter->fps_n = llgst_value_get_fraction_numerator(fps); -    filter->fps_d = llgst_value_get_fraction_denominator(fps); -    if (par) -    { -        filter->par_n = llgst_value_get_fraction_numerator(par); -        filter->par_d = llgst_value_get_fraction_denominator(par); -    } -    else -    { -        filter->par_n = 1; -        filter->par_d = 1; -    } -    GST_VIDEO_SINK_WIDTH(filter) = width; -    GST_VIDEO_SINK_HEIGHT(filter) = height; - -    // crufty lump - we *always* accept *only* RGBX now. -    /* -    filter->format = SLV_PF_UNKNOWN; -    if (0 == strcmp(llgst_structure_get_name(structure), -            "video/x-raw-rgb")) -    { -        int red_mask; -        int green_mask; -        int blue_mask; -        llgst_structure_get_int(structure, "red_mask", &red_mask); -        llgst_structure_get_int(structure, "green_mask", &green_mask); -        llgst_structure_get_int(structure, "blue_mask", &blue_mask); -        if ((unsigned int)red_mask   == 0xFF000000 && -            (unsigned int)green_mask == 0x00FF0000 && -            (unsigned int)blue_mask  == 0x0000FF00) -        { -            filter->format = SLV_PF_RGBX; -            //fprintf(stderr, "\n\nPIXEL FORMAT RGB\n\n"); -        } else if ((unsigned int)red_mask   == 0x0000FF00 && -               (unsigned int)green_mask == 0x00FF0000 && -               (unsigned int)blue_mask  == 0xFF000000) -        { -            filter->format = SLV_PF_BGRX; -            //fprintf(stderr, "\n\nPIXEL FORMAT BGR\n\n"); -        } -        }*/ - -    filter->format = SLV_PF_RGBX; - -    GST_OBJECT_UNLOCK(filter); - -    return TRUE; -} - - -static gboolean -gst_slvideo_start (GstBaseSink * bsink) -{ -    gboolean ret = TRUE; - -    GST_SLVIDEO(bsink); - -    return ret; -} - -static gboolean -gst_slvideo_stop (GstBaseSink * bsink) -{ -    GstSLVideo *slvideo; -    slvideo = GST_SLVIDEO(bsink); - -    // free-up retained frame buffer -    GST_OBJECT_LOCK(slvideo); -    slvideo->retained_frame_ready = FALSE; -    delete[] slvideo->retained_frame_data; -    slvideo->retained_frame_data = NULL; -    slvideo->retained_frame_allocbytes = 0; -    GST_OBJECT_UNLOCK(slvideo); - -    return TRUE; -} - - -static GstFlowReturn -gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, -              GstCaps * caps, GstBuffer ** buf) -{ -    gint width, height; -    GstStructure *structure = NULL; -    GstSLVideo *slvideo; -    slvideo = GST_SLVIDEO(bsink); - -    // caps == requested caps -    // we can ignore these and reverse-negotiate our preferred dimensions with -    // the peer if we like - we need to do this to obey dynamic resize requests -    // flowing in from the app. -    structure = llgst_caps_get_structure (caps, 0); -    if (!llgst_structure_get_int(structure, "width", &width) || -        !llgst_structure_get_int(structure, "height", &height)) -    { -        GST_WARNING_OBJECT (slvideo, "no width/height in caps %" GST_PTR_FORMAT, caps); -        return GST_FLOW_NOT_NEGOTIATED; -    } - -    GstBuffer *newbuf = llgst_buffer_new(); -    bool made_bufferdata_ptr = false; -#define MAXDEPTHHACK 4 - -    GST_OBJECT_LOCK(slvideo); -    if (slvideo->resize_forced_always) // app is giving us a fixed size to work with -    { -        gint slwantwidth, slwantheight; -        slwantwidth = slvideo->resize_try_width; -        slwantheight = slvideo->resize_try_height; - -        if (slwantwidth != width || -            slwantheight != height) -        { -            // don't like requested caps, we will issue our own suggestion - copy -            // the requested caps but substitute our own width and height and see -            // if our peer is happy with that. - -            GstCaps *desired_caps; -            GstStructure *desired_struct; -            desired_caps = llgst_caps_copy (caps); -            desired_struct = llgst_caps_get_structure (desired_caps, 0); - -            GValue value = {0}; -            g_value_init(&value, G_TYPE_INT); -            g_value_set_int(&value, slwantwidth); -            llgst_structure_set_value (desired_struct, "width", &value); -            g_value_unset(&value); -            g_value_init(&value, G_TYPE_INT); -            g_value_set_int(&value, slwantheight); -            llgst_structure_set_value (desired_struct, "height", &value); - -            if (llgst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (slvideo), -                            desired_caps)) -            { -                // todo: re-use buffers from a pool? -                // todo: set MALLOCDATA to null, set DATA to point straight to shm? - -                // peer likes our cap suggestion -                DEBUGMSG("peer loves us :)"); -                GST_BUFFER_SIZE(newbuf) = slwantwidth * slwantheight * MAXDEPTHHACK; -                GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf)); -                GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf); -                llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), desired_caps); - -                made_bufferdata_ptr = true; -            } else { -                // peer hates our cap suggestion -                INFOMSG("peer hates us :("); -                llgst_caps_unref(desired_caps); -            } -        } -    } - -    GST_OBJECT_UNLOCK(slvideo); - -    if (!made_bufferdata_ptr) // need to fallback to malloc at original size -    { -        GST_BUFFER_SIZE(newbuf) = width * height * MAXDEPTHHACK; -        GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf)); -        GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf); -        llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps); -    } - -    *buf = GST_BUFFER_CAST(newbuf); - -    return GST_FLOW_OK; -} - - -/* initialize the plugin's class */ -static void -gst_slvideo_class_init (GstSLVideoClass * klass) -{ -    GObjectClass *gobject_class; -    GstElementClass *gstelement_class; -    GstBaseSinkClass *gstbasesink_class; - -    gobject_class = (GObjectClass *) klass; -    gstelement_class = (GstElementClass *) klass; -    gstbasesink_class = (GstBaseSinkClass *) klass; - -    gobject_class->finalize = gst_slvideo_finalize; -    gobject_class->set_property = gst_slvideo_set_property; -    gobject_class->get_property = gst_slvideo_get_property; - -    gstelement_class->change_state = gst_slvideo_change_state; - -#define LLGST_DEBUG_FUNCPTR(p) (p) -    gstbasesink_class->get_caps = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_caps); -    gstbasesink_class->set_caps = LLGST_DEBUG_FUNCPTR( gst_slvideo_set_caps); -    gstbasesink_class->buffer_alloc=LLGST_DEBUG_FUNCPTR(gst_slvideo_buffer_alloc); -    //gstbasesink_class->get_times = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_times); -    gstbasesink_class->preroll = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame); -    gstbasesink_class->render = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame); - -    gstbasesink_class->start = LLGST_DEBUG_FUNCPTR (gst_slvideo_start); -    gstbasesink_class->stop = LLGST_DEBUG_FUNCPTR (gst_slvideo_stop); - -    //  gstbasesink_class->unlock = LLGST_DEBUG_FUNCPTR (gst_slvideo_unlock); -#undef LLGST_DEBUG_FUNCPTR -} - - -/* initialize the new element - * instantiate pads and add them to element - * set functions - * initialize structure - */ -static void -gst_slvideo_init (GstSLVideo * filter, -          GstSLVideoClass * gclass) -{ -    filter->caps = NULL; -    filter->width = -1; -    filter->height = -1; - -    // this is the info we share with the client app -    GST_OBJECT_LOCK(filter); -    filter->retained_frame_ready = FALSE; -    filter->retained_frame_data = NULL; -    filter->retained_frame_allocbytes = 0; -    filter->retained_frame_width = filter->width; -    filter->retained_frame_height = filter->height; -    filter->retained_frame_format = SLV_PF_UNKNOWN; -    GstCaps *caps = llgst_caps_from_string (SLV_ALLCAPS); -    llgst_caps_replace (&filter->caps, caps); -    filter->resize_forced_always = false; -    filter->resize_try_width = -1; -    filter->resize_try_height = -1; -    GST_OBJECT_UNLOCK(filter); -} - -static void -gst_slvideo_set_property (GObject * object, guint prop_id, -              const GValue * value, GParamSpec * pspec) -{ -    llg_return_if_fail (GST_IS_SLVIDEO (object)); - -    switch (prop_id) { -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -        break; -    } -} - -static void -gst_slvideo_get_property (GObject * object, guint prop_id, -              GValue * value, GParamSpec * pspec) -{ -    llg_return_if_fail (GST_IS_SLVIDEO (object)); - -    switch (prop_id) { -    default: -        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -        break; -    } -} - - -/* entry point to initialize the plug-in - * initialize the plug-in itself - * register the element factories and pad templates - * register the features - */ -static gboolean -plugin_init (GstPlugin * plugin) -{ -    DEBUGMSG("PLUGIN INIT"); - -    GST_DEBUG_CATEGORY_INIT (gst_slvideo_debug, (gchar*)"private-slvideo-plugin", -                 0, (gchar*)"Second Life Video Sink"); - -    return llgst_element_register (plugin, "private-slvideo", -                       GST_RANK_NONE, GST_TYPE_SLVIDEO); -} - -/* this is the structure that gstreamer looks for to register plugins - */ -/* NOTE: Can't rely upon GST_PLUGIN_DEFINE_STATIC to self-register, since -   some g++ versions buggily avoid __attribute__((constructor)) functions - -   so we provide an explicit plugin init function. - */ -#define PACKAGE (gchar*)"packagehack" -// this macro quietly refers to PACKAGE internally -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, -           GST_VERSION_MINOR, -           (gchar*)"private-slvideoplugin", -           (gchar*)"SL Video sink plugin", -           plugin_init, (gchar*)"1.0", (gchar*)"LGPL", -           (gchar*)"Second Life", -           (gchar*)"http://www.secondlife.com/"); -#undef PACKAGE -void gst_slvideo_init_class (void) -{ -    ll_gst_plugin_register_static (&gst_plugin_desc); -    DEBUGMSG("CLASS INIT"); -} - -#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h deleted file mode 100644 index d4e07daf4f..0000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @file llmediaimplgstreamervidplug.h - * @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - * @endcond - */ - -#ifndef __GST_SLVIDEO_H__ -#define __GST_SLVIDEO_H__ - -#if LL_GSTREAMER010_ENABLED - -extern "C" { -#include <gst/gst.h> -#include <gst/video/video.h> -#include <gst/video/gstvideosink.h> -} - -G_BEGIN_DECLS - -/* #defines don't like whitespacey bits */ -#define GST_TYPE_SLVIDEO \ -  (gst_slvideo_get_type()) -#define GST_SLVIDEO(obj) \ -  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SLVIDEO,GstSLVideo)) -#define GST_SLVIDEO_CLASS(klass) \ -  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SLVIDEO,GstSLVideoClass)) -#define GST_IS_SLVIDEO(obj) \ -  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SLVIDEO)) -#define GST_IS_SLVIDEO_CLASS(klass) \ -  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SLVIDEO)) - -typedef struct _GstSLVideo      GstSLVideo; -typedef struct _GstSLVideoClass GstSLVideoClass; - -typedef enum { -    SLV_PF_UNKNOWN = 0, -    SLV_PF_RGBX    = 1, -    SLV_PF_BGRX    = 2, -    SLV__END       = 3 -} SLVPixelFormat; -const int SLVPixelFormatBytes[SLV__END] = {1, 4, 4}; - -struct _GstSLVideo -{ -    GstVideoSink video_sink; - -    GstCaps *caps; - -    int fps_n, fps_d; -    int par_n, par_d; -    int height, width; -    SLVPixelFormat format; - -    // SHARED WITH APPLICATION: -    // Access to the following should be protected by GST_OBJECT_LOCK() on -    // the GstSLVideo object, and should be totally consistent upon UNLOCK -    // (i.e. all written at once to reflect the current retained frame info -    // when the retained frame is updated.) -    bool retained_frame_ready; // new frame ready since flag last reset. (*TODO: could get the writer to wait on a semaphore instead of having the reader poll, potentially making dropped frames somewhat cheaper.) -    unsigned char*  retained_frame_data; -    int retained_frame_allocbytes; -    int retained_frame_width, retained_frame_height; -    SLVPixelFormat retained_frame_format; -    // sticky resize info -    bool resize_forced_always; -    int resize_try_width; -    int resize_try_height; -}; - -struct _GstSLVideoClass -{ -    GstVideoSinkClass parent_class; -}; - -GType gst_slvideo_get_type (void); - -void gst_slvideo_init_class (void); - -G_END_DECLS - -#endif // LL_GSTREAMER010_ENABLED - -#endif /* __GST_SLVIDEO_H__ */ diff --git a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp b/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp deleted file mode 100644 index 97d1d7d7b5..0000000000 --- a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp +++ /dev/null @@ -1,1266 +0,0 @@ -/** - * @file media_plugin_gstreamer010.cpp - * @brief GStreamer-0.10 plugin for LLMedia API plugin system - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - * @endcond - */ - -#include "linden_common.h" - -#include "llgl.h" - -#include "llplugininstance.h" -#include "llpluginmessage.h" -#include "llpluginmessageclasses.h" -#include "media_plugin_base.h" - -#if LL_GSTREAMER010_ENABLED - -extern "C" { -#include <gst/gst.h> -} - -#include "llmediaimplgstreamer.h" -#include "llmediaimplgstreamertriviallogging.h" - -#include "llmediaimplgstreamervidplug.h" - -#include "llmediaimplgstreamer_syms.h" - -////////////////////////////////////////////////////////////////////////////// -// -class MediaPluginGStreamer010 : public MediaPluginBase -{ -public: -    MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); -    ~MediaPluginGStreamer010(); - -    /* virtual */ void receiveMessage(const char *message_string); - -    static bool startup(); -    static bool closedown(); - -    gboolean processGSTEvents(GstBus     *bus, -                  GstMessage *message); - -private: -    std::string getVersion(); -    bool navigateTo( const std::string urlIn ); -    bool seek( double time_sec ); -    bool setVolume( float volume ); - -    // misc -    bool pause(); -    bool stop(); -    bool play(double rate); -    bool getTimePos(double &sec_out); - -    static const double MIN_LOOP_SEC = 1.0F; - -    bool mIsLooping; - -    enum ECommand { -        COMMAND_NONE, -        COMMAND_STOP, -        COMMAND_PLAY, -        COMMAND_FAST_FORWARD, -        COMMAND_FAST_REWIND, -        COMMAND_PAUSE, -        COMMAND_SEEK, -    }; -    ECommand mCommand; - -private: -    bool unload(); -    bool load(); - -    bool update(int milliseconds); -        void mouseDown( int x, int y ); -        void mouseUp( int x, int y ); -        void mouseMove( int x, int y ); - -        void sizeChanged(); - -    static bool mDoneInit; - -    guint mBusWatchID; - -    float mVolume; - -    int mDepth; - -    // media NATURAL size -    int mNaturalWidth; -    int mNaturalHeight; -    // media current size -    int mCurrentWidth; -    int mCurrentHeight; -    int mCurrentRowbytes; -      // previous media size so we can detect changes -      int mPreviousWidth; -      int mPreviousHeight; -    // desired render size from host -    int mWidth; -    int mHeight; -    // padded texture size we need to write into -    int mTextureWidth; -    int mTextureHeight; - -    int mTextureFormatPrimary; -    int mTextureFormatType; - -    bool mSeekWanted; -    double mSeekDestination; - -    // Very GStreamer-specific -    GMainLoop *mPump; // event pump for this media -    GstElement *mPlaybin; -    GstElement *mVisualizer; -    GstSLVideo *mVideoSink; -}; - -//static -bool MediaPluginGStreamer010::mDoneInit = false; - -MediaPluginGStreamer010::MediaPluginGStreamer010( -    LLPluginInstance::sendMessageFunction host_send_func, -    void *host_user_data ) : -    MediaPluginBase(host_send_func, host_user_data), -    mBusWatchID ( 0 ), -    mCurrentRowbytes ( 4 ), -    mTextureFormatPrimary ( GL_RGBA ), -    mTextureFormatType ( GL_UNSIGNED_INT_8_8_8_8_REV ), -    mSeekWanted(false), -    mSeekDestination(0.0), -    mPump ( NULL ), -    mPlaybin ( NULL ), -    mVisualizer ( NULL ), -    mVideoSink ( NULL ), -    mCommand ( COMMAND_NONE ) -{ -    std::ostringstream str; -    INFOMSG("MediaPluginGStreamer010 constructor - my PID=%u", U32(getpid())); -} - -/////////////////////////////////////////////////////////////////////////////// -// -//#define LL_GST_REPORT_STATE_CHANGES -#ifdef LL_GST_REPORT_STATE_CHANGES -static char* get_gst_state_name(GstState state) -{ -    switch (state) { -    case GST_STATE_VOID_PENDING: return "VOID_PENDING"; -    case GST_STATE_NULL: return "NULL"; -    case GST_STATE_READY: return "READY"; -    case GST_STATE_PAUSED: return "PAUSED"; -    case GST_STATE_PLAYING: return "PLAYING"; -    } -    return "(unknown)"; -} -#endif // LL_GST_REPORT_STATE_CHANGES - -gboolean -MediaPluginGStreamer010::processGSTEvents(GstBus     *bus, -                      GstMessage *message) -{ -    if (!message) -        return TRUE; // shield against GStreamer bug - -    if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_STATE_CHANGED && -        GST_MESSAGE_TYPE(message) != GST_MESSAGE_BUFFERING) -    { -        DEBUGMSG("Got GST message type: %s", -            LLGST_MESSAGE_TYPE_NAME (message)); -    } -    else -    { -        // TODO: grok 'duration' message type -        DEBUGMSG("Got GST message type: %s", -             LLGST_MESSAGE_TYPE_NAME (message)); -    } - -    switch (GST_MESSAGE_TYPE (message)) { -    case GST_MESSAGE_BUFFERING: { -        // NEEDS GST 0.10.11+ -        if (llgst_message_parse_buffering) -        { -            gint percent = 0; -            llgst_message_parse_buffering(message, &percent); -            DEBUGMSG("GST buffering: %d%%", percent); -        } -        break; -    } -    case GST_MESSAGE_STATE_CHANGED: { -        GstState old_state; -        GstState new_state; -        GstState pending_state; -        llgst_message_parse_state_changed(message, -                        &old_state, -                        &new_state, -                        &pending_state); -#ifdef LL_GST_REPORT_STATE_CHANGES -        // not generally very useful, and rather spammy. -        DEBUGMSG("state change (old,<new>,pending): %s,<%s>,%s", -             get_gst_state_name(old_state), -             get_gst_state_name(new_state), -             get_gst_state_name(pending_state)); -#endif // LL_GST_REPORT_STATE_CHANGES - -        switch (new_state) { -        case GST_STATE_VOID_PENDING: -            break; -        case GST_STATE_NULL: -            break; -        case GST_STATE_READY: -            setStatus(STATUS_LOADED); -            break; -        case GST_STATE_PAUSED: -            setStatus(STATUS_PAUSED); -            break; -        case GST_STATE_PLAYING: -            setStatus(STATUS_PLAYING); -            break; -        } -        break; -    } -    case GST_MESSAGE_ERROR: { -        GError *err = NULL; -        gchar *debug = NULL; - -        llgst_message_parse_error (message, &err, &debug); -        WARNMSG("GST error: %s", err?err->message:"(unknown)"); -        if (err) -            g_error_free (err); -        g_free (debug); - -        mCommand = COMMAND_STOP; - -        setStatus(STATUS_ERROR); - -        break; -    } -    case GST_MESSAGE_INFO: { -        if (llgst_message_parse_info) -        { -            GError *err = NULL; -            gchar *debug = NULL; - -            llgst_message_parse_info (message, &err, &debug); -            INFOMSG("GST info: %s", err?err->message:"(unknown)"); -            if (err) -                g_error_free (err); -            g_free (debug); -        } -        break; -    } -    case GST_MESSAGE_WARNING: { -        GError *err = NULL; -        gchar *debug = NULL; - -        llgst_message_parse_warning (message, &err, &debug); -        WARNMSG("GST warning: %s", err?err->message:"(unknown)"); -        if (err) -            g_error_free (err); -        g_free (debug); - -        break; -    } -    case GST_MESSAGE_EOS: -        /* end-of-stream */ -        DEBUGMSG("GST end-of-stream."); -        if (mIsLooping) -        { -            DEBUGMSG("looping media..."); -            double eos_pos_sec = 0.0F; -            bool got_eos_position = getTimePos(eos_pos_sec); - -            if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC) -            { -                // if we know that the movie is really short, don't -                // loop it else it can easily become a time-hog -                // because of GStreamer spin-up overhead -                DEBUGMSG("really short movie (%0.3fsec) - not gonna loop this, pausing instead.", eos_pos_sec); -                // inject a COMMAND_PAUSE -                mCommand = COMMAND_PAUSE; -            } -            else -            { -#undef LLGST_LOOP_BY_SEEKING -// loop with a stop-start instead of a seek, because it actually seems rather -// faster than seeking on remote streams. -#ifdef LLGST_LOOP_BY_SEEKING -                // first, try looping by an explicit rewind -                bool seeksuccess = seek(0.0); -                if (seeksuccess) -                { -                    play(1.0); -                } -                else -#endif // LLGST_LOOP_BY_SEEKING -                {  // use clumsy stop-start to loop -                    DEBUGMSG("didn't loop by rewinding - stopping and starting instead..."); -                    stop(); -                    play(1.0); -                } -            } -        } -        else // not a looping media -        { -            // inject a COMMAND_STOP -            mCommand = COMMAND_STOP; -        } -        break; -    default: -        /* unhandled message */ -        break; -    } - -    /* we want to be notified again the next time there is a message -     * on the bus, so return true (false means we want to stop watching -     * for messages on the bus and our callback should not be called again) -     */ -    return TRUE; -} - -extern "C" { -gboolean -llmediaimplgstreamer_bus_callback (GstBus     *bus, -                   GstMessage *message, -                   gpointer    data) -{ -    MediaPluginGStreamer010 *impl = (MediaPluginGStreamer010*)data; -    return impl->processGSTEvents(bus, message); -} -} // extern "C" - - - -bool -MediaPluginGStreamer010::navigateTo ( const std::string urlIn ) -{ -    if (!mDoneInit) -        return false; // error - -    setStatus(STATUS_LOADING); - -    DEBUGMSG("Setting media URI: %s", urlIn.c_str()); - -    mSeekWanted = false; - -    if (NULL == mPump || -        NULL == mPlaybin) -    { -        setStatus(STATUS_ERROR); -        return false; // error -    } - -    // set URI -    g_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL); -    //g_object_set (G_OBJECT (mPlaybin), "uri", "file:///tmp/movie", NULL); - -    // navigateTo implicitly plays, too. -    play(1.0); - -    return true; -} - - -bool -MediaPluginGStreamer010::update(int milliseconds) -{ -    if (!mDoneInit) -        return false; // error - -    DEBUGMSG("updating media..."); - -    // sanity check -    if (NULL == mPump || -        NULL == mPlaybin) -    { -        DEBUGMSG("dead media..."); -        return false; -    } - -    // see if there's an outstanding seek wanted -    if (mSeekWanted && -        // bleh, GST has to be happy that the movie is really truly playing -        // or it may quietly ignore the seek (with rtsp:// at least). -        (GST_STATE(mPlaybin) == GST_STATE_PLAYING)) -    { -        seek(mSeekDestination); -        mSeekWanted = false; -    } - -    // *TODO: time-limit - but there isn't a lot we can do here, most -    // time is spent in gstreamer's own opaque worker-threads.  maybe -    // we can do something sneaky like only unlock the video object -    // for 'milliseconds' and otherwise hold the lock. -    while (g_main_context_pending(g_main_loop_get_context(mPump))) -    { -           g_main_context_iteration(g_main_loop_get_context(mPump), FALSE); -    } - -    // check for availability of a new frame - -    if (mVideoSink) -    { -            GST_OBJECT_LOCK(mVideoSink); -        if (mVideoSink->retained_frame_ready) -        { -            DEBUGMSG("NEW FRAME READY"); - -            if (mVideoSink->retained_frame_width != mCurrentWidth || -                mVideoSink->retained_frame_height != mCurrentHeight) -                // *TODO: also check for change in format -            { -                // just resize container, don't consume frame -                int neww = mVideoSink->retained_frame_width; -                int newh = mVideoSink->retained_frame_height; - -                int newd = 4; -                mTextureFormatPrimary = GL_RGBA; -                mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; - -                /* -                int newd = SLVPixelFormatBytes[mVideoSink->retained_frame_format]; -                if (SLV_PF_BGRX == mVideoSink->retained_frame_format) -                { -                    mTextureFormatPrimary = GL_BGRA; -                    mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; -                } -                else -                { -                    mTextureFormatPrimary = GL_RGBA; -                    mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; -                } -                */ - -                GST_OBJECT_UNLOCK(mVideoSink); - -                mCurrentRowbytes = neww * newd; -                DEBUGMSG("video container resized to %dx%d", -                     neww, newh); - -                mDepth = newd; -                mCurrentWidth = neww; -                mCurrentHeight = newh; -                sizeChanged(); -                return true; -            } - -            if (mPixels && -                mCurrentHeight <= mHeight && -                mCurrentWidth <= mWidth && -                !mTextureSegmentName.empty()) -            { -                // we're gonna totally consume this frame - reset 'ready' flag -                mVideoSink->retained_frame_ready = FALSE; -                int destination_rowbytes = mWidth * mDepth; -                for (int row=0; row<mCurrentHeight; ++row) -                { -                    memcpy(&mPixels -                            [destination_rowbytes * row], -                           &mVideoSink->retained_frame_data -                            [mCurrentRowbytes * row], -                           mCurrentRowbytes); -                } - -                GST_OBJECT_UNLOCK(mVideoSink); -                DEBUGMSG("NEW FRAME REALLY TRULY CONSUMED, TELLING HOST"); - -                setDirty(0,0,mCurrentWidth,mCurrentHeight); -            } -            else -            { -                // new frame ready, but we're not ready to -                // consume it. - -                GST_OBJECT_UNLOCK(mVideoSink); - -                DEBUGMSG("NEW FRAME not consumed, still waiting for a shm segment and/or shm resize"); -            } - -            return true; -        } -        else -        { -            // nothing to do yet. -            GST_OBJECT_UNLOCK(mVideoSink); -            return true; -        } -    } - -    return true; -} - - -void -MediaPluginGStreamer010::mouseDown( int x, int y ) -{ -  // do nothing -} - -void -MediaPluginGStreamer010::mouseUp( int x, int y ) -{ -  // do nothing -} - -void -MediaPluginGStreamer010::mouseMove( int x, int y ) -{ -  // do nothing -} - - -bool -MediaPluginGStreamer010::pause() -{ -    DEBUGMSG("pausing media..."); -    // todo: error-check this? -    if (mDoneInit && mPlaybin) -    { -        llgst_element_set_state(mPlaybin, GST_STATE_PAUSED); -        return true; -    } -    return false; -} - -bool -MediaPluginGStreamer010::stop() -{ -    DEBUGMSG("stopping media..."); -    // todo: error-check this? -    if (mDoneInit && mPlaybin) -    { -        llgst_element_set_state(mPlaybin, GST_STATE_READY); -        return true; -    } -    return false; -} - -bool -MediaPluginGStreamer010::play(double rate) -{ -    // NOTE: we don't actually support non-natural rate. - -        DEBUGMSG("playing media... rate=%f", rate); -    // todo: error-check this? -    if (mDoneInit && mPlaybin) -    { -        llgst_element_set_state(mPlaybin, GST_STATE_PLAYING); -        return true; -    } -    return false; -} - -bool -MediaPluginGStreamer010::setVolume( float volume ) -{ -    // we try to only update volume as conservatively as -    // possible, as many gst-plugins-base versions up to at least -    // November 2008 have critical race-conditions in setting volume - sigh -    if (mVolume == volume) -        return true; // nothing to do, everything's fine - -    mVolume = volume; -    if (mDoneInit && mPlaybin) -    { -        g_object_set(mPlaybin, "volume", mVolume, NULL); -        return true; -    } - -    return false; -} - -bool -MediaPluginGStreamer010::seek(double time_sec) -{ -    bool success = false; -    if (mDoneInit && mPlaybin) -    { -        success = llgst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME, -                GstSeekFlags(GST_SEEK_FLAG_FLUSH | -                         GST_SEEK_FLAG_KEY_UNIT), -                GST_SEEK_TYPE_SET, gint64(time_sec*GST_SECOND), -                GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); -    } -    DEBUGMSG("MEDIA SEEK REQUEST to %fsec result was %d", -         float(time_sec), int(success)); -    return success; -} - -bool -MediaPluginGStreamer010::getTimePos(double &sec_out) -{ -    bool got_position = false; -    if (mDoneInit && mPlaybin) -    { -        gint64 pos; -        GstFormat timefmt = GST_FORMAT_TIME; -        got_position = -            llgst_element_query_position && -            llgst_element_query_position(mPlaybin, -                             &timefmt, -                             &pos); -        got_position = got_position -            && (timefmt == GST_FORMAT_TIME); -        // GStreamer may have other ideas, but we consider the current position -        // undefined if not PLAYING or PAUSED -        got_position = got_position && -            (GST_STATE(mPlaybin) == GST_STATE_PLAYING || -             GST_STATE(mPlaybin) == GST_STATE_PAUSED); -        if (got_position && !GST_CLOCK_TIME_IS_VALID(pos)) -        { -            if (GST_STATE(mPlaybin) == GST_STATE_PLAYING) -            { -                // if we're playing then we treat an invalid clock time -                // as 0, for complicated reasons (insert reason here) -                pos = 0; -            } -            else -            { -                got_position = false; -            } - -        } -        // If all the preconditions succeeded... we can trust the result. -        if (got_position) -        { -            sec_out = double(pos) / double(GST_SECOND); // gst to sec -        } -    } -    return got_position; -} - -bool -MediaPluginGStreamer010::load() -{ -    if (!mDoneInit) -        return false; // error - -    setStatus(STATUS_LOADING); - -    DEBUGMSG("setting up media..."); - -    mIsLooping = false; -    mVolume = 0.1234567; // minor hack to force an initial volume update - -    // Create a pumpable main-loop for this media -    mPump = g_main_loop_new (NULL, FALSE); -    if (!mPump) -    { -        setStatus(STATUS_ERROR); -        return false; // error -    } - -    // instantiate a playbin element to do the hard work -    mPlaybin = llgst_element_factory_make ("playbin", "play"); -    if (!mPlaybin) -    { -        setStatus(STATUS_ERROR); -        return false; // error -    } - -    // get playbin's bus -    GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); -    if (!bus) -    { -        setStatus(STATUS_ERROR); -        return false; // error -    } -    mBusWatchID = llgst_bus_add_watch (bus, -                       llmediaimplgstreamer_bus_callback, -                       this); -    llgst_object_unref (bus); - -#if 0 // not quite stable/correct yet -    // get a visualizer element (bonus feature!) -    char* vis_name = getenv("LL_GST_VIS_NAME"); -    if (!vis_name || -        (vis_name && std::string(vis_name)!="none")) -    { -        if (vis_name) -        { -            mVisualizer = llgst_element_factory_make (vis_name, "vis"); -        } -        if (!mVisualizer) -        { -            mVisualizer = llgst_element_factory_make ("libvisual_jess", "vis"); -            if (!mVisualizer) -            { -                mVisualizer = llgst_element_factory_make ("goom", "vis"); -                if (!mVisualizer) -                { -                    mVisualizer = llgst_element_factory_make ("libvisual_lv_scope", "vis"); -                    if (!mVisualizer) -                    { -                        // That's okay, we don't NEED this. -                    } -                } -            } -        } -    } -#endif - -    if (NULL == getenv("LL_GSTREAMER_EXTERNAL")) { -        // instantiate a custom video sink -        mVideoSink = -            GST_SLVIDEO(llgst_element_factory_make ("private-slvideo", "slvideo")); -        if (!mVideoSink) -        { -            WARNMSG("Could not instantiate private-slvideo element."); -            // todo: cleanup. -            setStatus(STATUS_ERROR); -            return false; // error -        } - -        // connect the pieces -        g_object_set(mPlaybin, "video-sink", mVideoSink, NULL); -    } - -    if (mVisualizer) -    { -        g_object_set(mPlaybin, "vis-plugin", mVisualizer, NULL); -    } - -    return true; -} - -bool -MediaPluginGStreamer010::unload () -{ -    if (!mDoneInit) -        return false; // error - -    DEBUGMSG("unloading media..."); - -    // stop getting callbacks for this bus -    g_source_remove(mBusWatchID); -    mBusWatchID = 0; - -    if (mPlaybin) -    { -        llgst_element_set_state (mPlaybin, GST_STATE_NULL); -        llgst_object_unref (GST_OBJECT (mPlaybin)); -        mPlaybin = NULL; -    } - -    if (mVisualizer) -    { -        llgst_object_unref (GST_OBJECT (mVisualizer)); -        mVisualizer = NULL; -    } - -    if (mPump) -    { -        g_main_loop_quit(mPump); -        mPump = NULL; -    } - -    mVideoSink = NULL; - -    setStatus(STATUS_NONE); - -    return true; -} - - -//static -bool -MediaPluginGStreamer010::startup() -{ -    // first - check if GStreamer is explicitly disabled -    if (NULL != getenv("LL_DISABLE_GSTREAMER")) -        return false; - -    // only do global GStreamer initialization once. -    if (!mDoneInit) -    { -        g_thread_init(NULL); - -        // Init the glib type system - we need it. -        g_type_init(); - -        // Get symbols! -#if LL_DARWIN -        if (! grab_gst_syms("libgstreamer-0.10.dylib", -                    "libgstvideo-0.10.dylib") ) -#elseif LL_WINDOWS -        if (! grab_gst_syms("libgstreamer-0.10.dll", -                    "libgstvideo-0.10.dll") ) -#else // linux or other ELFy unixoid -        if (! grab_gst_syms("libgstreamer-0.10.so.0", -                    "libgstvideo-0.10.so.0") ) -#endif -        { -            WARNMSG("Couldn't find suitable GStreamer 0.10 support on this system - video playback disabled."); -            return false; -        } - -        if (llgst_segtrap_set_enabled) -        { -            llgst_segtrap_set_enabled(FALSE); -        } -        else -        { -            WARNMSG("gst_segtrap_set_enabled() is not available; plugin crashes won't be caught."); -        } - -#if LL_LINUX -        // Gstreamer tries a fork during init, waitpid-ing on it, -        // which conflicts with any installed SIGCHLD handler... -        struct sigaction tmpact, oldact; -        if (llgst_registry_fork_set_enabled) { -            // if we can disable SIGCHLD-using forking behaviour, -            // do it. -            llgst_registry_fork_set_enabled(false); -        } -        else { -            // else temporarily install default SIGCHLD handler -            // while GStreamer initialises -            tmpact.sa_handler = SIG_DFL; -            sigemptyset( &tmpact.sa_mask ); -            tmpact.sa_flags = SA_SIGINFO; -            sigaction(SIGCHLD, &tmpact, &oldact); -        } -#endif // LL_LINUX - -        // Protect against GStreamer resetting the locale, yuck. -        static std::string saved_locale; -        saved_locale = setlocale(LC_ALL, NULL); - -        // finally, try to initialize GStreamer! -        GError *err = NULL; -        gboolean init_gst_success = llgst_init_check(NULL, NULL, &err); - -        // restore old locale -        setlocale(LC_ALL, saved_locale.c_str() ); - -#if LL_LINUX -        // restore old SIGCHLD handler -        if (!llgst_registry_fork_set_enabled) -            sigaction(SIGCHLD, &oldact, NULL); -#endif // LL_LINUX - -        if (!init_gst_success) // fail -        { -            if (err) -            { -                WARNMSG("GST init failed: %s", err->message); -                g_error_free(err); -            } -            else -            { -                WARNMSG("GST init failed for unspecified reason."); -            } -            return false; -        } - -        // Init our custom plugins - only really need do this once. -        gst_slvideo_init_class(); - -        mDoneInit = true; -    } - -    return true; -} - - -void -MediaPluginGStreamer010::sizeChanged() -{ -    // the shared writing space has possibly changed size/location/whatever - -    // Check to see whether the movie's NATURAL size has been set yet -    if (1 == mNaturalWidth && -        1 == mNaturalHeight) -    { -        mNaturalWidth = mCurrentWidth; -        mNaturalHeight = mCurrentHeight; -        DEBUGMSG("Media NATURAL size better detected as %dx%d", -             mNaturalWidth, mNaturalHeight); -    } - -    // if the size has changed then the shm has changed and the app needs telling -    if (mCurrentWidth != mPreviousWidth || -        mCurrentHeight != mPreviousHeight) -    { -        mPreviousWidth = mCurrentWidth; -        mPreviousHeight = mCurrentHeight; - -        LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request"); -        message.setValue("name", mTextureSegmentName); -        message.setValueS32("width", mNaturalWidth); -        message.setValueS32("height", mNaturalHeight); -        DEBUGMSG("<--- Sending size change request to application with name: '%s' - natural size is %d x %d", mTextureSegmentName.c_str(), mNaturalWidth, mNaturalHeight); -        sendMessage(message); -    } -} - - - -//static -bool -MediaPluginGStreamer010::closedown() -{ -    if (!mDoneInit) -        return false; // error - -    ungrab_gst_syms(); - -    mDoneInit = false; - -    return true; -} - -MediaPluginGStreamer010::~MediaPluginGStreamer010() -{ -    DEBUGMSG("MediaPluginGStreamer010 destructor"); - -    closedown(); - -    DEBUGMSG("GStreamer010 closing down"); -} - - -std::string -MediaPluginGStreamer010::getVersion() -{ -    std::string plugin_version = "GStreamer010 media plugin, GStreamer version "; -    if (mDoneInit && -        llgst_version) -    { -        guint major, minor, micro, nano; -        llgst_version(&major, &minor, µ, &nano); -        plugin_version += llformat("%u.%u.%u.%u (runtime), %u.%u.%u.%u (headers)", (unsigned int)major, (unsigned int)minor, (unsigned int)micro, (unsigned int)nano, (unsigned int)GST_VERSION_MAJOR, (unsigned int)GST_VERSION_MINOR, (unsigned int)GST_VERSION_MICRO, (unsigned int)GST_VERSION_NANO); -    } -    else -    { -        plugin_version += "(unknown)"; -    } -    return plugin_version; -} - -void MediaPluginGStreamer010::receiveMessage(const char *message_string) -{ -    //std::cerr << "MediaPluginGStreamer010::receiveMessage: received message: \"" << message_string << "\"" << std::endl; - -    LLPluginMessage message_in; - -    if(message_in.parse(message_string) >= 0) -    { -        std::string message_class = message_in.getClass(); -        std::string message_name = message_in.getName(); -        if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) -        { -            if(message_name == "init") -            { -                LLPluginMessage message("base", "init_response"); -                LLSD versions = LLSD::emptyMap(); -                versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; -                versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; -                versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; -                message.setValueLLSD("versions", versions); - -                if ( load() ) -                { -                    DEBUGMSG("GStreamer010 media instance set up"); -                } -                else -                { -                    WARNMSG("GStreamer010 media instance failed to set up"); -                } - -                message.setValue("plugin_version", getVersion()); -                sendMessage(message); -            } -            else if(message_name == "idle") -            { -                // no response is necessary here. -                double time = message_in.getValueReal("time"); - -                // Convert time to milliseconds for update() -                update((int)(time * 1000.0f)); -            } -            else if(message_name == "cleanup") -            { -                unload(); -                closedown(); -            } -            else if(message_name == "shm_added") -            { -                SharedSegmentInfo info; -                info.mAddress = message_in.getValuePointer("address"); -                info.mSize = (size_t)message_in.getValueS32("size"); -                std::string name = message_in.getValue("name"); - -                std::ostringstream str; -                INFOMSG("MediaPluginGStreamer010::receiveMessage: shared memory added, name: %s, size: %d, address: %p", name.c_str(), int(info.mSize), info.mAddress); - -                mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); -            } -            else if(message_name == "shm_remove") -            { -                std::string name = message_in.getValue("name"); - -                DEBUGMSG("MediaPluginGStreamer010::receiveMessage: shared memory remove, name = %s", name.c_str()); - -                SharedSegmentMap::iterator iter = mSharedSegments.find(name); -                if(iter != mSharedSegments.end()) -                { -                    if(mPixels == iter->second.mAddress) -                    { -                        // This is the currently active pixel buffer.  Make sure we stop drawing to it. -                        mPixels = NULL; -                        mTextureSegmentName.clear(); - -                        // Make sure the movie decoder is no longer pointed at the shared segment. -                        sizeChanged(); -                    } -                    mSharedSegments.erase(iter); -                } -                else -                { -                    WARNMSG("MediaPluginGStreamer010::receiveMessage: unknown shared memory region!"); -                } - -                // Send the response so it can be cleaned up. -                LLPluginMessage message("base", "shm_remove_response"); -                message.setValue("name", name); -                sendMessage(message); -            } -            else -            { -                std::ostringstream str; -                INFOMSG("MediaPluginGStreamer010::receiveMessage: unknown base message: %s", message_name.c_str()); -            } -        } -        else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) -        { -            if(message_name == "init") -            { -                // Plugin gets to decide the texture parameters to use. -                LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); -                // lame to have to decide this now, it depends on the movie.  Oh well. -                mDepth = 4; - -                mCurrentWidth = 1; -                mCurrentHeight = 1; -                mPreviousWidth = 1; -                mPreviousHeight = 1; -                mNaturalWidth = 1; -                mNaturalHeight = 1; -                mWidth = 1; -                mHeight = 1; -                mTextureWidth = 1; -                mTextureHeight = 1; - -                message.setValueU32("format", GL_RGBA); -                message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV); - -                message.setValueS32("depth", mDepth); -                message.setValueS32("default_width", mWidth); -                message.setValueS32("default_height", mHeight); -                message.setValueU32("internalformat", GL_RGBA8); -                message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left. -                message.setValueBoolean("allow_downsample", true); // we respond with grace and performance if asked to downscale -                sendMessage(message); -            } -            else if(message_name == "size_change") -            { -                std::string name = message_in.getValue("name"); -                S32 width = message_in.getValueS32("width"); -                S32 height = message_in.getValueS32("height"); -                S32 texture_width = message_in.getValueS32("texture_width"); -                S32 texture_height = message_in.getValueS32("texture_height"); - -                std::ostringstream str; -                INFOMSG("---->Got size change instruction from application with shm name: %s - size is %d x %d", name.c_str(), width, height); - -                LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); -                message.setValue("name", name); -                message.setValueS32("width", width); -                message.setValueS32("height", height); -                message.setValueS32("texture_width", texture_width); -                message.setValueS32("texture_height", texture_height); -                sendMessage(message); - -                if(!name.empty()) -                { -                    // Find the shared memory region with this name -                    SharedSegmentMap::iterator iter = mSharedSegments.find(name); -                    if(iter != mSharedSegments.end()) -                    { -                        INFOMSG("*** Got size change with matching shm, new size is %d x %d", width, height); -                        INFOMSG("*** Got size change with matching shm, texture size size is %d x %d", texture_width, texture_height); - -                        mPixels = (unsigned char*)iter->second.mAddress; -                        mTextureSegmentName = name; -                        mWidth = width; -                        mHeight = height; - -                        if (texture_width > 1 || -                            texture_height > 1) // not a dummy size from the app, a real explicit forced size -                        { -                            INFOMSG("**** = REAL RESIZE REQUEST FROM APP"); - -                            GST_OBJECT_LOCK(mVideoSink); -                            mVideoSink->resize_forced_always = true; -                            mVideoSink->resize_try_width = texture_width; -                            mVideoSink->resize_try_height = texture_height; -                            GST_OBJECT_UNLOCK(mVideoSink); -                        } - -                        mTextureWidth = texture_width; -                        mTextureHeight = texture_height; -                    } -                } -            } -            else if(message_name == "load_uri") -            { -                std::string uri = message_in.getValue("uri"); -                navigateTo( uri ); -                sendStatus(); -            } -            else if(message_name == "mouse_event") -            { -                std::string event = message_in.getValue("event"); -                S32 x = message_in.getValueS32("x"); -                S32 y = message_in.getValueS32("y"); - -                if(event == "down") -                { -                    mouseDown(x, y); -                } -                else if(event == "up") -                { -                    mouseUp(x, y); -                } -                else if(event == "move") -                { -                    mouseMove(x, y); -                }; -            }; -        } -        else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) -        { -            if(message_name == "stop") -            { -                stop(); -            } -            else if(message_name == "start") -            { -                double rate = 0.0; -                if(message_in.hasValue("rate")) -                { -                    rate = message_in.getValueReal("rate"); -                } -                // NOTE: we don't actually support rate. -                play(rate); -            } -            else if(message_name == "pause") -            { -                pause(); -            } -            else if(message_name == "seek") -            { -                double time = message_in.getValueReal("time"); -                // defer the actual seek in case we haven't -                // really truly started yet in which case there -                // is nothing to seek upon -                mSeekWanted = true; -                mSeekDestination = time; -            } -            else if(message_name == "set_loop") -            { -                bool loop = message_in.getValueBoolean("loop"); -                mIsLooping = loop; -            } -            else if(message_name == "set_volume") -            { -                double volume = message_in.getValueReal("volume"); -                setVolume(volume); -            } -        } -        else -        { -            INFOMSG("MediaPluginGStreamer010::receiveMessage: unknown message class: %s", message_class.c_str()); -        } -    } -} - -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) -{ -    if (MediaPluginGStreamer010::startup()) -    { -        MediaPluginGStreamer010 *self = new MediaPluginGStreamer010(host_send_func, host_user_data); -        *plugin_send_func = MediaPluginGStreamer010::staticReceiveMessage; -        *plugin_user_data = (void*)self; - -        return 0; // okay -    } -    else -    { -        return -1; // failed to init -    } -} - -#else // LL_GSTREAMER010_ENABLED - -// Stubbed-out class with constructor/destructor (necessary or windows linker -// will just think its dead code and optimize it all out) -class MediaPluginGStreamer010 : public MediaPluginBase -{ -public: -    MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); -    ~MediaPluginGStreamer010(); -    /* virtual */ void receiveMessage(const char *message_string); -}; - -MediaPluginGStreamer010::MediaPluginGStreamer010( -    LLPluginInstance::sendMessageFunction host_send_func, -    void *host_user_data ) : -    MediaPluginBase(host_send_func, host_user_data) -{ -    // no-op -} - -MediaPluginGStreamer010::~MediaPluginGStreamer010() -{ -    // no-op -} - -void MediaPluginGStreamer010::receiveMessage(const char *message_string) -{ -    // no-op -} - -// We're building without GStreamer enabled.  Just refuse to initialize. -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) -{ -    return -1; -} - -#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer10/CMakeLists.txt b/indra/media_plugins/gstreamer10/CMakeLists.txt new file mode 100644 index 0000000000..14ce5bfaa1 --- /dev/null +++ b/indra/media_plugins/gstreamer10/CMakeLists.txt @@ -0,0 +1,41 @@ +# -*- cmake -*- + +project(media_plugin_gstreamer10) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLMath) +include(LLWindow) +include(Linking) +include(PluginAPI) +include(OpenGL) +include(GLIB) + +include(GStreamer10Plugin) + +### media_plugin_gstreamer10 + +set(media_plugin_gstreamer10_SOURCE_FILES +    media_plugin_gstreamer10.cpp +    ) + +set(media_plugin_gstreamer10_HEADER_FILES +    llmediaimplgstreamer_syms.h +    llmediaimplgstreamertriviallogging.h +    ) + +add_library(media_plugin_gstreamer10 +    SHARED +    ${media_plugin_gstreamer10_SOURCE_FILES} +) + +target_link_libraries(media_plugin_gstreamer10 media_plugin_base ll::gstreamer10 ) + +if (WINDOWS) +  set_target_properties( +    media_plugin_gstreamer10 +    PROPERTIES +    LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMT" +    ) +endif (WINDOWS) diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h b/indra/media_plugins/gstreamer10/llmediaimplgstreamer.h index cae11a5cb3..cae11a5cb3 100644 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h +++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer.h diff --git a/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc new file mode 100644 index 0000000000..6f5bb04bdf --- /dev/null +++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc @@ -0,0 +1,71 @@ +#define G gstSymbolGrabber + +LL_GRAB_SYM(G, true, gst_buffer_new, GstBuffer*, void) +LL_GRAB_SYM(G, true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*) +LL_GRAB_SYM(G, true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err) +LL_GRAB_SYM(G, true, gst_message_get_type, GType, void) +LL_GRAB_SYM(G, true, gst_message_type_get_name, const gchar*, GstMessageType type) +LL_GRAB_SYM(G, true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GRAB_SYM(G, true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GRAB_SYM(G, true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending) +LL_GRAB_SYM(G, true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state) +LL_GRAB_SYM(G, true, gst_object_unref, void, gpointer object) +LL_GRAB_SYM(G, true, gst_object_get_type, GType, void) +LL_GRAB_SYM(G, true, gst_pipeline_get_type, GType, void) +LL_GRAB_SYM(G, true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline) +LL_GRAB_SYM(G, true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data) +LL_GRAB_SYM(G, true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name) +LL_GRAB_SYM(G, true, gst_element_get_type, GType, void) +LL_GRAB_SYM(G, true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template) +LL_GRAB_SYM(G, true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp) +LL_GRAB_SYM(G, true, gst_caps_from_string, GstCaps *, const gchar *string) +LL_GRAB_SYM(G, true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index) +LL_GRAB_SYM(G, true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type) +LL_GRAB_SYM(G, true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value) +LL_GRAB_SYM(G, true, gst_structure_get_value, const GValue *, const GstStructure *structure, const gchar *fieldname) +LL_GRAB_SYM(G, true, gst_value_get_fraction_numerator, gint, const GValue *value) +LL_GRAB_SYM(G, true, gst_value_get_fraction_denominator, gint, const GValue *value) +LL_GRAB_SYM(G, true, gst_structure_get_name, const gchar *, const GstStructure *structure) +LL_GRAB_SYM(G, true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64) + +LL_GRAB_SYM(G, false, gst_registry_fork_set_enabled, void, gboolean enabled) +LL_GRAB_SYM(G, false, gst_segtrap_set_enabled, void, gboolean enabled) +LL_GRAB_SYM(G, false, gst_message_parse_buffering, void, GstMessage *message, gint *percent) +LL_GRAB_SYM(G, false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GRAB_SYM(G, false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur) +LL_GRAB_SYM(G, false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano) + +LL_GRAB_SYM(G, true, gst_message_parse_tag, void, GstMessage *, GstTagList **) +LL_GRAB_SYM(G, true, gst_tag_list_foreach, void, const GstTagList *, GstTagForeachFunc, gpointer) +LL_GRAB_SYM(G, true, gst_tag_list_get_tag_size, guint, const GstTagList *, const gchar *) +LL_GRAB_SYM(G, true, gst_tag_list_get_value_index, const GValue *, const GstTagList *, const gchar *, guint) + +LL_GRAB_SYM(G, true, gst_caps_new_simple, GstCaps*, const char *, const char*, ... ) + +LL_GRAB_SYM(G, true, gst_sample_get_caps, GstCaps*, GstSample* ) +LL_GRAB_SYM(G, true, gst_sample_get_buffer, GstBuffer*, GstSample* ) +LL_GRAB_SYM(G, true, gst_buffer_map, gboolean, GstBuffer*, GstMapInfo*, GstMapFlags ) +LL_GRAB_SYM(G, true, gst_buffer_unmap, void, GstBuffer*, GstMapInfo* ) + +LL_GRAB_SYM(G, true, gst_app_sink_set_caps, void, GstAppSink*, GstCaps const* ) +LL_GRAB_SYM(G, true, gst_app_sink_pull_sample, GstSample*, GstAppSink* ) + +LL_GRAB_SYM(G, true, g_free, void, gpointer ) +LL_GRAB_SYM(G, true, g_error_free, void, GError* ) + +LL_GRAB_SYM(G, true, g_main_context_pending, gboolean, GMainContext* ) +LL_GRAB_SYM(G, true, g_main_loop_get_context, GMainContext*, GMainLoop* ) +LL_GRAB_SYM(G, true, g_main_context_iteration, gboolean, GMainContext*, gboolean ) +LL_GRAB_SYM(G, true, g_main_loop_new, GMainLoop*, GMainContext*, gboolean ) +LL_GRAB_SYM(G, true, g_main_loop_quit, void, GMainLoop* ) +LL_GRAB_SYM(G, true, gst_mini_object_unref, void, GstMiniObject* ) +LL_GRAB_SYM(G, true, g_object_set, void, gpointer, gchar const*, ... ) +LL_GRAB_SYM(G, true, g_source_remove, gboolean, guint ) +LL_GRAB_SYM(G, true, g_value_get_string, gchar const*, GValue const* ) + +LL_GRAB_SYM(G, true, gst_debug_set_active, void, gboolean ) +LL_GRAB_SYM(G, true, gst_debug_add_log_function, void, GstLogFunction, gpointer, GDestroyNotify ) +LL_GRAB_SYM(G, true, gst_debug_set_default_threshold, void, GstDebugLevel ) +LL_GRAB_SYM(G, true, gst_debug_message_get , gchar const*, GstDebugMessage * ) + +#undef G diff --git a/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp b/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp new file mode 100644 index 0000000000..3f636915ea --- /dev/null +++ b/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp @@ -0,0 +1,958 @@ +/**  + * @file media_plugin_gstreamer10.cpp + * @brief GStreamer-1.0 plugin for LLMedia API plugin system + * + * @cond + * $LicenseInfo:firstyear=2016&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2016, Linden Research, Inc. / Nicky Dasmijn + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + * @endcond + */ + +#define FLIP_Y + +#include "linden_common.h" + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#define G_DISABLE_CAST_CHECKS +extern "C" { +#include <gst/gst.h> +#include <gst/app/gstappsink.h> +} + +SymbolGrabber gstSymbolGrabber; + +#include "llmediaimplgstreamer_syms_raw.inc" + +static inline void llgst_caps_unref( GstCaps * caps ) +{ +    llgst_mini_object_unref( GST_MINI_OBJECT_CAST( caps ) ); +} + +static inline void llgst_sample_unref( GstSample *aSample ) +{ +    llgst_mini_object_unref( GST_MINI_OBJECT_CAST( aSample ) ); +} + +////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginGStreamer10 : public MediaPluginBase +{ +public: +    MediaPluginGStreamer10(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); +    ~MediaPluginGStreamer10(); + +    /* virtual */ void receiveMessage(const char *message_string); + +    static bool startup(); +    static bool closedown(); + +    gboolean processGSTEvents(GstBus *bus, GstMessage *message); + +private: +    std::string getVersion(); +    bool navigateTo( const std::string urlIn ); +    bool seek( double time_sec ); +    bool setVolume( float volume ); +     +    // misc +    bool pause(); +    bool stop(); +    bool play(double rate); +    bool getTimePos(double &sec_out); + +    double MIN_LOOP_SEC = 1.0F; +    U32 INTERNAL_TEXTURE_SIZE = 1024; +     +    bool mIsLooping; + +    enum ECommand { +        COMMAND_NONE, +        COMMAND_STOP, +        COMMAND_PLAY, +        COMMAND_FAST_FORWARD, +        COMMAND_FAST_REWIND, +        COMMAND_PAUSE, +        COMMAND_SEEK, +    }; +    ECommand mCommand; + +private: +    bool unload(); +    bool load(); + +    bool update(int milliseconds); +    void mouseDown( int x, int y ); +    void mouseUp( int x, int y ); +    void mouseMove( int x, int y ); + +    static bool mDoneInit; +     +    guint mBusWatchID; +     +    float mVolume; + +    int mDepth; + +    // padded texture size we need to write into +    int mTextureWidth; +    int mTextureHeight; +     +    bool mSeekWanted; +    double mSeekDestination; +     +    // Very GStreamer-specific +    GMainLoop *mPump; // event pump for this media +    GstElement *mPlaybin; +    GstAppSink *mAppSink; +}; + +//static +bool MediaPluginGStreamer10::mDoneInit = false; + +MediaPluginGStreamer10::MediaPluginGStreamer10( LLPluginInstance::sendMessageFunction host_send_func, +                                                void *host_user_data ) +    : MediaPluginBase(host_send_func, host_user_data) +    , mBusWatchID ( 0 ) +    , mSeekWanted(false) +    , mSeekDestination(0.0) +    , mPump ( nullptr ) +    , mPlaybin ( nullptr ) +    , mAppSink ( nullptr ) +    , mCommand ( COMMAND_NONE ) +{ +} + +gboolean MediaPluginGStreamer10::processGSTEvents(GstBus *bus, GstMessage *message) +{ +    if (!message)  +        return TRUE; // shield against GStreamer bug + +    switch (GST_MESSAGE_TYPE (message)) +    { +        case GST_MESSAGE_BUFFERING: +        { +            // NEEDS GST 0.10.11+ +            if (llgst_message_parse_buffering) +            { +                gint percent = 0; +                llgst_message_parse_buffering(message, &percent); +            } +            break; +        } +        case GST_MESSAGE_STATE_CHANGED: +        { +            GstState old_state; +            GstState new_state; +            GstState pending_state; +            llgst_message_parse_state_changed(message, +                                              &old_state, +                                              &new_state, +                                              &pending_state); + +            switch (new_state) +            { +                case GST_STATE_VOID_PENDING: +                    break; +                case GST_STATE_NULL: +                    break; +                case GST_STATE_READY: +                    setStatus(STATUS_LOADED); +                    break; +                case GST_STATE_PAUSED: +                    setStatus(STATUS_PAUSED); +                    break; +                case GST_STATE_PLAYING: +                    setStatus(STATUS_PLAYING); +                    break; +            } +            break; +        } +        case GST_MESSAGE_ERROR: +        { +            GError *err = nullptr; +            gchar *debug = nullptr; + +            llgst_message_parse_error (message, &err, &debug); +            if (err) +                llg_error_free (err); +            llg_free (debug); + +            mCommand = COMMAND_STOP; + +            setStatus(STATUS_ERROR); + +            break; +        } +        case GST_MESSAGE_INFO: +        { +            if (llgst_message_parse_info) +            { +                GError *err = nullptr; +                gchar *debug = nullptr; +             +                llgst_message_parse_info (message, &err, &debug); +                if (err) +                    llg_error_free (err); +                llg_free (debug); +            } +            break; +        } +        case GST_MESSAGE_WARNING: +        { +            GError *err = nullptr; +            gchar *debug = nullptr; +             +            llgst_message_parse_warning (message, &err, &debug); +            if (err) +                llg_error_free (err); +            llg_free (debug); + +            break; +        } +        case GST_MESSAGE_EOS: +            /* end-of-stream */ +            if (mIsLooping) +            { +                double eos_pos_sec = 0.0F; +                bool got_eos_position = getTimePos(eos_pos_sec); +                 +                if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC) +                { +                    // if we know that the movie is really short, don't +                    // loop it else it can easily become a time-hog +                    // because of GStreamer spin-up overhead +                    // inject a COMMAND_PAUSE +                    mCommand = COMMAND_PAUSE; +                } +                else +                { +                    stop(); +                    play(1.0); +                } +            } +            else // not a looping media +            { +                // inject a COMMAND_STOP +                mCommand = COMMAND_STOP; +            } +            break; +        default: +            /* unhandled message */ +            break; +    } + +    /* we want to be notified again the next time there is a message +     * on the bus, so return true (false means we want to stop watching +     * for messages on the bus and our callback should not be called again) +     */ +    return TRUE; +} + +extern "C" { +    gboolean llmediaimplgstreamer_bus_callback (GstBus     *bus, +                                                GstMessage *message, +                                                gpointer    data) +    { +        MediaPluginGStreamer10 *impl = (MediaPluginGStreamer10*)data; +        return impl->processGSTEvents(bus, message); +    } +} // extern "C" + + + +bool MediaPluginGStreamer10::navigateTo ( const std::string urlIn ) +{ +    if (!mDoneInit) +        return false; // error + +    setStatus(STATUS_LOADING); + +    mSeekWanted = false; + +    if (nullptr == mPump ||  nullptr == mPlaybin) +    { +        setStatus(STATUS_ERROR); +        return false; // error +    } + +    llg_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), nullptr); + +    // navigateTo implicitly plays, too. +    play(1.0); + +    return true; +} + + +class GstSampleUnref +{ +    GstSample *mT; +public: +    GstSampleUnref( GstSample *aT ) +        : mT( aT ) +    { llassert_always( mT ); } + +    ~GstSampleUnref( ) +    { llgst_sample_unref( mT ); } +}; + +bool MediaPluginGStreamer10::update(int milliseconds) +{ +    if (!mDoneInit) +        return false; // error + +    //  DEBUGMSG("updating media..."); +     +    // sanity check +    if (nullptr == mPump || nullptr == mPlaybin) +    { +        return false; +    } + +    // see if there's an outstanding seek wanted +    if (mSeekWanted && +        // bleh, GST has to be happy that the movie is really truly playing +        // or it may quietly ignore the seek (with rtsp:// at least). +        (GST_STATE(mPlaybin) == GST_STATE_PLAYING)) +    { +        seek(mSeekDestination); +        mSeekWanted = false; +    } + +    // *TODO: time-limit - but there isn't a lot we can do here, most +    // time is spent in gstreamer's own opaque worker-threads.  maybe +    // we can do something sneaky like only unlock the video object +    // for 'milliseconds' and otherwise hold the lock. +    while (llg_main_context_pending(llg_main_loop_get_context(mPump))) +    { +           llg_main_context_iteration(llg_main_loop_get_context(mPump), FALSE); +    } + +    // check for availability of a new frame +     +    if( !mAppSink ) +        return true; + +    if( GST_STATE(mPlaybin) != GST_STATE_PLAYING) // Do not try to pull a sample if not in playing state +        return true; +     +    GstSample *pSample = llgst_app_sink_pull_sample( mAppSink ); +    if(!pSample) +        return false; // Done playing + +    GstSampleUnref oSampleUnref( pSample ); +    GstCaps *pCaps = llgst_sample_get_caps ( pSample ); +    if (!pCaps) +        return false; + +    gint width = 0, height = 0; +    GstStructure *pStruct = llgst_caps_get_structure ( pCaps, 0); + +    if(!llgst_structure_get_int ( pStruct, "width", &width) ) +        width = 0; +    if(!llgst_structure_get_int ( pStruct, "height", &height) ) +        height = 0; + +    if( !mPixels || width == 0 || height == 0) +        return true; +     +    GstBuffer *pBuffer = llgst_sample_get_buffer ( pSample ); +    GstMapInfo map; +    llgst_buffer_map ( pBuffer, &map, GST_MAP_READ); + +    // Our render buffer is always 1kx1k + +    U32 rowSkip = INTERNAL_TEXTURE_SIZE / mTextureHeight; +    U32 colSkip = INTERNAL_TEXTURE_SIZE / mTextureWidth; + +    for (int row = 0; row < mTextureHeight; ++row) +    { +        U8 const *pTexelIn = map.data + (row*rowSkip * width *3); +#ifndef FLIP_Y +        U8 *pTexelOut = mPixels + (row * mTextureWidth * mDepth ); +#else +        U8 *pTexelOut = mPixels + ((mTextureHeight-row-1) * mTextureWidth * mDepth ); +#endif       +        for( int col = 0; col < mTextureWidth; ++col ) +        { +            pTexelOut[ 0 ] = pTexelIn[0]; +            pTexelOut[ 1 ] = pTexelIn[1]; +            pTexelOut[ 2 ] = pTexelIn[2]; +            pTexelOut += mDepth; +            pTexelIn += colSkip*3; +        } +    } + +    llgst_buffer_unmap( pBuffer, &map ); +    setDirty(0,0,mTextureWidth,mTextureHeight); + +    return true; +} + +void MediaPluginGStreamer10::mouseDown( int x, int y ) +{ +  // do nothing +} + +void MediaPluginGStreamer10::mouseUp( int x, int y ) +{ +  // do nothing +} + +void MediaPluginGStreamer10::mouseMove( int x, int y ) +{ +  // do nothing +} + + +bool MediaPluginGStreamer10::pause() +{ +    // todo: error-check this? +    if (mDoneInit && mPlaybin) +    { +        llgst_element_set_state(mPlaybin, GST_STATE_PAUSED); +        return true; +    } +    return false; +} + +bool MediaPluginGStreamer10::stop() +{ +    // todo: error-check this? +    if (mDoneInit && mPlaybin) +    { +        llgst_element_set_state(mPlaybin, GST_STATE_READY); +        return true; +    } +    return false; +} + +bool MediaPluginGStreamer10::play(double rate) +{ +    // NOTE: we don't actually support non-natural rate. + +    // todo: error-check this? +    if (mDoneInit && mPlaybin) +    { +        llgst_element_set_state(mPlaybin, GST_STATE_PLAYING); +        return true; +    } +    return false; +} + +bool MediaPluginGStreamer10::setVolume( float volume ) +{ +    // we try to only update volume as conservatively as +    // possible, as many gst-plugins-base versions up to at least +    // November 2008 have critical race-conditions in setting volume - sigh +    if (mVolume == volume) +        return true; // nothing to do, everything's fine + +    mVolume = volume; +    if (mDoneInit && mPlaybin) +    { +        llg_object_set(mPlaybin, "volume", mVolume, nullptr); +        return true; +    } + +    return false; +} + +bool MediaPluginGStreamer10::seek(double time_sec) +{ +    bool success = false; +    if (mDoneInit && mPlaybin) +    { +        success = llgst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME, +                GstSeekFlags(GST_SEEK_FLAG_FLUSH | +                         GST_SEEK_FLAG_KEY_UNIT), +                GST_SEEK_TYPE_SET, gint64(time_sec*GST_SECOND), +                GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); +    } +    return success; +} + +bool MediaPluginGStreamer10::getTimePos(double &sec_out) +{ +    bool got_position = false; +    if (mDoneInit && mPlaybin) +    { +        gint64 pos(0); +        GstFormat timefmt = GST_FORMAT_TIME; +        got_position = +            llgst_element_query_position && +            llgst_element_query_position(mPlaybin, +                             &timefmt, +                             &pos); +        got_position = got_position +            && (timefmt == GST_FORMAT_TIME); +        // GStreamer may have other ideas, but we consider the current position +        // undefined if not PLAYING or PAUSED +        got_position = got_position && +            (GST_STATE(mPlaybin) == GST_STATE_PLAYING || +             GST_STATE(mPlaybin) == GST_STATE_PAUSED); +        if (got_position && !GST_CLOCK_TIME_IS_VALID(pos)) +        { +            if (GST_STATE(mPlaybin) == GST_STATE_PLAYING) +            { +                // if we're playing then we treat an invalid clock time +                // as 0, for complicated reasons (insert reason here) +                pos = 0; +            } +            else +            { +                got_position = false; +            } +             +        } +        // If all the preconditions succeeded... we can trust the result. +        if (got_position) +        { +            sec_out = double(pos) / double(GST_SECOND); // gst to sec +        } +    } +    return got_position; +} + +bool MediaPluginGStreamer10::load() +{ +    if (!mDoneInit) +        return false; // error + +    setStatus(STATUS_LOADING); + +    mIsLooping = false; +    mVolume = 0.1234567f; // minor hack to force an initial volume update + +    // Create a pumpable main-loop for this media +    mPump = llg_main_loop_new (nullptr, FALSE); +    if (!mPump) +    { +        setStatus(STATUS_ERROR); +        return false; // error +    } + +    // instantiate a playbin element to do the hard work +    mPlaybin = llgst_element_factory_make ("playbin", ""); +    if (!mPlaybin) +    { +        setStatus(STATUS_ERROR); +        return false; // error +    } + +    // get playbin's bus +    GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); +    if (!bus) +    { +        setStatus(STATUS_ERROR); +        return false; // error +    } +    mBusWatchID = llgst_bus_add_watch (bus, +                       llmediaimplgstreamer_bus_callback, +                       this); +    llgst_object_unref (bus); + +    mAppSink = (GstAppSink*)(llgst_element_factory_make ("appsink", "")); + +    GstCaps* pCaps = llgst_caps_new_simple( "video/x-raw", +                                            "format", G_TYPE_STRING, "RGB", +                                            "width", G_TYPE_INT, INTERNAL_TEXTURE_SIZE, +                                            "height", G_TYPE_INT, INTERNAL_TEXTURE_SIZE, +                                            nullptr ); + +    llgst_app_sink_set_caps( mAppSink, pCaps ); +    llgst_caps_unref( pCaps ); + +    if (!mAppSink) +    { +        setStatus(STATUS_ERROR); +        return false; +    } +     +    llg_object_set(mPlaybin, "video-sink", mAppSink, nullptr); + +    return true; +} + +bool MediaPluginGStreamer10::unload () +{ +    if (!mDoneInit) +        return false; // error + +    // stop getting callbacks for this bus +    llg_source_remove(mBusWatchID); +    mBusWatchID = 0; + +    if (mPlaybin) +    { +        llgst_element_set_state (mPlaybin, GST_STATE_NULL); +        llgst_object_unref (GST_OBJECT (mPlaybin)); +        mPlaybin = nullptr; +    } + +    if (mPump) +    { +        llg_main_loop_quit(mPump); +        mPump = nullptr; +    } + +    mAppSink = nullptr; + +    setStatus(STATUS_NONE); + +    return true; +} + +void LogFunction(GstDebugCategory *category, GstDebugLevel level, const gchar *file, const gchar *function, gint line, GObject *object, GstDebugMessage *message, gpointer user_data ) +{ +    std::cerr << file << ":" << line << "(" << function << "): " << llgst_debug_message_get( message ) << std::endl; +} + +//static +bool MediaPluginGStreamer10::startup() +{ +    // first - check if GStreamer is explicitly disabled +    if (nullptr != getenv("LL_DISABLE_GSTREAMER")) +        return false; + +    // only do global GStreamer initialization once. +    if (!mDoneInit) +    { +        ll_init_apr(); + +        // Get symbols! +        std::vector< std::string > vctDSONames; +        vctDSONames.push_back( "libgstreamer-1.0.so.0"  ); +        vctDSONames.push_back( "libgstapp-1.0.so.0"  ); +        vctDSONames.push_back( "libglib-2.0.so.0" ); +        vctDSONames.push_back( "libgobject-2.0.so" ); +        if( !gstSymbolGrabber.grabSymbols( vctDSONames ) ) +            return false; + +        if (llgst_segtrap_set_enabled) +        { +            llgst_segtrap_set_enabled(FALSE); +        } + +        // Gstreamer tries a fork during init, waitpid-ing on it, +        // which conflicts with any installed SIGCHLD handler... +        struct sigaction tmpact, oldact; +        if (llgst_registry_fork_set_enabled ) { +            // if we can disable SIGCHLD-using forking behaviour, +            // do it. +            llgst_registry_fork_set_enabled(false); +        } +        else { +            // else temporarily install default SIGCHLD handler +            // while GStreamer initialises +            tmpact.sa_handler = SIG_DFL; +            sigemptyset( &tmpact.sa_mask ); +            tmpact.sa_flags = SA_SIGINFO; +            sigaction(SIGCHLD, &tmpact, &oldact); +        } +        // Protect against GStreamer resetting the locale, yuck. +        static std::string saved_locale; +        saved_locale = setlocale(LC_ALL, nullptr); +         +        llgst_debug_set_default_threshold( GST_LEVEL_WARNING ); +        llgst_debug_add_log_function( LogFunction, nullptr, nullptr ); +        llgst_debug_set_active( false ); + +        // finally, try to initialize GStreamer! +        GError *err = nullptr; +        gboolean init_gst_success = llgst_init_check(nullptr, nullptr, &err); + +        // restore old locale +        setlocale(LC_ALL, saved_locale.c_str() ); + +        // restore old SIGCHLD handler +        if (!llgst_registry_fork_set_enabled) +            sigaction(SIGCHLD, &oldact, nullptr); + +        if (!init_gst_success) // fail +        { +            if (err) +                llg_error_free(err); +            return false; +        } +         +        mDoneInit = true; +    } + +    return true; +} + +//static +bool MediaPluginGStreamer10::closedown() +{ +    if (!mDoneInit) +        return false; // error + +    gstSymbolGrabber.ungrabSymbols(); +    mDoneInit = false; + +    return true; +} + +MediaPluginGStreamer10::~MediaPluginGStreamer10() +{ +    closedown(); +} + +std::string MediaPluginGStreamer10::getVersion() +{ +    std::string plugin_version = "GStreamer10 media plugin, GStreamer version "; +    if (mDoneInit && +        llgst_version) +    { +        guint major, minor, micro, nano; +        llgst_version(&major, &minor, µ, &nano); +        plugin_version += llformat("%u.%u.%u.%u (runtime), %u.%u.%u.%u (headers)", (unsigned int)major, (unsigned int)minor, +                                   (unsigned int)micro, (unsigned int)nano, (unsigned int)GST_VERSION_MAJOR, (unsigned int)GST_VERSION_MINOR, +                                   (unsigned int)GST_VERSION_MICRO, (unsigned int)GST_VERSION_NANO); +    } +    else +    { +        plugin_version += "(unknown)"; +    } +    return plugin_version; +} + +void MediaPluginGStreamer10::receiveMessage(const char *message_string) +{ +    LLPluginMessage message_in; + +    if(message_in.parse(message_string) >= 0) +    { +        std::string message_class = message_in.getClass(); +        std::string message_name = message_in.getName(); + +        if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) +        { +            if(message_name == "init") +            { +                LLPluginMessage message("base", "init_response"); +                LLSD versions = LLSD::emptyMap(); +                versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; +                versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; +                versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; +                message.setValueLLSD("versions", versions); + +                load(); + +                message.setValue("plugin_version", getVersion()); +                sendMessage(message); +            } +            else if(message_name == "idle") +            { +                // no response is necessary here. +                double time = message_in.getValueReal("time"); +                 +                // Convert time to milliseconds for update() +                update((int)(time * 1000.0f)); +            } +            else if(message_name == "cleanup") +            { +                unload(); +                closedown(); +            } +            else if(message_name == "shm_added") +            { +                SharedSegmentInfo info; +                info.mAddress = message_in.getValuePointer("address"); +                info.mSize = (size_t)message_in.getValueS32("size"); +                std::string name = message_in.getValue("name"); + +                mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); +            } +            else if(message_name == "shm_remove") +            { +                std::string name = message_in.getValue("name"); + +                SharedSegmentMap::iterator iter = mSharedSegments.find(name); +                if(iter != mSharedSegments.end()) +                { +                    if(mPixels == iter->second.mAddress) +                    { +                        // This is the currently active pixel buffer.  Make sure we stop drawing to it. +                        mPixels = nullptr; +                        mTextureSegmentName.clear(); +                    } +                    mSharedSegments.erase(iter); +                } + +                // Send the response so it can be cleaned up. +                LLPluginMessage message("base", "shm_remove_response"); +                message.setValue("name", name); +                sendMessage(message); +            } +        } +        else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) +        { +            if(message_name == "init") +            { +                // Plugin gets to decide the texture parameters to use. +                LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); +                // lame to have to decide this now, it depends on the movie.  Oh well. +                mDepth = 4; + +                mTextureWidth = 1; +                mTextureHeight = 1; + +                message.setValueU32("format", GL_RGBA); +                message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV); + +                message.setValueS32("depth", mDepth); +                message.setValueS32("default_width", INTERNAL_TEXTURE_SIZE ); +                message.setValueS32("default_height", INTERNAL_TEXTURE_SIZE ); +                message.setValueU32("internalformat", GL_RGBA8); +                message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left. +                message.setValueBoolean("allow_downsample", true); // we respond with grace and performance if asked to downscale +                sendMessage(message); +            } +            else if(message_name == "size_change") +            { +                std::string name = message_in.getValue("name"); +                S32 width = message_in.getValueS32("width"); +                S32 height = message_in.getValueS32("height"); +                S32 texture_width = message_in.getValueS32("texture_width"); +                S32 texture_height = message_in.getValueS32("texture_height"); + +                LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); +                message.setValue("name", name); +                message.setValueS32("width", width); +                message.setValueS32("height", height); +                message.setValueS32("texture_width", texture_width); +                message.setValueS32("texture_height", texture_height); +                sendMessage(message); + +                if(!name.empty()) +                { +                    // Find the shared memory region with this name +                    SharedSegmentMap::iterator iter = mSharedSegments.find(name); +                    if(iter != mSharedSegments.end()) +                    { +                        mPixels = (unsigned char*)iter->second.mAddress; +                        mTextureSegmentName = name; + +                        mTextureWidth = texture_width; +                        mTextureHeight = texture_height; +                        memset( mPixels, 0, mTextureWidth*mTextureHeight*mDepth ); +                    } +                     +                    LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request"); +                    message.setValue("name", mTextureSegmentName); +                    message.setValueS32("width", INTERNAL_TEXTURE_SIZE ); +                    message.setValueS32("height", INTERNAL_TEXTURE_SIZE ); +                    sendMessage(message); + +                } +            } +            else if(message_name == "load_uri") +            { +                std::string uri = message_in.getValue("uri"); +                navigateTo( uri ); +                sendStatus();        +            } +            else if(message_name == "mouse_event") +            { +                std::string event = message_in.getValue("event"); +                S32 x = message_in.getValueS32("x"); +                S32 y = message_in.getValueS32("y"); +                 +                if(event == "down") +                { +                    mouseDown(x, y); +                } +                else if(event == "up") +                { +                    mouseUp(x, y); +                } +                else if(event == "move") +                { +                    mouseMove(x, y); +                }; +            }; +        } +        else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) +        { +            if(message_name == "stop") +            { +                stop(); +            } +            else if(message_name == "start") +            { +                double rate = 0.0; +                if(message_in.hasValue("rate")) +                { +                    rate = message_in.getValueReal("rate"); +                } +                // NOTE: we don't actually support rate. +                play(rate); +            } +            else if(message_name == "pause") +            { +                pause(); +            } +            else if(message_name == "seek") +            { +                double time = message_in.getValueReal("time"); +                // defer the actual seek in case we haven't +                // really truly started yet in which case there +                // is nothing to seek upon +                mSeekWanted = true; +                mSeekDestination = time; +            } +            else if(message_name == "set_loop") +            { +                bool loop = message_in.getValueBoolean("loop"); +                mIsLooping = loop; +            } +            else if(message_name == "set_volume") +            { +                double volume = message_in.getValueReal("volume"); +                setVolume(volume); +            } +        } +    } +} + +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ +    if( MediaPluginGStreamer10::startup() ) +    { +        MediaPluginGStreamer10 *self = new MediaPluginGStreamer10(host_send_func, host_user_data); +        *plugin_send_func = MediaPluginGStreamer10::staticReceiveMessage; +        *plugin_user_data = (void*)self; +         +        return 0; // okay +    } +    else  +    { +        return -1; // failed to init +    } +} diff --git a/indra/media_plugins/libvlc/CMakeLists.txt b/indra/media_plugins/libvlc/CMakeLists.txt index a3c1c4ef99..eaf9dde981 100644 --- a/indra/media_plugins/libvlc/CMakeLists.txt +++ b/indra/media_plugins/libvlc/CMakeLists.txt @@ -13,13 +13,6 @@ include(LibVLCPlugin)  ### media_plugin_libvlc -if(NOT ADDRESS_SIZE EQUAL 32) -  if(WINDOWS) -    ##add_definitions(/FIXED:NO) -  else(WINDOWS) # not windows therefore gcc LINUX and DARWIN -    add_definitions(-fPIC) -  endif(WINDOWS) -endif(NOT ADDRESS_SIZE EQUAL 32)  set(media_plugin_libvlc_SOURCE_FILES      media_plugin_libvlc.cpp diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c2869eedfd..fc4f089f2a 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1448,7 +1448,6 @@ if (LINUX)        PROPERTIES        COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}"        ) -    LIST(APPEND viewer_SOURCE_FILES llappviewerlinux_api_dbus.cpp)      SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed")  endif (LINUX) @@ -2384,4 +2383,3 @@ if (LL_TESTS)  endif (LL_TESTS)  check_message_template(${VIEWER_BINARY_NAME}) - diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7513c8e3d3..3eaa65b5a0 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4920,6 +4920,17 @@      <key>Value</key>      <integer>0</integer>    </map> +  <key>MediaPluginPipeWireVolumeCatcher</key> +  <map> +    <key>Comment</key> +    <string>Use PipeWire instead of PulseAudio for controlling web media volume.</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>Boolean</string> +    <key>Value</key> +    <integer>0</integer> +  </map>    <key>MediaControlFadeTime</key>    <map>      <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl index cf0595ee45..a33c4cc58b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl @@ -25,13 +25,13 @@  // debug stub -float random (vec2 uv) +float random (vec2 uv)   { -    return 0; +    return 0.;  }  float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source, float glossiness)  {      collectedColor = vec4(0); -    return 0; +    return 0.;  } diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index 210ecce8db..94d5664815 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -79,7 +79,9 @@ float getAmbientClamp();  void mirrorClip(vec3 pos); -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, +void mirrorClip(vec3 pos); + +void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv,          vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear);  vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, float ambiance) diff --git a/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl index d178bf22b6..35848ff4cd 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl @@ -37,7 +37,7 @@ void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,          vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear)  {      ambenv = vec3(reflection_probe_ambiance * 0.25); - +          vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));      vec3 env_vec = env_mat * refnormpersp;      glossenv = srgb_to_linear(texture(environmentMap, env_vec).rgb); @@ -55,11 +55,11 @@ vec4 sampleReflectionProbesDebug(vec3 pos)      return vec4(0, 0, 0, 0);  } -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, +void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv,          vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear)  {      ambenv = vec3(reflection_probe_ambiance * 0.25); - +          vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));      vec3 env_vec = env_mat * refnormpersp; @@ -70,7 +70,7 @@ void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout  void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm)  { - +      }  void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity) diff --git a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl index 03dc3d7113..5e38864d38 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl @@ -48,7 +48,7 @@ vec3 linear_to_srgb(vec3 c);  vec3 srgb_to_linear(vec3 c);  // reflection probe interface -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, +void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv,          vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear);  void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl index d3e19cf4a8..28b1b5f5e6 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl @@ -60,7 +60,7 @@ out vec4 frag_color;  float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);  #endif -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, +void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv,          vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear);  void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm);  void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); @@ -281,10 +281,10 @@ float getShadow(vec3 pos, vec3 norm)      #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)          return sampleDirectionalShadow(pos, norm, vary_texcoord0.xy);      #else -        return 1; +        return 1.;      #endif  #else -    return 1; +    return 1.;  #endif  } diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl index 90c84cc428..ae3188cebd 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl @@ -452,8 +452,8 @@ void boxIntersectionDebug( in vec3 ro, in vec3 p, vec3 boxSize, inout vec4 col)  void boxIntersectDebug(vec3 origin, vec3 pos, mat4 i, inout vec4 col)  { -    mat4 clipToLocal = i; -     +    mat4 clipToLocal = refBox[i]; +      // transform into unit cube space      origin = (clipToLocal * vec4(origin, 1.0)).xyz;      pos = (clipToLocal * vec4(pos, 1.0)).xyz; @@ -837,7 +837,7 @@ vec4 sampleReflectionProbesDebug(vec3 pos)      return col;  } -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, +void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv,          vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit)  {      float reflection_lods = max_probe_lod; diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl index 96c32734e4..8db04f2c18 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl @@ -71,7 +71,7 @@ vec3  scaleSoftClipFragLinear(vec3 l);  // reflection probe interface  void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,      vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear); -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, +void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 legacyenv,          vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear);  void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm);  void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); @@ -169,7 +169,7 @@ void main()      if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR))      { -        vec3 orm = spec.rgb;  +        vec3 orm = texture(specularRect, tc).rgb;          float perceptualRoughness = orm.g;          float metallic = orm.b;          float ao = orm.r; @@ -179,7 +179,7 @@ void main()          float gloss      = 1.0 - perceptualRoughness;          sampleReflectionProbes(irradiance, radiance, tc, pos.xyz, norm.xyz, gloss, false, amblit_linear); - +                  adjustIrradiance(irradiance, ambocc);          vec3 diffuseColor; @@ -215,7 +215,7 @@ void main()          vec3 legacyenv = vec3(0);          sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, tc, pos.xyz, norm.xyz, spec.a, envIntensity, false, amblit_linear); - +                  adjustIrradiance(irradiance, ambocc);          // apply lambertian IBL only (see pbrIbl) diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index eb3ead433b..a027aaf6d1 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -58,21 +58,14 @@ fi  ## - Avoids an often-buggy X feature that doesn't really benefit us anyway.  export SDL_VIDEO_X11_DGAMOUSE=0 -## - Works around a problem with misconfigured 64-bit systems not finding GL -I386_MULTIARCH="$(dpkg-architecture -ai386 -qDEB_HOST_MULTIARCH 2>/dev/null)" -MULTIARCH_ERR=$? -if [ $MULTIARCH_ERR -eq 0 ]; then -    echo 'Multi-arch support detected.' -    MULTIARCH_GL_DRIVERS="/usr/lib/${I386_MULTIARCH}/dri" -    export LIBGL_DRIVERS_PATH="${LIBGL_DRIVERS_PATH}:${MULTIARCH_GL_DRIVERS}:/usr/lib64/dri:/usr/lib32/dri:/usr/lib/dri" -else -    export LIBGL_DRIVERS_PATH="${LIBGL_DRIVERS_PATH}:/usr/lib64/dri:/usr/lib32/dri:/usr/lib/dri" -fi -  ## - The 'scim' GTK IM module widely crashes the viewer.  Avoid it.  if [ "$GTK_IM_MODULE" = "scim" ]; then      export GTK_IM_MODULE=xim  fi +if [ "$XMODIFIERS" = "" ]; then +    ## IME is valid only for fcitx, not when using ibus +    export XMODIFIERS="@im=fcitx" +fi  ## - Automatically work around the ATI mouse cursor crash bug:  ## (this workaround is disabled as most fglrx users do not see the bug) @@ -98,25 +91,6 @@ cd "${RUN_PATH}"  ## Before we mess with LD_LIBRARY_PATH, save the old one to restore for  ##  subprocesses that care.  export SAVED_LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" - -# if [ -n "$LL_TCMALLOC" ]; then -#    tcmalloc_libs='/usr/lib/libtcmalloc.so.0 /usr/lib/libstacktrace.so.0 /lib/libpthread.so.0' -#    all=1 -#    for f in $tcmalloc_libs; do -#        if [ ! -f $f ]; then -#	    all=0 -#	fi -#    done -#    if [ $all != 1 ]; then -#        echo 'Cannot use tcmalloc libraries: components missing' 1>&2 -#    else -#	export LD_PRELOAD=$(echo $tcmalloc_libs | tr ' ' :) -#	if [ -z "$HEAPCHECK" -a -z "$HEAPPROFILE" ]; then -#	    export HEAPCHECK=${HEAPCHECK:-normal} -#	fi -#    fi -#fi -  export LD_LIBRARY_PATH="$PWD/lib:${LD_LIBRARY_PATH}"  # Copy "$@" to ARGS array specifically to delete the --skip-gridargs switch. @@ -140,18 +114,6 @@ LL_RUN_ERR=$?  if [ $LL_RUN_ERR -ne 0 ]; then  	# generic error running the binary  	echo '*** Bad shutdown ($LL_RUN_ERR). ***' -	if [ "$(uname -m)" = "x86_64" ]; then -		echo -		cat << EOFMARKER -You are running the Second Life Viewer on a x86_64 platform.  The -most common problems when launching the Viewer (particularly -'bin/do-not-directly-run-secondlife-bin: not found' and 'error while -loading shared libraries') may be solved by installing your Linux -distribution's 32-bit compatibility packages. -For example, on Ubuntu and other Debian-based Linuxes you might run: -$ sudo apt-get install ia32-libs ia32-libs-gtk ia32-libs-kde ia32-libs-sdl -EOFMARKER -	fi  fi  echo diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 76271571cd..b2ce4d56dd 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -1385,8 +1385,6 @@ void AISUpdate::parseCategory(const LLSD& category_map, S32 depth)                       && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN                       && version > curr_cat->getVersion())              { -                // Potentially should new_cat->setVersion(unknown) here, -                // but might be waiting for a callback that would increment                  LL_DEBUGS("Inventory") << "Category " << category_id                      << " is stale. Known version: " << curr_cat->getVersion()                      << " server version: " << version << LL_ENDL; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 1626af74e2..77d9bc305a 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -266,10 +266,6 @@ using namespace LL;  // define a self-registering event API object  #include "llappviewerlistener.h" -#if LL_LINUX && LL_GTK -#include "glib.h" -#endif // (LL_LINUX) && LL_GTK -  #if LL_MSVC  // disable boost::lexical_cast warning  #pragma warning (disable:4702) @@ -1125,7 +1121,7 @@ bool LLAppViewer::init()      gGLActive = FALSE; -#if LL_RELEASE_FOR_DOWNLOAD +#if LL_RELEASE_FOR_DOWNLOAD && !LL_LINUX      // Skip updater if this is a non-interactive instance      if (!gSavedSettings.getBOOL("CmdLineSkipUpdater") && !gNonInteractive)      { @@ -2354,6 +2350,14 @@ void LLAppViewer::initLoggingAndGetLastDuration()          {              LL_WARNS("MarkerFile") << duration_log_msg << LL_ENDL;          } + +        std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.log"); +        if (gDirUtilp->fileExists(user_data_path_cef_log)) +        { +            std::string user_data_path_cef_old = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.old"); +            LLFile::remove(user_data_path_cef_old, ENOENT); +            LLFile::rename(user_data_path_cef_log, user_data_path_cef_old); +        }      }  } @@ -5693,4 +5697,3 @@ void LLAppViewer::metricsSend(bool enable_reporting)      // resolution in time.      gViewerAssetStats->restart();  } - diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 1709970156..2f366f0538 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -40,17 +40,57 @@  #include <exception> -#if LL_DBUS_ENABLED -# include "llappviewerlinux_api_dbus.h" - -// regrettable hacks to give us better runtime compatibility with older systems inside llappviewerlinux_api.h: -#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0) -#undef g_return_if_fail -#define g_return_if_fail(COND) llg_return_if_fail(COND) -// The generated API -# include "llappviewerlinux_api.h" +#include <gio/gio.h> +#include <resolv.h> + +#if (__GLIBC__*1000 + __GLIBC_MINOR__) >= 2034 +extern "C" +{ +  int __res_nquery(res_state statep, +                   const char *dname, int qclass, int type, +                   unsigned char *answer, int anslen) +  { +    return res_nquery( statep, dname, qclass, type, answer, anslen ); +  } + +  int __dn_expand(const unsigned char *msg, +                  const unsigned char *eomorig, +                  const unsigned char *comp_dn, char *exp_dn, +                  int length) +  { +    return dn_expand( msg,eomorig,comp_dn,exp_dn,length); +  } +} +#endif + +#if LL_SEND_CRASH_REPORTS +#include "breakpad/client/linux/handler/exception_handler.h" +#include "breakpad/common/linux/http_upload.h" +#include "lldir.h" +#include "../llcrashlogger/llcrashlogger.h" +#include "jsoncpp/reader.h" // JSON +  #endif +#define VIEWERAPI_SERVICE "com.secondlife.ViewerAppAPIService" +#define VIEWERAPI_PATH "/com/secondlife/ViewerAppAPI" +#define VIEWERAPI_INTERFACE "com.secondlife.ViewerAppAPI" + +static const char * DBUS_SERVER = "<node name=\"/com/secondlife/ViewerAppAPI\">\n" +                                  "  <interface name=\"com.secondlife.ViewerAppAPI\">\n" +                                  "    <annotation name=\"org.freedesktop.DBus.GLib.CSymbol\" value=\"viewer_app_api\"/>\n" +                                  "    <method name=\"GoSLURL\">\n" +                                  "      <annotation name=\"org.freedesktop.DBus.GLib.CSymbol\" value=\"dispatchSLURL\"/>\n" +                                  "      <arg type=\"s\" name=\"slurl\" direction=\"in\" />\n" +                                  "    </method>\n" +                                  "  </interface>\n" +                                  "</node>"; + +typedef struct +{ +    GObject parent; +} ViewerAppAPI; +  namespace  {      int gArgC = 0; @@ -81,6 +121,8 @@ int main( int argc, char **argv )      // install unexpected exception handler      gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler); +    unsetenv( "LD_PRELOAD" ); // <FS:ND/> Get rid of any preloading, we do not want this to happen during startup of plugins. +      bool ok = viewer_app_ptr->init();      if(!ok)      { @@ -114,21 +156,74 @@ LLAppViewerLinux::~LLAppViewerLinux()  {  } -bool LLAppViewerLinux::init() +#if LL_SEND_CRASH_REPORTS +std::string gCrashLogger; +std::string gVersion; +std::string gBugsplatDB; +std::string gCrashBehavior; + +static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) +{ +    if( fork() == 0 ) +        execl( gCrashLogger.c_str(), gCrashLogger.c_str(), descriptor.path(), gVersion.c_str(), gBugsplatDB.c_str(),  gCrashBehavior.c_str(), nullptr ); +    return succeeded; +} + +void setupBreadpad()  { -    // g_thread_init() must be called before *any* use of glib, *and* -    // before any mutexes are held, *and* some of our third-party -    // libraries likes to use glib functions; in short, do this here -    // really early in app startup! -    if (!g_thread_supported ()) g_thread_init (NULL); +    std::string build_data_fname(gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); +    gCrashLogger =  gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "linux-crash-logger.bin"); + +    llifstream inf(build_data_fname.c_str()); +    if(!inf.is_open()) +    { +        LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't read '" << build_data_fname << "'" << LL_ENDL; +        return; +    } + +    Json::Reader reader; +    Json::Value build_data; +    if(!reader.parse(inf, build_data, false)) +    { +        LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't parse '" << build_data_fname << "': " +                             << reader.getFormatedErrorMessages() << LL_ENDL; +        return; +    } +    Json::Value BugSplat_DB = build_data["BugSplat DB"]; +    if(!BugSplat_DB) +    { +        LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" << build_data_fname +                             << "'" << LL_ENDL; +        return; +    } +    gVersion = STRINGIZE( +            LL_VIEWER_VERSION_MAJOR << '.' << LL_VIEWER_VERSION_MINOR << '.' << LL_VIEWER_VERSION_PATCH +                                    << '.' << LL_VIEWER_VERSION_BUILD); +    gBugsplatDB = BugSplat_DB.asString(); + +    LL_INFOS("BUGSPLAT") << "Initializing with crash logger: " << gCrashLogger << " database: " << gBugsplatDB << " version: " << gVersion << LL_ENDL; + +    google_breakpad::MinidumpDescriptor *descriptor = new google_breakpad::MinidumpDescriptor(gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "")); +    google_breakpad::ExceptionHandler *eh = new google_breakpad::ExceptionHandler(*descriptor, NULL, dumpCallback, NULL, true, -1); +} +#endif + +bool LLAppViewerLinux::init() +{      bool success = LLAppViewer::init();  #if LL_SEND_CRASH_REPORTS -    if (success) +    S32 nCrashSubmitBehavior = gCrashSettings.getS32("CrashSubmitBehavior"); + +    // For the first version we just consider always send and create a nice dialog for CRASH_BEHAVIOR_ASK later. +    if (success && nCrashSubmitBehavior != CRASH_BEHAVIOR_NEVER_SEND )      { -        LLAppViewer* pApp = LLAppViewer::instance(); -        pApp->initCrashReporting(); +        if( nCrashSubmitBehavior == CRASH_BEHAVIOR_ASK ) +            gCrashBehavior = "ask"; +        else +            gCrashBehavior = "send"; +        setupBreadpad();      }  #endif @@ -143,7 +238,7 @@ bool LLAppViewerLinux::restoreErrorTrap()  }  ///////////////////////////////////////// -#if LL_DBUS_ENABLED +#if LL_GLIB  typedef struct  { @@ -153,101 +248,77 @@ typedef struct  static void viewerappapi_init(ViewerAppAPI *server);  static void viewerappapi_class_init(ViewerAppAPIClass *klass); -/// - -// regrettable hacks to give us better runtime compatibility with older systems in general -static GType llg_type_register_static_simple_ONCE(GType parent_type, -                          const gchar *type_name, -                          guint class_size, -                          GClassInitFunc class_init, -                          guint instance_size, -                          GInstanceInitFunc instance_init, -                          GTypeFlags flags) -{ -    static GTypeInfo type_info; -    memset(&type_info, 0, sizeof(type_info)); - -    type_info.class_size = class_size; -    type_info.class_init = class_init; -    type_info.instance_size = instance_size; -    type_info.instance_init = instance_init; - -    return g_type_register_static(parent_type, type_name, &type_info, flags); -} -#define llg_intern_static_string(S) (S) -#define g_intern_static_string(S) llg_intern_static_string(S) -#define g_type_register_static_simple(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags) llg_type_register_static_simple_ONCE(parent_type, type_name, class_size, class_init, instance_size, instance_init, flags) -  G_DEFINE_TYPE(ViewerAppAPI, viewerappapi, G_TYPE_OBJECT);  void viewerappapi_class_init(ViewerAppAPIClass *klass)  {  } -static bool dbus_server_init = false; - -void viewerappapi_init(ViewerAppAPI *server) +static void dispatchSLURL(gchar const *slurl)  { -    // Connect to the default DBUS, register our service/API. - -    if (!dbus_server_init) -    { -        GError *error = NULL; - -        server->connection = lldbus_g_bus_get(DBUS_BUS_SESSION, &error); -        if (server->connection) -        { -            lldbus_g_object_type_install_info(viewerappapi_get_type(), &dbus_glib_viewerapp_object_info); +    LL_INFOS() << "Was asked to go to slurl: " << slurl << LL_ENDL; -            lldbus_g_connection_register_g_object(server->connection, VIEWERAPI_PATH, G_OBJECT(server)); +    std::string url = slurl; +    LLMediaCtrl* web = NULL; +    const bool trusted_browser = false; +    LLURLDispatcher::dispatch(url, "", web, trusted_browser); +} -            DBusGProxy *serverproxy = lldbus_g_proxy_new_for_name(server->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); +static void DoMethodeCall (GDBusConnection       *connection, +                                const gchar           *sender, +                                const gchar           *object_path, +                                const gchar           *interface_name, +                                const gchar           *method_name, +                                GVariant              *parameters, +                                GDBusMethodInvocation *invocation, +                                gpointer               user_data) +{ +    LL_INFOS() << "DBUS message " << method_name << "  from: " << sender << " interface: " << interface_name << LL_ENDL; +    const gchar *slurl; -            guint request_name_ret_unused; -            // akin to org_freedesktop_DBus_request_name -            if (lldbus_g_proxy_call(serverproxy, "RequestName", &error, G_TYPE_STRING, VIEWERAPI_SERVICE, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &request_name_ret_unused, G_TYPE_INVALID)) -            { -                // total success. -                dbus_server_init = true; -            } -            else -            { -                LL_WARNS() << "Unable to register service name: " << error->message << LL_ENDL; -            } +    g_variant_get (parameters, "(&s)", &slurl); +    dispatchSLURL(slurl); +} -            g_object_unref(serverproxy); -        } -        else +GDBusNodeInfo *gBusNodeInfo = nullptr; +static const GDBusInterfaceVTable interface_vtable =          { -            g_warning("Unable to connect to dbus: %s", error->message); -        } - -        if (error) -            g_error_free(error); -    } +                DoMethodeCall +        }; +static void busAcquired(GDBusConnection *connection, const gchar *name, gpointer user_data) +{ +    auto id = g_dbus_connection_register_object(connection, +                                                VIEWERAPI_PATH, +                                                gBusNodeInfo->interfaces[0], +                                                &interface_vtable, +                                                NULL,  /* user_data */ +                                                             NULL,  /* user_data_free_func */ +                                                             NULL); /* GError** */ +    g_assert (id > 0);  } -gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **success_rtn, GError **error) +static void nameAcquired(GDBusConnection *connection, const gchar *name, gpointer user_data)  { -    bool success = false; - -    LL_INFOS() << "Was asked to go to slurl: " << slurl << LL_ENDL; +} -    std::string url = slurl; -    LLMediaCtrl* web = NULL; -    const bool trusted_browser = false; -    if (LLURLDispatcher::dispatch(url, "", web, trusted_browser)) -    { -        // bring window to foreground, as it has just been "launched" from a URL -        // todo: hmm, how to get there from here? -        //xxx->mWindow->bringToFront(); -        success = true; -    } +static void nameLost(GDBusConnection *connection, const gchar *name, gpointer user_data) +{ -    *success_rtn = g_new (gboolean, 1); -    (*success_rtn)[0] = (gboolean)success; +} +void viewerappapi_init(ViewerAppAPI *server) +{ +    gBusNodeInfo = g_dbus_node_info_new_for_xml (DBUS_SERVER, NULL); +    g_assert (gBusNodeInfo != NULL); + +    g_bus_own_name(G_BUS_TYPE_SESSION, +                   VIEWERAPI_SERVICE, +                   G_BUS_NAME_OWNER_FLAGS_NONE, +                   busAcquired, +                   nameAcquired, +                   nameLost, +                   NULL, +                   NULL); -    return TRUE; // the invokation succeeded, even if the actual dispatch didn't.  }  /// @@ -255,13 +326,6 @@ gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **succ  //virtual  bool LLAppViewerLinux::initSLURLHandler()  { -    if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME)) -    { -        return false; // failed -    } - -    g_type_init(); -      //ViewerAppAPI *api_server = (ViewerAppAPI*)      g_object_new(viewerappapi_get_type(), NULL); @@ -271,49 +335,49 @@ bool LLAppViewerLinux::initSLURLHandler()  //virtual  bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)  { -    if (!grab_dbus_syms(DBUSGLIB_DYLIB_DEFAULT_NAME)) +    auto *pBus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, nullptr); + +    if( !pBus )      { -        return false; // failed +        LL_WARNS() << "Getting dbus failed." << LL_ENDL; +        return false;      } -    bool success = false; -    DBusGConnection *bus; -    GError *error = NULL; - -    g_type_init(); +    auto pProxy = g_dbus_proxy_new_sync(pBus, G_DBUS_PROXY_FLAGS_NONE, nullptr, +                                        VIEWERAPI_SERVICE, VIEWERAPI_PATH, +                                        VIEWERAPI_INTERFACE, nullptr, nullptr); -    bus = lldbus_g_bus_get (DBUS_BUS_SESSION, &error); -    if (bus) +    if( !pProxy )      { -        gboolean rtn = FALSE; -        DBusGProxy *remote_object = -            lldbus_g_proxy_new_for_name(bus, VIEWERAPI_SERVICE, VIEWERAPI_PATH, VIEWERAPI_INTERFACE); - -        if (lldbus_g_proxy_call(remote_object, "GoSLURL", &error, -                    G_TYPE_STRING, url.c_str(), G_TYPE_INVALID, -                       G_TYPE_BOOLEAN, &rtn, G_TYPE_INVALID)) -        { -            success = rtn; -        } -        else -        { -            LL_INFOS() << "Call-out to other instance failed (perhaps not running): " << error->message << LL_ENDL; -        } - -        g_object_unref(G_OBJECT(remote_object)); +        LL_WARNS() << "Cannot create new dbus proxy." << LL_ENDL; +        g_object_unref( pBus ); +        return false;      } -    else + +    auto *pArgs = g_variant_new( "(s)", url.c_str() ); +    if( !pArgs )      { -        LL_WARNS() << "Couldn't connect to session bus: " << error->message << LL_ENDL; +        LL_WARNS() << "Cannot create new variant." << LL_ENDL; +        g_object_unref( pBus ); +        return false;      } -    if (error) -        g_error_free(error); +    auto pRes  = g_dbus_proxy_call_sync(pProxy, +                                        "GoSLURL", +                                        pArgs, +                                        G_DBUS_CALL_FLAGS_NONE, +                                        -1, nullptr, nullptr); -    return success; + + +    if( pRes ) +        g_variant_unref( pRes ); +    g_object_unref( pProxy ); +    g_object_unref( pBus ); +    return true;  } -#else // LL_DBUS_ENABLED +#else // LL_GLIB  bool LLAppViewerLinux::initSLURLHandler()  {      return false; // not implemented without dbus @@ -322,7 +386,7 @@ bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)  {      return false; // not implemented without dbus  } -#endif // LL_DBUS_ENABLED +#endif // LL_GLIB  void LLAppViewerLinux::initCrashReporting(bool reportFreeze)  { @@ -338,15 +402,18 @@ void LLAppViewerLinux::initCrashReporting(bool reportFreeze)      pid_str <<  LLApp::getPid();      std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");      std::string appname = gDirUtilp->getExecutableFilename(); +    std::string grid{ LLGridManager::getInstance()->getGridId() }; +    std::string title{ LLAppViewer::instance()->getSecondLifeTitle() }; +    std::string pidstr{ pid_str.str() };      // launch the actual crash logger      const char * cmdargv[] =          {cmd.c_str(),           "-user", -         (char*)LLGridManager::getInstance()->getGridId().c_str(), +         grid.c_str(),           "-name", -         LLAppViewer::instance()->getSecondLifeTitle().c_str(), +         title.c_str(),           "-pid", -         pid_str.str().c_str(), +         pidstr.c_str(),           "-dumpdir",           logdir.c_str(),           "-procname", diff --git a/indra/newview/llappviewerlinux.h b/indra/newview/llappviewerlinux.h index dde223878d..460ca721f1 100644 --- a/indra/newview/llappviewerlinux.h +++ b/indra/newview/llappviewerlinux.h @@ -27,17 +27,6 @@  #ifndef LL_LLAPPVIEWERLINUX_H  #define LL_LLAPPVIEWERLINUX_H -extern "C" { -# include <glib.h> -} - -#if LL_DBUS_ENABLED -extern "C" { -# include <glib-object.h> -# include <dbus/dbus-glib.h> -} -#endif -  #ifndef LL_LLAPPVIEWER_H  #include "llappviewer.h"  #endif @@ -70,21 +59,4 @@ protected:      virtual bool sendURLToOtherInstance(const std::string& url);  }; -#if LL_DBUS_ENABLED -typedef struct -{ -        GObject parent; -        DBusGConnection *connection; -} ViewerAppAPI; - -extern "C" { -    gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **success_rtn, GError **error); -} - -#define VIEWERAPI_SERVICE "com.secondlife.ViewerAppAPIService" -#define VIEWERAPI_PATH "/com/secondlife/ViewerAppAPI" -#define VIEWERAPI_INTERFACE "com.secondlife.ViewerAppAPI" - -#endif // LL_DBUS_ENABLED -  #endif // LL_LLAPPVIEWERLINUX_H diff --git a/indra/newview/llappviewerlinux_api.h b/indra/newview/llappviewerlinux_api.h deleted file mode 100644 index 3d1324dd19..0000000000 --- a/indra/newview/llappviewerlinux_api.h +++ /dev/null @@ -1,143 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ -/** - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#ifndef __dbus_glib_marshal_viewerapp_MARSHAL_H__ -#define __dbus_glib_marshal_viewerapp_MARSHAL_H__ - -#include    <glib-object.h> - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v) -#define g_marshal_value_peek_char(v)     g_value_get_char (v) -#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v) -#define g_marshal_value_peek_int(v)      g_value_get_int (v) -#define g_marshal_value_peek_uint(v)     g_value_get_uint (v) -#define g_marshal_value_peek_long(v)     g_value_get_long (v) -#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v)     g_value_get_enum (v) -#define g_marshal_value_peek_flags(v)    g_value_get_flags (v) -#define g_marshal_value_peek_float(v)    g_value_get_float (v) -#define g_marshal_value_peek_double(v)   g_value_get_double (v) -#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v)    g_value_get_param (v) -#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v) -#define g_marshal_value_peek_object(v)   g_value_get_object (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - *          Do not access GValues directly in your code. Instead, use the - *          g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int -#define g_marshal_value_peek_char(v)     (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint -#define g_marshal_value_peek_int(v)      (v)->data[0].v_int -#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint -#define g_marshal_value_peek_long(v)     (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long -#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v)    (v)->data[0].v_float -#define g_marshal_value_peek_double(v)   (v)->data[0].v_double -#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* BOOLEAN:STRING,POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.5XXD8T:1) */ -extern void dbus_glib_marshal_viewerapp_BOOLEAN__STRING_POINTER_POINTER (GClosure     *closure, -                                                                         GValue       *return_value, -                                                                         guint         n_param_values, -                                                                         const GValue *param_values, -                                                                         gpointer      invocation_hint, -                                                                         gpointer      marshal_data); -void -dbus_glib_marshal_viewerapp_BOOLEAN__STRING_POINTER_POINTER (GClosure     *closure, -                                                             GValue       *return_value, -                                                             guint         n_param_values, -                                                             const GValue *param_values, -                                                             gpointer      invocation_hint, -                                                             gpointer      marshal_data) -{ -  typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (gpointer     data1, -                                                                    gpointer     arg_1, -                                                                    gpointer     arg_2, -                                                                    gpointer     arg_3, -                                                                    gpointer     data2); -  register GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER callback; -  register GCClosure *cc = (GCClosure*) closure; -  register gpointer data1, data2; -  gboolean v_return; - -  g_return_if_fail (return_value != NULL); -  g_return_if_fail (n_param_values == 4); - -  if (G_CCLOSURE_SWAP_DATA (closure)) -    { -      data1 = closure->data; -      data2 = g_value_peek_pointer (param_values + 0); -    } -  else -    { -      data1 = g_value_peek_pointer (param_values + 0); -      data2 = closure->data; -    } -  callback = (GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); - -  v_return = callback (data1, -                       g_marshal_value_peek_string (param_values + 1), -                       g_marshal_value_peek_pointer (param_values + 2), -                       g_marshal_value_peek_pointer (param_values + 3), -                       data2); - -  g_value_set_boolean (return_value, v_return); -} - -G_END_DECLS - -#endif /* __dbus_glib_marshal_viewerapp_MARSHAL_H__ */ - -#include <dbus/dbus-glib.h> -static const DBusGMethodInfo dbus_glib_viewerapp_methods[] = { -  { (GCallback) viewer_app_api_GoSLURL, dbus_glib_marshal_viewerapp_BOOLEAN__STRING_POINTER_POINTER, 0 }, -}; - -const DBusGObjectInfo dbus_glib_viewerapp_object_info = { -  0, -  dbus_glib_viewerapp_methods, -  1, -"com.secondlife.ViewerAppAPI\0GoSLURL\0S\0slurl\0I\0s\0success_ret\0O\0F\0N\0b\0\0\0", -"\0", -"\0" -}; - diff --git a/indra/newview/llappviewerlinux_api.xml b/indra/newview/llappviewerlinux_api.xml deleted file mode 100644 index fac35b7adc..0000000000 --- a/indra/newview/llappviewerlinux_api.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> - -<!-- dbus-binding-tool -mode=glib-server llappviewerlinux_api.xml -prefix=viewerapp -output=llappviewerlinux_api.h --> - -<node name="/com/secondlife/ViewerAppAPI"> -  <interface name="com.secondlife.ViewerAppAPI"> -    <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="viewer_app_api"/> -    <method name="GoSLURL"> -      <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="viewer_app_api_GoSLURL"/> -      <arg type="s" name="slurl" direction="in" /> -      <arg type="b" name="success_ret" direction="out" /> -    </method> -  </interface> -</node> diff --git a/indra/newview/llappviewerlinux_api_dbus.cpp b/indra/newview/llappviewerlinux_api_dbus.cpp deleted file mode 100644 index be769356c3..0000000000 --- a/indra/newview/llappviewerlinux_api_dbus.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/** - * @file llappviewerlinux_api_dbus.cpp - * @brief dynamic DBus symbol-grabbing code - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#if LL_DBUS_ENABLED - -#include "linden_common.h" - -extern "C" { -#include <dbus/dbus-glib.h> - -#include "apr_pools.h" -#include "apr_dso.h" -} - -#define DEBUGMSG(...) do { LL_DEBUGS() << llformat(__VA_ARGS__) << LL_ENDL; } while(0) -#define INFOMSG(...) do { LL_INFOS() << llformat(__VA_ARGS__) << LL_ENDL; } while(0) -#define WARNMSG(...) do { LL_WARNS() << llformat(__VA_ARGS__) << LL_ENDL; } while(0) - -#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) RTN (*ll##DBUSSYM)(__VA_ARGS__) = NULL -#include "llappviewerlinux_api_dbus_syms_raw.inc" -#undef LL_DBUS_SYM - -static bool sSymsGrabbed = false; -static apr_pool_t *sSymDBUSDSOMemoryPool = NULL; -static apr_dso_handle_t *sSymDBUSDSOHandleG = NULL; - -bool grab_dbus_syms(std::string dbus_dso_name) -{ -    if (sSymsGrabbed) -    { -        // already have grabbed good syms -        return TRUE; -    } - -    bool sym_error = false; -    bool rtn = false; -    apr_status_t rv; -    apr_dso_handle_t *sSymDBUSDSOHandle = NULL; - -#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##DBUSSYM, sSymDBUSDSOHandle, #DBUSSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #DBUSSYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #DBUSSYM, (void*)ll##DBUSSYM);}while(0) - -    //attempt to load the shared library -    apr_pool_create(&sSymDBUSDSOMemoryPool, NULL); - -    if ( APR_SUCCESS == (rv = apr_dso_load(&sSymDBUSDSOHandle, -                           dbus_dso_name.c_str(), -                           sSymDBUSDSOMemoryPool) )) -    { -        INFOMSG("Found DSO: %s", dbus_dso_name.c_str()); - -#include "llappviewerlinux_api_dbus_syms_raw.inc" - -        if ( sSymDBUSDSOHandle ) -        { -            sSymDBUSDSOHandleG = sSymDBUSDSOHandle; -            sSymDBUSDSOHandle = NULL; -        } - -        rtn = !sym_error; -    } -    else -    { -        INFOMSG("Couldn't load DSO: %s", dbus_dso_name.c_str()); -        rtn = false; // failure -    } - -    if (sym_error) -    { -        WARNMSG("Failed to find necessary symbols in DBUS-GLIB libraries."); -    } -#undef LL_DBUS_SYM - -    sSymsGrabbed = rtn; -    return rtn; -} - - -void ungrab_dbus_syms() -{ -    // should be safe to call regardless of whether we've -    // actually grabbed syms. - -    if ( sSymDBUSDSOHandleG ) -    { -        apr_dso_unload(sSymDBUSDSOHandleG); -        sSymDBUSDSOHandleG = NULL; -    } - -    if ( sSymDBUSDSOMemoryPool ) -    { -        apr_pool_destroy(sSymDBUSDSOMemoryPool); -        sSymDBUSDSOMemoryPool = NULL; -    } - -    // NULL-out all of the symbols we'd grabbed -#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{ll##DBUSSYM = NULL;}while(0) -#include "llappviewerlinux_api_dbus_syms_raw.inc" -#undef LL_DBUS_SYM - -    sSymsGrabbed = false; -} - -#endif // LL_DBUS_ENABLED diff --git a/indra/newview/llappviewerlinux_api_dbus.h b/indra/newview/llappviewerlinux_api_dbus.h deleted file mode 100644 index 2f4492bd7a..0000000000 --- a/indra/newview/llappviewerlinux_api_dbus.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file llappviewerlinux_api_dbus.h - * @brief DBus-glib symbol handling - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#if LL_DBUS_ENABLED - -extern "C" { -#include <dbus/dbus-glib.h> -} - -#define DBUSGLIB_DYLIB_DEFAULT_NAME "libdbus-glib-1.so.2" - -bool grab_dbus_syms(std::string dbus_dso_name); -void ungrab_dbus_syms(); - -#define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) extern RTN (*ll##DBUSSYM)(__VA_ARGS__) -#include "llappviewerlinux_api_dbus_syms_raw.inc" -#undef LL_DBUS_SYM - -#endif // LL_DBUS_ENABLED diff --git a/indra/newview/llappviewerlinux_api_dbus_syms_raw.inc b/indra/newview/llappviewerlinux_api_dbus_syms_raw.inc deleted file mode 100644 index c0548e2fba..0000000000 --- a/indra/newview/llappviewerlinux_api_dbus_syms_raw.inc +++ /dev/null @@ -1,9 +0,0 @@ - -// required symbols to grab -LL_DBUS_SYM(true, dbus_g_bus_get, DBusGConnection*, DBusBusType, GError**); -LL_DBUS_SYM(true, dbus_g_proxy_new_for_name, DBusGProxy*, DBusGConnection*, const char *, const char*, const char*); -LL_DBUS_SYM(true, dbus_g_proxy_call, gboolean, DBusGProxy*, const char*, GError**, GType, ...); -LL_DBUS_SYM(true, dbus_g_object_type_install_info, void, GType, const DBusGObjectInfo*); -LL_DBUS_SYM(true, dbus_g_connection_register_g_object, void, DBusGConnection*, const char*, GObject*); - -// optional symbols to grab diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 4c90a82fcb..a13e4de308 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -400,17 +400,10 @@ void ll_nvapi_init(NvDRSSessionHandle hSession)      }  } -//#define DEBUGGING_SEH_FILTER 1 -#if DEBUGGING_SEH_FILTER -#   define WINMAIN DebuggingWinMain -#else -#   define WINMAIN wWinMain -#endif - -int APIENTRY WINMAIN(HINSTANCE hInstance, -                     HINSTANCE hPrevInstance, -                     PWSTR     pCmdLine, -                     int       nCmdShow) +int APIENTRY wWinMain(HINSTANCE hInstance, +                      HINSTANCE hPrevInstance, +                      PWSTR     pCmdLine, +                      int       nCmdShow)  {      // Call Tracy first thing to have it allocate memory      // https://github.com/wolfpld/tracy/issues/196 @@ -559,27 +552,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,      return 0;  } -#if DEBUGGING_SEH_FILTER -// The compiler doesn't like it when you use __try/__except blocks -// in a method that uses object destructors. Go figure. -// This winmain just calls the real winmain inside __try. -// The __except calls our exception filter function. For debugging purposes. -int APIENTRY wWinMain(HINSTANCE hInstance, -                     HINSTANCE hPrevInstance, -                     PWSTR     lpCmdLine, -                     int       nCmdShow) -{ -    __try -    { -        WINMAIN(hInstance, hPrevInstance, lpCmdLine, nCmdShow); -    } -    __except( viewer_windows_exception_handler( GetExceptionInformation() ) ) -    { -        _tprintf( _T("Exception handled.\n") ); -    } -} -#endif -  void LLAppViewerWin32::disableWinErrorReporting()  {      std::string executable_name = gDirUtilp->getExecutableFilename(); diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp index 832d4c269b..838062795b 100644 --- a/indra/newview/llconversationloglist.cpp +++ b/indra/newview/llconversationloglist.cpp @@ -93,8 +93,9 @@ BOOL LLConversationLogList::handleRightMouseDown(S32 x, S32 y, MASK mask)      LLToggleableMenu* context_menu = mContextMenu.get();      {          context_menu->buildDrawLabels(); -    if (context_menu && size()) -        context_menu->updateParent(LLMenuGL::sMenuContainer); +        if (context_menu && size()) +            context_menu->updateParent(LLMenuGL::sMenuContainer); +          LLMenuGL::showPopup(this, context_menu, x, y);      } diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index bac435ad80..75875551f4 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -41,6 +41,10 @@  # include "llfilepicker.h"  #endif +#ifdef LL_FLTK +  #include "FL/Fl.H" +  #include "FL/Fl_Native_File_Chooser.H" +#endif  //  // Globals  // @@ -193,20 +197,28 @@ LLDirPicker::LLDirPicker() :      mFileName(NULL),      mLocked(false)  { +#ifndef LL_FLTK      mFilePicker = new LLFilePicker(); +#endif      reset();  }  LLDirPicker::~LLDirPicker()  { +#ifndef LL_FLTK      delete mFilePicker; +#endif  }  void LLDirPicker::reset()  { +#ifndef LL_FLTK      if (mFilePicker)          mFilePicker->reset(); +#else +    mDir = ""; +#endif  }  BOOL LLDirPicker::getDir(std::string* filename, bool blocking) @@ -219,33 +231,38 @@ BOOL LLDirPicker::getDir(std::string* filename, bool blocking)          return FALSE;      } -#if !LL_MESA_HEADLESS - -    if (mFilePicker) +#ifdef LL_FLTK +    gViewerWindow->getWindow()->beforeDialog(); +    Fl_Native_File_Chooser flDlg; +    flDlg.title(LLTrans::getString("choose_the_directory").c_str()); +    flDlg.type(Fl_Native_File_Chooser::BROWSE_DIRECTORY ); +    int res = flDlg.show(); +    gViewerWindow->getWindow()->afterDialog(); +    if( res == 0 )      { -        GtkWindow* picker = mFilePicker->buildFilePicker(false, true, -                                 "dirpicker"); - -        if (picker) -        { -           gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("choose_the_directory").c_str()); -           gtk_widget_show_all(GTK_WIDGET(picker)); -           gtk_main(); -           return (!mFilePicker->getFirstFile().empty()); -        } +        char const *pDir = flDlg.filename(0); +        if( pDir ) +            mDir = pDir;      } -#endif // !LL_MESA_HEADLESS - -    return FALSE; +    else if( res == -1 ) +    { +        LL_WARNS() << "FLTK failed: " <<  flDlg.errmsg() << LL_ENDL; +    } +    return !mDir.empty(); +#endif  }  std::string LLDirPicker::getDirName()  { +#ifndef LL_FLTK      if (mFilePicker)      {          return mFilePicker->getFirstFile();      }      return ""; +#else +    return mDir; +#endif  }  #else // not implemented diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h index e76a19dd40..bcc7792c1a 100644 --- a/indra/newview/lldirpicker.h +++ b/indra/newview/lldirpicker.h @@ -80,8 +80,10 @@ private:  #if LL_LINUX || LL_DARWIN      // On Linux we just implement LLDirPicker on top of LLFilePicker +#ifndef LL_FLTK      LLFilePicker *mFilePicker;  #endif +#endif      std::string* mFileName; diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 4c26e6b8af..30b48df362 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -57,12 +57,6 @@  #include "llsculptidsize.h"  #include "llmeshrepository.h" -#if LL_LINUX -// Work-around spurious used before init warning on Vector4a -// -#pragma GCC diagnostic ignored "-Wuninitialized" -#endif -  #define LL_MAX_INDICES_COUNT 1000000  static LLStaticHashedString sTextureIndexIn("texture_index_in"); @@ -839,7 +833,6 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,          //VECTORIZE THIS          LLMatrix4a mat_vert;          mat_vert.loadu(mat_vert_in); -        LLVector4a new_extents[2];          llassert(less_than_max_mag(face.mExtents[0]));          llassert(less_than_max_mag(face.mExtents[1])); diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 9f12648470..f1e2d45bfb 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -40,6 +40,7 @@  #include "llappviewer.h"  #include "llbufferstream.h" +#include "llexception.h"  #include "llnotificationsutil.h"  #include "llviewercontrol.h"  #include "llworld.h" @@ -377,33 +378,6 @@ bool LLFeatureManager::parseFeatureTable(std::string filename)  F32 gpu_benchmark(); -#if LL_WINDOWS - -F32 logExceptionBenchmark() -{ -    // FIXME: gpu_benchmark uses many C++ classes on the stack to control state. -    //  SEH exceptions with our current exception handling options do not call -    //  destructors for these classes, resulting in an undefined state should -    //  this handler be invoked. -    F32 gbps = -1; -    __try -    { -        gbps = gpu_benchmark(); -    } -    __except (msc_exception_filter(GetExceptionCode(), GetExceptionInformation())) -    { -        // HACK - ensure that profiling is disabled -        LLGLSLShader::finishProfile(false); - -        // convert to C++ styled exception -        char integer_string[32]; -        sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); -        throw std::exception(integer_string); -    } -    return gbps; -} -#endif -  bool LLFeatureManager::loadGPUClass()  {      if (!gSavedSettings.getBOOL("SkipBenchmark")) @@ -413,14 +387,12 @@ bool LLFeatureManager::loadGPUClass()          F32 gbps;          try          { -#if LL_WINDOWS -            gbps = logExceptionBenchmark(); -#else -            gbps = gpu_benchmark(); -#endif +            gbps = LL::seh::catcher(gpu_benchmark);          }          catch (const std::exception& e)          { +            // HACK - ensure that profiling is disabled +            LLGLSLShader::finishProfile(false);              gbps = -1.f;              LL_WARNS("RenderInit") << "GPU benchmark failed: " << e.what() << LL_ENDL;          } diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 51b9923684..d2c041249b 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -40,6 +40,11 @@  #include "llwindowsdl.h" // for some X/GTK utils to help with filepickers  #endif // LL_SDL +#ifdef LL_FLTK +  #include "FL/Fl.H" +  #include "FL/Fl_Native_File_Chooser.H" +#endif +  #if LL_LINUX  #include "llhttpconstants.h"    // file picker uses some of thes constants on Linux  #endif @@ -670,6 +675,7 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF              break;          case FFLOAD_HDRI:              allowedv->push_back("exr"); +        case FFLOAD_MODEL:          case FFLOAD_COLLADA:              allowedv->push_back("dae");              break; @@ -1102,488 +1108,228 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter,  #elif LL_LINUX -# if LL_GTK - -// static -void LLFilePicker::add_to_selectedfiles(gpointer data, gpointer user_data) -{ -    // We need to run g_filename_to_utf8 in the user's locale -    std::string saved_locale(setlocale(LC_ALL, NULL)); -    setlocale(LC_ALL, ""); - -    LLFilePicker* picker = (LLFilePicker*) user_data; -    GError *error = NULL; -    gchar* filename_utf8 = g_filename_to_utf8((gchar*)data, -                          -1, NULL, NULL, &error); -    if (error) -    { -        // *FIXME. -        // This condition should really be notified to the user, e.g. -        // through a message box.  Just logging it is inappropriate. - -        // g_filename_display_name is ideal, but >= glib 2.6, so: -        // a hand-rolled hacky makeASCII which disallows control chars -        std::string display_name; -        for (const gchar *str = (const gchar *)data; *str; str++) -        { -            display_name += (char)((*str >= 0x20 && *str <= 0x7E) ? *str : '?'); -        } -        LL_WARNS() << "g_filename_to_utf8 failed on \"" << display_name << "\": " << error->message << LL_ENDL; -    } - -    if (filename_utf8) -    { -        picker->mFiles.push_back(std::string(filename_utf8)); -        LL_DEBUGS() << "ADDED FILE " << filename_utf8 << LL_ENDL; -        g_free(filename_utf8); -    } - -    setlocale(LC_ALL, saved_locale.c_str()); -} - -// static -void LLFilePicker::chooser_responder(GtkWidget *widget, gint response, gpointer user_data) -{ -    LLFilePicker* picker = (LLFilePicker*)user_data; - -    LL_DEBUGS() << "GTK DIALOG RESPONSE " << response << LL_ENDL; - -    if (response == GTK_RESPONSE_ACCEPT) -    { -        GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget)); -        g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data); -        g_slist_foreach(file_list, (GFunc)g_free, NULL); -        g_slist_free (file_list); -    } - -    // let's save the extension of the last added file(considering current filter) -    GtkFileFilter *gfilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(widget)); -    if(gfilter) -    { -        std::string filter = gtk_file_filter_get_name(gfilter); - -        if(filter == LLTrans::getString("png_image_files")) -        { -            picker->mCurrentExtension = ".png"; -        } -        else if(filter == LLTrans::getString("targa_image_files")) -        { -            picker->mCurrentExtension = ".tga"; -        } -    } - -    // set the default path for this usage context. -    const char* cur_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget)); -    if (cur_folder != NULL) -    { -        picker->mContextToPathMap[picker->mCurContextName] = cur_folder; -    } - -    gtk_widget_destroy(widget); -    gtk_main_quit(); -} - - -GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder, std::string context) -{ -#ifndef LL_MESA_HEADLESS -    if (LLWindowSDL::ll_try_gtk_init()) -    { -        GtkWidget *win = NULL; -        GtkFileChooserAction pickertype = -            is_save? -            (is_folder? -             GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER : -             GTK_FILE_CHOOSER_ACTION_SAVE) : -            (is_folder? -             GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : -             GTK_FILE_CHOOSER_ACTION_OPEN); - -        win = gtk_file_chooser_dialog_new(NULL, NULL, -                          pickertype, -                          GTK_STOCK_CANCEL, -                           GTK_RESPONSE_CANCEL, -                          is_folder ? -                          GTK_STOCK_APPLY : -                          (is_save ? -                           GTK_STOCK_SAVE : -                           GTK_STOCK_OPEN), -                           GTK_RESPONSE_ACCEPT, -                          (gchar *)NULL); -        mCurContextName = context; - -        // get the default path for this usage context if it's been -        // seen before. -        std::map<std::string,std::string>::iterator -            this_path = mContextToPathMap.find(context); -        if (this_path != mContextToPathMap.end()) -        { -            gtk_file_chooser_set_current_folder -                (GTK_FILE_CHOOSER(win), -                 this_path->second.c_str()); -        } - -#  if LL_X11 -        // Make GTK tell the window manager to associate this -        // dialog with our non-GTK raw X11 window, which should try -        // to keep it on top etc. -        Window XWindowID = LLWindowSDL::get_SDL_XWindowID(); -        if (None != XWindowID) -        { -            gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin -            GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID); -            gdk_window_set_transient_for(GTK_WIDGET(win)->window, -                             gdkwin); -        } -        else -        { -            LL_WARNS() << "Hmm, couldn't get xwid to use for transient." << LL_ENDL; -        } -#  endif //LL_X11 - -        g_signal_connect (GTK_FILE_CHOOSER(win), -                  "response", -                  G_CALLBACK(LLFilePicker::chooser_responder), -                  this); - -        gtk_window_set_modal(GTK_WINDOW(win), TRUE); - -        /* GTK 2.6: if (is_folder) -            gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win), -            TRUE); */ +#if LL_FLTK -        return GTK_WINDOW(win); -    } -    else -    { -        return NULL; -    } -#else -    return NULL; -#endif //LL_MESA_HEADLESS -} - -static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter, -                         GtkWindow *picker, -                         std::string filtername) -{ -    gtk_file_filter_set_name(gfilter, filtername.c_str()); -    gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), -                    gfilter); -    GtkFileFilter *allfilter = gtk_file_filter_new(); -    gtk_file_filter_add_pattern(allfilter, "*"); -    gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str()); -    gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter); -    gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter); -} - -static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker, -                               std::string pattern, -                               std::string filtername) -{ -    GtkFileFilter *gfilter = gtk_file_filter_new(); -    gtk_file_filter_add_pattern(gfilter, pattern.c_str()); -    add_common_filters_to_gtkchooser(gfilter, picker, filtername); -    return filtername; -} - -static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker, -                            std::string mime, -                            std::string filtername) -{ -    GtkFileFilter *gfilter = gtk_file_filter_new(); -    gtk_file_filter_add_mime_type(gfilter, mime.c_str()); -    add_common_filters_to_gtkchooser(gfilter, picker, filtername); -    return filtername; -} - -static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker) +BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, +                                       const std::string& filename, +                                       void (*callback)(bool, std::string&, void*), +                                       void *userdata)  { -    return add_simple_mime_filter_to_gtkchooser(picker,  "audio/x-wav", -                            LLTrans::getString("sound_files") + " (*.wav)"); +    LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; +    return FALSE;  } -static std::string add_anim_filter_to_gtkchooser(GtkWindow *picker) +BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, +                                       void (*callback)(bool, std::vector<std::string> &, void*), +                                       void *userdata)  { -    GtkFileFilter *gfilter = gtk_file_filter_new(); -    gtk_file_filter_add_pattern(gfilter, "*.bvh"); -    gtk_file_filter_add_pattern(gfilter, "*.anim"); -    std::string filtername = LLTrans::getString("animation_files") + " (*.bvh; *.anim)"; -    add_common_filters_to_gtkchooser(gfilter, picker, filtername); -    return filtername; +    LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; +    return FALSE;  } -static std::string add_xml_filter_to_gtkchooser(GtkWindow *picker) +BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, +                                                void (*callback)(bool, std::vector<std::string> &, void*), +                                                void *userdata )  { -    return add_simple_pattern_filter_to_gtkchooser(picker,  "*.xml", -                                                   LLTrans::getString("xml_files") + " (*.xml)"); +    LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; +    return FALSE;  } -static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker) -{ -    return add_simple_pattern_filter_to_gtkchooser(picker,  "*.dae", -                               LLTrans::getString("scene_files") + " (*.dae)"); -} -static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) -{ -    GtkFileFilter *gfilter = gtk_file_filter_new(); -    gtk_file_filter_add_pattern(gfilter, "*.tga"); -    gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str()); -    gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str()); -    gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str()); -    std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; -    add_common_filters_to_gtkchooser(gfilter, picker, filtername); -    return filtername; -} -static std::string add_script_filter_to_gtkchooser(GtkWindow *picker) +BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking )  { -    return add_simple_mime_filter_to_gtkchooser(picker,  HTTP_CONTENT_TEXT_PLAIN, -                            LLTrans::getString("script_files") + " (*.lsl)"); +    return openFileDialog( filter, blocking, eSaveFile );  } -static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker) +BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking )  { -    return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN, -                            LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)"); +    return openFileDialog( filter, blocking, eOpenFile );  } -static std::string add_save_texture_filter_to_gtkchooser(GtkWindow *picker) +BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking)  { -    GtkFileFilter *gfilter_tga = gtk_file_filter_new(); -    GtkFileFilter *gfilter_png = gtk_file_filter_new(); - -    gtk_file_filter_add_pattern(gfilter_tga, "*.tga"); -    gtk_file_filter_add_mime_type(gfilter_png, "image/png"); -    std::string caption = LLTrans::getString("save_texture_image_files") + " (*.tga; *.png)"; -    gtk_file_filter_set_name(gfilter_tga, LLTrans::getString("targa_image_files").c_str()); -    gtk_file_filter_set_name(gfilter_png, LLTrans::getString("png_image_files").c_str()); - -    gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), -                    gfilter_png); -    gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), -                    gfilter_tga); -    return caption; +    return openFileDialog( filter, blocking, eOpenMultiple );  } -BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking ) +bool LLFilePicker::openFileDialog( int32_t filter, bool blocking, EType aType )  { -    BOOL rtn = FALSE; - -    // if local file browsing is turned off, return without opening dialog      if ( check_local_file_access_enabled() == false ) -    { -        return FALSE; -    } - +        return false;      gViewerWindow->getWindow()->beforeDialog(); -      reset(); - -    GtkWindow* picker = buildFilePicker(true, false, "savefile"); - -    if (picker) -    { -        std::string suggest_name = "untitled"; -        std::string suggest_ext = ""; -        std::string caption = LLTrans::getString("save_file_verb") + " "; -        switch (filter) +    Fl_Native_File_Chooser::Type flType = Fl_Native_File_Chooser::BROWSE_FILE; +    if( aType == eOpenMultiple ) +        flType = Fl_Native_File_Chooser::BROWSE_MULTI_FILE; +    else if( aType == eSaveFile ) +        flType = Fl_Native_File_Chooser::BROWSE_SAVE_FILE; +    Fl_Native_File_Chooser flDlg; +    std::string file_dialog_title; +    std::string file_dialog_filter; +    if (aType == EType::eSaveFile) +    { +        std::string file_type("all_files"); +        switch ((ESaveFilter) filter)          { -        case FFSAVE_WAV: -            caption += add_wav_filter_to_gtkchooser(picker); -            suggest_ext = ".wav"; -            break; -        case FFSAVE_TGA: -            caption += add_simple_pattern_filter_to_gtkchooser -                (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)"); -            suggest_ext = ".tga"; -            break; -        case FFSAVE_BMP: -            caption += add_simple_mime_filter_to_gtkchooser -                (picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)"); -            suggest_ext = ".bmp"; -            break; -        case FFSAVE_PNG: -            caption += add_simple_mime_filter_to_gtkchooser -                (picker, "image/png", LLTrans::getString("png_image_files") + " (*.png)"); -            suggest_ext = ".png"; -            break; -        case FFSAVE_TGAPNG: -            caption += add_save_texture_filter_to_gtkchooser(picker); -            suggest_ext = ".png"; -            break; -        case FFSAVE_AVI: -            caption += add_simple_mime_filter_to_gtkchooser -                (picker, "video/x-msvideo", -                 LLTrans::getString("avi_movie_file") + " (*.avi)"); -            suggest_ext = ".avi"; -            break; -        case FFSAVE_ANIM: -            caption += add_simple_pattern_filter_to_gtkchooser -                (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)"); -            suggest_ext = ".xaf"; -            break; -        case FFSAVE_XML: -            caption += add_simple_pattern_filter_to_gtkchooser -                (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)"); -            suggest_ext = ".xml"; -            break; -        case FFSAVE_RAW: -            caption += add_simple_pattern_filter_to_gtkchooser -                (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)"); -            suggest_ext = ".raw"; -            break; -        case FFSAVE_J2C: -            // *TODO: Should this be 'image/j2c' ? -            caption += add_simple_mime_filter_to_gtkchooser -                (picker, "images/jp2", -                 LLTrans::getString("compressed_image_files") + " (*.j2c)"); -            suggest_ext = ".j2c"; -            break; -        case FFSAVE_SCRIPT: -            caption += add_script_filter_to_gtkchooser(picker); -            suggest_ext = ".lsl"; -            break; -        default:; -            break; +            case FFSAVE_ALL: +                break; +            case FFSAVE_TGA: +                file_type = "targa_image_files"; +                file_dialog_filter = "*.tga"; +                break; +            case FFSAVE_BMP: +                file_type = "bitmap_image_files"; +                file_dialog_filter = "*.bmp"; +                break; +            case FFSAVE_AVI: +                file_type = "avi_movie_file"; +                file_dialog_filter = "*.avi"; +                break; +            case FFSAVE_ANIM: +                file_type = "xaf_animation_file"; +                file_dialog_filter = "*.xaf"; +                break; +            case FFSAVE_XML: +                file_type = "xml_file"; +                file_dialog_filter = "*.xml"; +                break; +            case FFSAVE_COLLADA: +                file_type = "collada_files"; +                file_dialog_filter = "*.dae"; +                break; +            case FFSAVE_RAW: +                file_type = "raw_file"; +                file_dialog_filter = "*.raw"; +                break; +            case FFSAVE_J2C: +                file_type = "compressed_image_files"; +                file_dialog_filter = "*.j2c"; +                break; +            case FFSAVE_PNG: +                file_type = "png_image_files"; +                file_dialog_filter = "*.png"; +                break; +            case FFSAVE_JPEG: +                file_type = "jpeg_image_files"; +                file_dialog_filter = "*.{jpg,jpeg}"; +                break; +            case FFSAVE_SCRIPT: +                file_type = "script_files"; +                file_dialog_filter = "*.lsl"; +                break; +            case FFSAVE_TGAPNG: +                file_type = "save_texture_image_files"; +                file_dialog_filter = "*.{tga,png}"; +                break; +            case FFSAVE_WAV: +                file_type = "sound_files"; +                file_dialog_filter = "*.wav"; +                break; +            case FFSAVE_GLTF: +                file_type = "gltf_asset_file"; +                file_dialog_filter = "*.{gltf,glb}"; +                break;          } - -        gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - -        if (filename.empty()) +        file_dialog_title = LLTrans::getString("save_file_verb") + " " + LLTrans::getString(file_type); +        file_dialog_filter = LLTrans::getString(file_type) + " \t" + file_dialog_filter; +    } +    else +    { +        std::string file_type("all_files"); +        switch ((ELoadFilter) filter)          { -            suggest_name += suggest_ext; +            case FFLOAD_ALL: +                break; +            case FFLOAD_WAV: +                file_type = "sound_files"; +                file_dialog_filter = "*.wav"; +                break; +            case FFLOAD_IMAGE: +                file_type = "image_files"; +                file_dialog_filter = "*.{tga,bmp,jpg,jpeg,png}"; +                break; +            case FFLOAD_ANIM: +                file_type = "animation_files"; +                file_dialog_filter = "*.{bvh,anim}"; +                break; +            case FFLOAD_XML: +                file_type = "xml_file"; +                file_dialog_filter = "*.xml"; +                break; +            case FFLOAD_SLOBJECT: +                file_type = "xml_file"; +                file_dialog_filter = "*.slobject"; +                break; +            case FFLOAD_RAW: +                file_type = "raw_file"; +                file_dialog_filter = "*.raw"; +                break; +            case FFLOAD_MODEL: +            case FFLOAD_COLLADA: +                file_type = "collada_files"; +                file_dialog_filter = "*.dae"; +                break; +            case FFLOAD_SCRIPT: +                file_type = "script_files"; +                file_dialog_filter = "*.lsl"; +                break; +            case FFLOAD_DICTIONARY: +                file_type = "dictionary_files"; +                file_dialog_filter = "*.{dic,xcu}"; +                break; +            case FFLOAD_DIRECTORY: +                file_type = "choose_the_directory"; +                break; +            case FFLOAD_EXE: +                file_type = "executable_files"; +                break; +            case FFLOAD_GLTF: +            case FFLOAD_MATERIAL: +                file_type = "gltf_asset_file"; +                file_dialog_filter = "*.{gltg,glb}"; +                break; +            case FFLOAD_MATERIAL_TEXTURE: +                file_dialog_filter = "*.{gltf,glb,tga,bmp,jpg,jpeg,png}"; +                file_type = "image_files"; -            gtk_file_chooser_set_current_name -                (GTK_FILE_CHOOSER(picker), -                 suggest_name.c_str());          } -        else +        if (aType == EType::eOpenMultiple)          { -            gtk_file_chooser_set_current_name -                (GTK_FILE_CHOOSER(picker), filename.c_str()); +            file_dialog_title = LLTrans::getString("load_files");          } - -        gtk_widget_show_all(GTK_WIDGET(picker)); - -        gtk_main(); - -        rtn = (getFileCount() == 1); - -        if(rtn && filter == FFSAVE_TGAPNG) +        else          { -            std::string selected_file = mFiles.back(); -            mFiles.pop_back(); -            mFiles.push_back(selected_file + mCurrentExtension); +            file_dialog_title = LLTrans::getString("load_file_verb") + " " + LLTrans::getString(file_type); +            file_dialog_filter = LLTrans::getString(file_type) + " \t" + file_dialog_filter;          }      } - -    gViewerWindow->getWindow()->afterDialog(); - -    return rtn; -} - -BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) -{ -    BOOL rtn = FALSE; - -    // if local file browsing is turned off, return without opening dialog -    if ( check_local_file_access_enabled() == false ) +    flDlg.title(file_dialog_title.c_str()); +    flDlg.type(flType); +    if (!file_dialog_filter.empty())      { -        return FALSE; +        flDlg.filter(file_dialog_filter.c_str());      } - -    gViewerWindow->getWindow()->beforeDialog(); - -    reset(); - -    GtkWindow* picker = buildFilePicker(false, false, "openfile"); - -    if (picker) +    int res = flDlg.show(); +    gViewerWindow->getWindow()->afterDialog(); +    if( res == 0 )      { -        std::string caption = LLTrans::getString("load_file_verb") + " "; -        std::string filtername = ""; -        switch (filter) +        int32_t count = flDlg.count(); +        if( count < 0 ) +            count = 0; +        for( int32_t i = 0; i < count; ++i )          { -        case FFLOAD_WAV: -            filtername = add_wav_filter_to_gtkchooser(picker); -            break; -        case FFLOAD_ANIM: -            filtername = add_anim_filter_to_gtkchooser(picker); -            break; -        case FFLOAD_XML: -            filtername = add_xml_filter_to_gtkchooser(picker); -            break; -        case FFLOAD_GLTF: -            filtername = dead_code_should_blow_up_here(picker); -            break; -        case FFLOAD_COLLADA: -            filtername = add_collada_filter_to_gtkchooser(picker); -            break; -        case FFLOAD_IMAGE: -            filtername = add_imageload_filter_to_gtkchooser(picker); -            break; -        case FFLOAD_SCRIPT: -            filtername = add_script_filter_to_gtkchooser(picker); -            break; -        case FFLOAD_DICTIONARY: -            filtername = add_dictionary_filter_to_gtkchooser(picker); -            break; -        default:; -            break; +            char const *pFile = flDlg.filename(i); +            if( pFile && strlen(pFile) > 0 ) +                mFiles.push_back( pFile  );          } - -        caption += filtername; - -        gtk_window_set_title(GTK_WINDOW(picker), caption.c_str()); - -        gtk_widget_show_all(GTK_WIDGET(picker)); -        gtk_main(); - -        rtn = (getFileCount() == 1);      } - -    gViewerWindow->getWindow()->afterDialog(); - -    return rtn; -} - -BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) -{ -    BOOL rtn = FALSE; - -    // if local file browsing is turned off, return without opening dialog -    if ( check_local_file_access_enabled() == false ) +    else if( res == -1 )      { -        return FALSE; +        LL_WARNS() << "FLTK failed: " <<  flDlg.errmsg() << LL_ENDL;      } - -    gViewerWindow->getWindow()->beforeDialog(); - -    reset(); - -    GtkWindow* picker = buildFilePicker(false, false, "openfile"); - -    if (picker) -    { -        gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker), -                              TRUE); - -        gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str()); - -        gtk_widget_show_all(GTK_WIDGET(picker)); -        gtk_main(); -        rtn = !mFiles.empty(); -    } - -    gViewerWindow->getWindow()->afterDialog(); - -    return rtn; +    return mFiles.empty()?FALSE:TRUE;  } - -# else // LL_GTK - +#else  // Hacky stubs designed to facilitate fake getSaveFile and getOpenFile with  // static results, when we don't have a real filepicker. @@ -1671,7 +1417,7 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter,      return FALSE;  } -#endif // LL_GTK +#endif // LL_FLTK  #else // not implemented diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 994e7458d3..faffee7aba 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -54,19 +54,8 @@  #include <commdlg.h>  #endif -extern "C" { -// mostly for Linux, possible on others -#if LL_GTK -# include "gtk/gtk.h" -#endif // LL_GTK -} -  class LLFilePicker  { -#ifdef LL_GTK -    friend class LLDirPicker; -    friend void chooser_responder(GtkWidget *, gint, gpointer); -#endif // LL_GTK  public:      // calling this before main() is undefined      static LLFilePicker& instance( void ) { return sInstance; } @@ -184,14 +173,12 @@ private:                                   void *userdata);  #endif -#if LL_GTK -    static void add_to_selectedfiles(gpointer data, gpointer user_data); -    static void chooser_responder(GtkWidget *widget, gint response, gpointer user_data); -    // we remember the last path that was accessed for a particular usage -    std::map <std::string, std::string> mContextToPathMap; -    std::string mCurContextName; -    // we also remember the extension of the last added file. -    std::string mCurrentExtension; +#if LL_FLTK +    enum EType +    { +     eSaveFile, eOpenFile, eOpenMultiple +    }; +    bool openFileDialog( int32_t filter, bool blocking, EType aType );  #endif      std::vector<std::string> mFiles; @@ -200,12 +187,6 @@ private:      static LLFilePicker sInstance; -protected: -#if LL_GTK -        GtkWindow* buildFilePicker(bool is_save, bool is_folder, -                   std::string context = "generic"); -#endif -  public:      // don't call these directly please.      LLFilePicker(); diff --git a/indra/newview/llfloatercreatelandmark.cpp b/indra/newview/llfloatercreatelandmark.cpp index d2ca0aaf69..f810f3afe7 100644 --- a/indra/newview/llfloatercreatelandmark.cpp +++ b/indra/newview/llfloatercreatelandmark.cpp @@ -31,6 +31,7 @@  #include "llagent.h"  #include "llagentui.h"  #include "llcombobox.h" +#include "llfloaterreg.h"  #include "llinventoryfunctions.h"  #include "llinventoryobserver.h"  #include "lllandmarkactions.h" @@ -286,8 +287,7 @@ void LLFloaterCreateLandmark::onCreateFolderClicked()              std::string folder_name = resp["message"].asString();              if (!folder_name.empty())              { -                inventory_func_type func = boost::bind(&LLFloaterCreateLandmark::folderCreatedCallback, this, _1); -                gInventory.createNewCategory(mLandmarksID, LLFolderType::FT_NONE, folder_name, func); +                gInventory.createNewCategory(mLandmarksID, LLFolderType::FT_NONE, folder_name, folderCreatedCallback);                  gInventory.notifyObservers();              }          } @@ -296,7 +296,11 @@ void LLFloaterCreateLandmark::onCreateFolderClicked()  void LLFloaterCreateLandmark::folderCreatedCallback(LLUUID folder_id)  { -    populateFoldersList(folder_id); +    LLFloaterCreateLandmark* floater = LLFloaterReg::findTypedInstance<LLFloaterCreateLandmark>("add_landmark"); +    if (floater && !floater->isDead()) +    { +        floater->populateFoldersList(folder_id); +    }  }  void LLFloaterCreateLandmark::onSaveClicked() @@ -389,6 +393,7 @@ void LLFloaterCreateLandmark::setItem(const uuid_set_t& items)              {                  mItem = item;                  mAssetID = mItem->getAssetUUID(); +                mParentID = mItem->getParentUUID();                  setVisibleAndFrontmost(true);                  break;              } @@ -418,8 +423,7 @@ void LLFloaterCreateLandmark::updateItem(const uuid_set_t& items, U32 mask)                  closeFloater();              } -            LLUUID folder_id = mFolderCombo->getValue().asUUID(); -            if (folder_id != mItem->getParentUUID()) +            if (mParentID != mItem->getParentUUID())              {                  // user moved landmark in inventory,                  // assume that we are done all other changes should already be commited diff --git a/indra/newview/llfloatercreatelandmark.h b/indra/newview/llfloatercreatelandmark.h index dc121677a4..89e0a0bb6a 100644 --- a/indra/newview/llfloatercreatelandmark.h +++ b/indra/newview/llfloatercreatelandmark.h @@ -62,13 +62,14 @@ private:      void onSaveClicked();      void onCancelClicked(); -    void folderCreatedCallback(LLUUID folder_id); +    static void folderCreatedCallback(LLUUID folder_id);      LLComboBox*     mFolderCombo;      LLLineEditor*   mLandmarkTitleEditor;      LLTextEditor*   mNotesEditor;      LLUUID          mLandmarksID;      LLUUID          mAssetID; +    LLUUID          mParentID;      LLLandmarksInventoryObserver*   mInventoryObserver;      LLPointer<LLInventoryItem>      mItem; diff --git a/indra/newview/llfloateremojipicker.cpp b/indra/newview/llfloateremojipicker.cpp index 78b94d1b0c..c9d14c45f8 100644 --- a/indra/newview/llfloateremojipicker.cpp +++ b/indra/newview/llfloateremojipicker.cpp @@ -57,8 +57,7 @@ static const S32 USED_EMOJIS_IMAGE_INDEX = 0x23F2;  // https://www.compart.com/en/unicode/U+1F6D1  static const S32 EMPTY_LIST_IMAGE_INDEX = 0x1F6D1;  // The following categories should follow the required alphabetic order -static const std::string RECENTLY_USED_CATEGORY = "1 recently used"; -static const std::string FREQUENTLY_USED_CATEGORY = "2 frequently used"; +static const std::string FREQUENTLY_USED_CATEGORY = "frequently used";  // Floater state related variables  static std::list<llwchar> sRecentlyUsed; @@ -436,6 +435,7 @@ void LLFloaterEmojiPicker::fillGroups()      LLButton::Params params;      params.font = LLFontGL::getFontEmojiLarge(); +    params.name = "all_categories";      LLRect rect;      rect.mTop = mGroups->getRect().getHeight(); @@ -444,11 +444,10 @@ void LLFloaterEmojiPicker::fillGroups()      // Create button for "All categories"      createGroupButton(params, rect, ALL_EMOJIS_IMAGE_INDEX); -    // Create group and button for "Recently used" and/or "Frequently used" -    if (!sRecentlyUsed.empty() || !sFrequentlyUsed.empty()) +    // Create group and button for "Frequently used" +    if (!sFrequentlyUsed.empty())      {          std::map<std::string, std::vector<LLEmojiSearchResult>> cats; -        fillCategoryRecentlyUsed(cats);          fillCategoryFrequentlyUsed(cats);          if (!cats.empty()) @@ -479,40 +478,6 @@ void LLFloaterEmojiPicker::fillGroups()      resizeGroupButtons();  } -void LLFloaterEmojiPicker::fillCategoryRecentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats) -{ -    if (sRecentlyUsed.empty()) -        return; - -    std::vector<LLEmojiSearchResult> emojis; - -    // In case of empty mFilterPattern we'd use sRecentlyUsed directly -    if (!mFilterPattern.empty()) -    { -        // List all emojis in "Recently used" -        const LLEmojiDictionary::emoji2descr_map_t& emoji2descr = LLEmojiDictionary::instance().getEmoji2Descr(); -        std::size_t begin, end; -        for (llwchar emoji : sRecentlyUsed) -        { -            auto e2d = emoji2descr.find(emoji); -            if (e2d != emoji2descr.end() && !e2d->second->ShortCodes.empty()) -            { -                for (const std::string& shortcode : e2d->second->ShortCodes) -                { -                    if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern)) -                    { -                        emojis.emplace_back(emoji, shortcode, begin, end); -                    } -                } -            } -        } -        if (emojis.empty()) -            return; -    } - -    cats.emplace(std::make_pair(RECENTLY_USED_CATEGORY, emojis)); -} -  void LLFloaterEmojiPicker::fillCategoryFrequentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats)  {      if (sFrequentlyUsed.empty()) @@ -533,13 +498,13 @@ void LLFloaterEmojiPicker::fillCategoryFrequentlyUsed(std::map<std::string, std:              {                  for (const std::string& shortcode : e2d->second->ShortCodes)                  { -                    if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern)) -                    { -                        emojis.emplace_back(emoji.first, shortcode, begin, end); -                    } +                if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern)) +                { +                    emojis.emplace_back(emoji.first, shortcode, begin, end);                  }              }          } +        }          if (emojis.empty())              return;      } @@ -571,13 +536,13 @@ void LLFloaterEmojiPicker::fillGroupEmojis(std::map<std::string, std::vector<LLE                  {                      for (const std::string& shortcode : descr->ShortCodes)                      { -                        if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern)) -                        { -                            emojis.emplace_back(descr->Character, shortcode, begin, end); -                        } +                    if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern)) +                    { +                        emojis.emplace_back(descr->Character, shortcode, begin, end);                      }                  }              } +            }              if (emojis.empty())                  continue;          } @@ -754,7 +719,6 @@ void LLFloaterEmojiPicker::fillEmojisCategory(const std::vector<LLEmojiSearchRes  {      // Place the category title      std::string title = -        category == RECENTLY_USED_CATEGORY ? getString("title_for_recently_used") :          category == FREQUENTLY_USED_CATEGORY ? getString("title_for_frequently_used") :          isupper(category.front()) ? category : LLStringUtil::capitalize(category);      LLEmojiGridDivider* div = new LLEmojiGridDivider(row_panel_params, title); @@ -767,21 +731,7 @@ void LLFloaterEmojiPicker::fillEmojisCategory(const std::vector<LLEmojiSearchRes      {          const LLEmojiDictionary::emoji2descr_map_t& emoji2descr = LLEmojiDictionary::instance().getEmoji2Descr();          LLEmojiSearchResult emoji { 0, "", 0, 0 }; -        if (category == RECENTLY_USED_CATEGORY) -        { -            for (llwchar code : sRecentlyUsed) -            { -                const LLEmojiDictionary::emoji2descr_map_t::const_iterator& e2d = emoji2descr.find(code); -                if (e2d != emoji2descr.end() && !e2d->second->ShortCodes.empty()) -                { -                    emoji.Character = code; -                    emoji.String = e2d->second->ShortCodes.front(); -                    createEmojiIcon(emoji, category, row_panel_params, row_list_params, icon_params, -                        icon_rect, max_icons, bg, row, icon_index); -                } -            } -        } -        else if (category == FREQUENTLY_USED_CATEGORY) +        if (category == FREQUENTLY_USED_CATEGORY)          {              for (const auto& code : sFrequentlyUsed)              { diff --git a/indra/newview/llfloateremojipicker.h b/indra/newview/llfloateremojipicker.h index 05b4826e37..bc64cb1f35 100644 --- a/indra/newview/llfloateremojipicker.h +++ b/indra/newview/llfloateremojipicker.h @@ -60,7 +60,6 @@ public:  private:      void initialize();      void fillGroups(); -    void fillCategoryRecentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats);      void fillCategoryFrequentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats);      void fillGroupEmojis(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats, U32 index);      void createGroupButton(LLButton::Params& params, const LLRect& rect, llwchar emoji); diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index 97ae97dafc..ba655ab760 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -115,12 +115,12 @@ BOOL LLFloaterPerformance::postBuild()      mHUDList = mHUDsPanel->getChild<LLNameListCtrl>("hud_list");      mHUDList->setNameListType(LLNameListCtrl::SPECIAL);      mHUDList->setHoverIconName("StopReload_Off"); -    mHUDList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachItem, this, _1)); +    mHUDList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachObject, this, _1));      mObjectList = mComplexityPanel->getChild<LLNameListCtrl>("obj_list");      mObjectList->setNameListType(LLNameListCtrl::SPECIAL);      mObjectList->setHoverIconName("StopReload_Off"); -    mObjectList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachItem, this, _1)); +    mObjectList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachObject, this, _1));      mSettingsPanel->getChild<LLButton>("advanced_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickAdvanced, this));      mSettingsPanel->getChild<LLButton>("defaults_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickDefaults, this)); @@ -524,9 +524,13 @@ void LLFloaterPerformance::setFPSText()      getChild<LLTextBox>("fps_lbl")->setValue(fps_text);  } -void LLFloaterPerformance::detachItem(const LLUUID& item_id) +void LLFloaterPerformance::detachObject(const LLUUID& obj_id)  { -    LLAppearanceMgr::instance().removeItemFromAvatar(item_id); +    LLViewerObject* obj = gObjectList.findObject(obj_id); +    if (obj) +    { +        LLAppearanceMgr::instance().removeItemFromAvatar(obj->getAttachmentItemID()); +    }  }  void LLFloaterPerformance::onClickAdvanced() diff --git a/indra/newview/llfloaterperformance.h b/indra/newview/llfloaterperformance.h index d2f45a9e2e..03fa9e8184 100644 --- a/indra/newview/llfloaterperformance.h +++ b/indra/newview/llfloaterperformance.h @@ -46,7 +46,7 @@ public:      void hidePanels();      void showAutoadjustmentsPanel(); -    void detachItem(const LLUUID& item_id); +    void detachObject(const LLUUID& obj_id);      void onAvatarListRightClick(LLUICtrl* ctrl, S32 x, S32 y); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index d731f1c592..23ddd087eb 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -329,6 +329,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)      mCommitCallbackRegistrar.add("Pref.AutoAdjustments",         boost::bind(&LLFloaterPreference::onClickAutoAdjustments, this));      mCommitCallbackRegistrar.add("Pref.HardwareDefaults",       boost::bind(&LLFloaterPreference::setHardwareDefaults, this));      mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable",  boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this)); +    mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", boost::bind(&LLFloaterPreference::updateMaxNonImpostors, this));      mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity",    boost::bind(&LLFloaterPreference::updateMaxComplexity, this));      mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate",     boost::bind(&LLFloaterPreference::onRenderOptionEnable, this));      mCommitCallbackRegistrar.add("Pref.WindowedMod",            boost::bind(&LLFloaterPreference::onCommitWindowedMode, this)); @@ -360,6 +361,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)      LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this );      mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPreference::updateComplexityText, this)); +    mImpostorsChangedSignal = gSavedSettings.getControl("RenderAvatarMaxNonImpostors")->getSignal()->connect(boost::bind(&LLFloaterPreference::updateIndirectMaxNonImpostors, this, _2));      mCommitCallbackRegistrar.add("Pref.ClearLog",               boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance()));      mCommitCallbackRegistrar.add("Pref.DeleteTranscripts",      boost::bind(&LLFloaterPreference::onDeleteTranscripts, this)); @@ -527,6 +529,7 @@ LLFloaterPreference::~LLFloaterPreference()  {      LLConversationLog::instance().removeObserver(this);      mComplexityChangedSignal.disconnect(); +    mImpostorsChangedSignal.disconnect();  }  void LLFloaterPreference::draw() @@ -1280,6 +1283,9 @@ void LLAvatarComplexityControls::setIndirectMaxArc()  void LLFloaterPreference::refresh()  {      LLPanel::refresh(); +    setMaxNonImpostorsText( +        gSavedSettings.getU32("RenderAvatarMaxNonImpostors"), +        getChild<LLTextBox>("IndirectMaxNonImpostorsText", true));      LLAvatarComplexityControls::setText(          gSavedSettings.getU32("RenderAvatarMaxComplexity"),          getChild<LLTextBox>("IndirectMaxComplexityText", true)); @@ -1558,6 +1564,44 @@ void LLAvatarComplexityControls::setRenderTimeText(F32 value, LLTextBox* text_bo      }  } +void LLFloaterPreference::updateMaxNonImpostors() +{ +    // Called when the IndirectMaxNonImpostors control changes +    // Responsible for fixing the slider label (IndirectMaxNonImpostorsText) and setting RenderAvatarMaxNonImpostors +    LLSliderCtrl* ctrl = getChild<LLSliderCtrl>("IndirectMaxNonImpostors", true); +    U32 value = ctrl->getValue().asInteger(); + +    if (0 == value || LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER <= value) +    { +        value = 0; +    } +    gSavedSettings.setU32("RenderAvatarMaxNonImpostors", value); +    LLVOAvatar::updateImpostorRendering(value); // make it effective immediately +    setMaxNonImpostorsText(value, getChild<LLTextBox>("IndirectMaxNonImpostorsText")); +} + +void LLFloaterPreference::updateIndirectMaxNonImpostors(const LLSD& newvalue) +{ +    U32 value = newvalue.asInteger(); +    if ((value != 0) && (value != gSavedSettings.getU32("IndirectMaxNonImpostors"))) +    { +        gSavedSettings.setU32("IndirectMaxNonImpostors", value); +    } +    setMaxNonImpostorsText(value, getChild<LLTextBox>("IndirectMaxNonImpostorsText")); +} + +void LLFloaterPreference::setMaxNonImpostorsText(U32 value, LLTextBox* text_box) +{ +    if (0 == value) +    { +        text_box->setText(LLTrans::getString("no_limit")); +    } +    else +    { +        text_box->setText(llformat("%d", value)); +    } +} +  void LLFloaterPreference::updateMaxComplexity()  {      // Called when the IndirectMaxComplexity control changes diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index fe684cf88c..bb7892362c 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -210,6 +210,9 @@ private:      void onDeleteTranscripts();      void onDeleteTranscriptsResponse(const LLSD& notification, const LLSD& response);      void updateDeleteTranscriptsButton(); +    void updateMaxNonImpostors(); +    void updateIndirectMaxNonImpostors(const LLSD& newvalue); +    void setMaxNonImpostorsText(U32 value, LLTextBox* text_box);      void updateMaxComplexity();      void updateComplexityText();      static bool loadFromFilename(const std::string& filename, std::map<std::string, std::string> &label_map); @@ -233,6 +236,7 @@ private:      std::unique_ptr< ll::prefs::SearchData > mSearchData;      bool mSearchDataDirty; +    boost::signals2::connection mImpostorsChangedSignal;      boost::signals2::connection mComplexityChangedSignal;      void onUpdateFilterTerm( bool force = false ); diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp index 709963b924..ae1c5cf6c9 100644 --- a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp @@ -52,13 +52,14 @@ LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const L      mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnCancel, this, _2));      mCommitCallbackRegistrar.add("Pref.OK",     boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnOK, this, _2)); -    gSavedSettings.getControl("RenderAvatarMaxNonImpostors")->getSignal()->connect(boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateIndirectMaxNonImpostors, this, _2)); +    mImpostorsChangedSignal = gSavedSettings.getControl("RenderAvatarMaxNonImpostors")->getSignal()->connect(boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateIndirectMaxNonImpostors, this, _2));  }  LLFloaterPreferenceGraphicsAdvanced::~LLFloaterPreferenceGraphicsAdvanced()  {      mComplexityChangedSignal.disconnect();      mLODFactorChangedSignal.disconnect(); +    mImpostorsChangedSignal.disconnect();  }  BOOL LLFloaterPreferenceGraphicsAdvanced::postBuild() @@ -221,8 +222,8 @@ void LLFloaterPreferenceGraphicsAdvanced::updateIndirectMaxNonImpostors(const LL      if ((value != 0) && (value != gSavedSettings.getU32("IndirectMaxNonImpostors")))      {          gSavedSettings.setU32("IndirectMaxNonImpostors", value); -        setMaxNonImpostorsText(value, getChild<LLTextBox>("IndirectMaxNonImpostorsText"));      } +    setMaxNonImpostorsText(value, getChild<LLTextBox>("IndirectMaxNonImpostorsText"));  }  void LLFloaterPreferenceGraphicsAdvanced::setMaxNonImpostorsText(U32 value, LLTextBox* text_box) diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.h b/indra/newview/llfloaterpreferencesgraphicsadvanced.h index 114a79a936..bab51b712b 100644 --- a/indra/newview/llfloaterpreferencesgraphicsadvanced.h +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.h @@ -60,6 +60,7 @@ protected:      void        onBtnOK(const LLSD& userdata);      void        onBtnCancel(const LLSD& userdata); +    boost::signals2::connection mImpostorsChangedSignal;      boost::signals2::connection mComplexityChangedSignal;      boost::signals2::connection mLODFactorChangedSignal;  }; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 8d2efc79db..0a66b7d037 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -4159,7 +4159,6 @@ void LLPanelRegionEnvironment::onChkAllowOverride(bool value)      mAllowOverrideRestore = mAllowOverride;      mAllowOverride = value; -      std::string notification("EstateParcelEnvironmentOverride");      if (LLPanelEstateInfo::isLindenEstate())          notification = "ChangeLindenEstate"; diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp index 44d33eec93..de82952b9d 100644 --- a/indra/newview/llhttpretrypolicy.cpp +++ b/indra/newview/llhttpretrypolicy.cpp @@ -91,14 +91,14 @@ void LLAdaptiveRetryPolicy::onSuccess()  void LLAdaptiveRetryPolicy::onFailure(S32 status, const LLSD& headers)  { -    F32 retry_header_time; +    F32 retry_header_time{};      bool has_retry_header_time = getRetryAfter(headers,retry_header_time);      onFailureCommon(status, has_retry_header_time, retry_header_time);  }  void LLAdaptiveRetryPolicy::onFailure(const LLCore::HttpResponse *response)  { -    F32 retry_header_time; +    F32 retry_header_time{};      const LLCore::HttpHeaders::ptr_t headers = response->getHeaders();      bool has_retry_header_time = getRetryAfter(headers,retry_header_time);      onFailureCommon(response->getStatus().getType(), has_retry_header_time, retry_header_time); @@ -184,4 +184,3 @@ bool LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(const std::string& retry_a      return true;  } - diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index fbb4ac8801..bbd8e20c68 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -850,7 +850,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,              disabled_items.push_back(std::string("Copy"));          } -        if (isAgentInventory() && !single_folder_root) +        if (isAgentInventory() && !single_folder_root && !isMarketplaceListingsFolder())          {              items.push_back(std::string("New folder from selected"));              items.push_back(std::string("Subfolder Separator")); @@ -5309,7 +5309,7 @@ void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer<LLI      // Note: creation will take time, so passing folder id to callback is slightly unreliable,      // but so is collecting and passing descendants' ids -    inventory_func_type func = boost::bind(&LLFolderBridge::outfitFolderCreatedCallback, this, inv_cat->getUUID(), _1, cb); +    inventory_func_type func = boost::bind(outfitFolderCreatedCallback, inv_cat->getUUID(), _1, cb, mInventoryPanel);      gInventory.createNewCategory(dest_id,                                   LLFolderType::FT_OUTFIT,                                   inv_cat->getName(), @@ -5317,11 +5317,25 @@ void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer<LLI                                   inv_cat->getThumbnailUUID());  } -void LLFolderBridge::outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id, LLPointer<LLInventoryCallback> cb) +void LLFolderBridge::outfitFolderCreatedCallback(LLUUID cat_source_id, +                                                 LLUUID cat_dest_id, +                                                 LLPointer<LLInventoryCallback> cb, +                                                 LLHandle<LLInventoryPanel> inventory_panel)  {      LLInventoryModel::cat_array_t* categories;      LLInventoryModel::item_array_t* items; -    getInventoryModel()->getDirectDescendentsOf(cat_source_id, categories, items); + +    LLInventoryPanel* panel = inventory_panel.get(); +    if (!panel) +    { +        return; +    } +    LLInventoryModel*  model = panel->getModel(); +    if (!model) +    { +        return; +    } +    model->getDirectDescendentsOf(cat_source_id, categories, items);      LLInventoryObject::const_object_list_t link_array; diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index b0139e225e..70a457f98c 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -378,7 +378,10 @@ public:      static void staticFolderOptionsMenu();  protected: -    void outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id, LLPointer<LLInventoryCallback> cb); +    static void outfitFolderCreatedCallback(LLUUID cat_source_id, +                                            LLUUID cat_dest_id, +                                            LLPointer<LLInventoryCallback> cb, +                                            LLHandle<LLInventoryPanel> inventory_panel);      void callback_pasteFromClipboard(const LLSD& notification, const LLSD& response);      void perform_pasteFromClipboard();      void gatherMessage(std::string& message, S32 depth, LLError::ELevel log_level); diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 4b47346473..5f5474b359 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -569,7 +569,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men              items.push_back(std::string("Copy Asset UUID"));              items.push_back(std::string("Copy Separator")); -            bool is_asset_knowable = is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(obj->getType()); +            bool is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(obj->getType());              if ( !is_asset_knowable // disable menu item for Inventory items with unknown asset. EXT-5308                   || (! ( is_full_perm_item || gAgent.isGodlike())))              { diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 65b8bc9e2c..c6192ddf1a 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1744,7 +1744,7 @@ void LLInventoryModel::changeItemParent(LLViewerInventoryItem* item,              << " from " << make_inventory_info(item->getParentUUID())              << " to " << make_inventory_info(new_parent_id) << LL_ENDL; -        LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(), -1); +        LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1);          accountForUpdate(old_folder);          LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1, false);          accountForUpdate(new_folder); @@ -2046,8 +2046,8 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo          {              LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child cats" << LL_ENDL;          } -        delete cat_list;          mParentChildCategoryTree.erase(id); +        delete cat_list;      }      addChangedMask(LLInventoryObserver::REMOVE, id); @@ -2540,7 +2540,7 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const                  cat->setDescendentCount(descendents_actual);                  if (update.mChangeVersion)                  { -                    cat->setVersion(++version); +                cat->setVersion(++version);                  }                  LL_DEBUGS(LOG_INV) << "accounted: '" << cat->getName() << "' "                                     << version << " with " << descendents_actual @@ -5056,4 +5056,3 @@ void LLInventoryModel::FetchItemHttpHandler::processFailure(const char * const r                        << LLCoreHttpUtil::responseToString(response) << "]" << LL_ENDL;      gInventory.notifyObservers();  } - diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index b664bfe6b9..77cf5bdcf2 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -30,6 +30,7 @@  #include "llaisapi.h"  #include "llagent.h"  #include "llappviewer.h" +#include "llappearancemgr.h"  #include "llcallbacklist.h"  #include "llinventorymodel.h"  #include "llinventorypanel.h" @@ -470,6 +471,22 @@ void LLInventoryModelBackgroundFetch::fetchCOF(nullary_func_t callback)                           callback();                           LLUUID cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);                           LLInventoryModelBackgroundFetch::getInstance()->onAISFolderCalback(cat_id, id, FT_DEFAULT); + +                         if (id.notNull()) +                         { +                             // COF might have fetched base outfit folder through a link, but it hasn't +                             // fetched base outfit's content, which doesn't nessesary match COF, +                             // so make sure it's up to date +                             LLUUID baseoutfit_id = LLAppearanceMgr::getInstance()->getBaseOutfitUUID(); +                             if (baseoutfit_id.notNull()) +                             { +                                 LLViewerInventoryCategory* cat = gInventory.getCategory(baseoutfit_id); +                                 if (!cat || cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) +                                 { +                                     LLInventoryModelBackgroundFetch::getInstance()->fetchFolderAndLinks(baseoutfit_id, no_op); +                                 } +                             } +                         }                       });      // start idle loop to track completion diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 4ac43ea6b2..a87d18e4bb 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -578,8 +578,8 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve          if (model_item && view_item && viewmodel_item)          {              const LLUUID& idp = viewmodel_item->getUUID(); -            view_item->destroyView();              removeItemID(idp); +            view_item->destroyView();          }          LLInventoryObject const* objectp = mInventory->getObject(item_id); diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp index f43613be9f..b852ba0e3c 100644 --- a/indra/newview/llmanip.cpp +++ b/indra/newview/llmanip.cpp @@ -574,9 +574,6 @@ void LLManip::renderTickValue(const LLVector3& pos, F32 value, const std::string              gGL.scalef(inv_zoom_amt, inv_zoom_amt, inv_zoom_amt);          } -        LLColor4 shadow_color = LLColor4::black; -        shadow_color.mV[VALPHA] = color.mV[VALPHA] * 0.5f; -          if (fractional_portion != 0)          {              fraction_string = llformat("%c%02d%s", LLResMgr::getInstance()->getDecimalPoint(), fractional_portion, suffix.c_str()); diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 736971276e..92545cf008 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -132,25 +132,17 @@ std::string getLodSuffix(S32 lod)  void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut)  { -    LLModelLoader::scene::iterator base_iter = scene.begin(); -    bool found = false; -    while (!found && (base_iter != scene.end())) +    for (auto scene_iter = scene.begin(); scene_iter != scene.end(); scene_iter++)      { -        matOut = base_iter->first; - -        LLModelLoader::model_instance_list::iterator base_instance_iter = base_iter->second.begin(); -        while (!found && (base_instance_iter != base_iter->second.end())) +        for (auto model_iter = scene_iter->second.begin(); model_iter != scene_iter->second.end(); model_iter++)          { -            LLModelInstance& base_instance = *base_instance_iter++; -            LLModel* base_model = base_instance.mModel; - -            if (base_model && (base_model->mLabel == name_to_match)) +            if (model_iter->mModel && (model_iter->mModel->mLabel == name_to_match))              { -                baseModelOut = base_model; +                baseModelOut = model_iter->mModel; +                matOut = scene_iter->first;                  return;              }          } -        base_iter++;      }  } @@ -210,9 +202,12 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)  LLModelPreview::~LLModelPreview()  { +    LLMutexLock lock(this); +      if (mModelLoader)      {          mModelLoader->shutdown(); +        mModelLoader = NULL;      }      if (mPreviewAvatar) @@ -260,7 +255,7 @@ void LLModelPreview::updateDimentionsAndOffsets()              accounted.insert(instance.mModel);              // update instance skin info for each lods pelvisZoffset -            for (int j = 0; j<LLModel::NUM_LODS; ++j) +            for (int j = 0; j < LLModel::NUM_LODS; ++j)              {                  if (instance.mLOD[j])                  { @@ -301,7 +296,7 @@ void LLModelPreview::rebuildUploadData()      BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching");      U32 load_state = 0; -    for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) +    for (auto iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter)      { //for each transform in scene          LLMatrix4 mat = iter->first; @@ -320,9 +315,9 @@ void LLModelPreview::rebuildUploadData()          mat *= scale_mat; -        for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();) +        for (auto model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)          { // for each instance with said transform applied -            LLModelInstance instance = *model_iter++; +            LLModelInstance instance = *model_iter;              LLModel* base_model = instance.mModel; @@ -882,7 +877,7 @@ void LLModelPreview::clearIncompatible(S32 lod)                  {                      mBaseModel = mModel[lod];                      mBaseScene = mScene[lod]; -                    mVertexBuffer[5].clear(); +                    mVertexBuffer[LLModel::NUM_LODS].clear();                      replaced_base_model = true;                  }              } @@ -1081,7 +1076,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)              mBaseModel = mModel[loaded_lod];              mBaseScene = mScene[loaded_lod]; -            mVertexBuffer[5].clear(); +            mVertexBuffer[LLModel::NUM_LODS].clear();          }          else          { @@ -1186,7 +1181,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)      {          if (!mBaseModel.empty())          { -            const std::string& model_name = mBaseModel[0]->getName(); +            std::string model_name = mBaseModel.front()->getName();              LLLineEditor* description_form = mFMP->getChild<LLLineEditor>("description_form");              if (description_form->getText().empty())              { @@ -1207,6 +1202,8 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)  void LLModelPreview::resetPreviewTarget()  { +    LLMutexLock lock(this); +      if (mModelLoader)      {          mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; @@ -1252,7 +1249,7 @@ void LLModelPreview::generateNormals()              (*it)->generateNormals(angle_cutoff);          } -        mVertexBuffer[5].clear(); +        mVertexBuffer[LLModel::NUM_LODS].clear();      }      bool perform_copy = mModelFacesCopy[which_lod].empty(); @@ -2094,7 +2091,7 @@ void LLModelPreview::updateStatusMessages()      S32 total_verts[LLModel::NUM_LODS];      S32 total_submeshes[LLModel::NUM_LODS]; -    for (U32 i = 0; i < LLModel::NUM_LODS - 1; i++) +    for (U32 i = 0; i < LLModel::NUM_LODS; i++)      {          total_tris[i] = 0;          total_verts[i] = 0; @@ -2398,12 +2395,16 @@ void LLModelPreview::updateStatusMessages()          }      } -    if (mModelNoErrors && mModelLoader) +    if (mModelNoErrors)      { -        if (!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) +        LLMutexLock lock(this); +        if (mModelLoader)          { -            // Some textures are still loading, prevent upload until they are done -            mModelNoErrors = false; +            if (!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) +            { +                // Some textures are still loading, prevent upload until they are done +                mModelNoErrors = false; +            }          }      } @@ -2732,10 +2733,10 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)  {      LLModelLoader::model_list* model = NULL; -    if (lod < 0 || lod > 4) +    if (lod < 0 || lod >= LLModel::NUM_LODS)      {          model = &mBaseModel; -        lod = 5; +        lod = LLModel::NUM_LODS;      }      else      { @@ -2972,8 +2973,9 @@ void LLModelPreview::loadedCallback(      S32 lod,      void* opaque)  { -    LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); -    if (pPreview && !LLModelPreview::sIgnoreLoadedCallback) +    LLModelPreview* pPreview = static_cast<LLModelPreview*>(opaque); +    LLMutexLock lock(pPreview); +    if (pPreview && pPreview->mModelLoader && !LLModelPreview::sIgnoreLoadedCallback)      {          // Load loader's warnings into floater's log tab          const LLSD out = pPreview->mModelLoader->logOut(); @@ -2994,7 +2996,9 @@ void LLModelPreview::loadedCallback(          }          const LLVOAvatar* avatarp = pPreview->getPreviewAvatar(); -        if (avatarp) { // set up ground plane for possible rendering +        if (avatarp && avatarp->mRoot && avatarp->mDrawable) +        { +            // set up ground plane for possible rendering              const LLVector3 root_pos = avatarp->mRoot->getPosition();              const LLVector4a* ext = avatarp->mDrawable->getSpatialExtents();              const LLVector4a min = ext[0], max = ext[1]; @@ -3131,12 +3135,12 @@ BOOL LLModelPreview::render()      LLMutexLock lock(this);      mNeedsUpdate = FALSE; -    bool edges = mViewOption["show_edges"]; -    bool joint_overrides = mViewOption["show_joint_overrides"]; -    bool joint_positions = mViewOption["show_joint_positions"]; -    bool skin_weight = mViewOption["show_skin_weight"]; -    bool textures = mViewOption["show_textures"]; -    bool physics = mViewOption["show_physics"]; +    bool show_edges = mViewOption["show_edges"]; +    bool show_joint_overrides = mViewOption["show_joint_overrides"]; +    bool show_joint_positions = mViewOption["show_joint_positions"]; +    bool show_skin_weight = mViewOption["show_skin_weight"]; +    bool show_textures = mViewOption["show_textures"]; +    bool show_physics = mViewOption["show_physics"];      S32 width = getWidth();      S32 height = getHeight(); @@ -3213,15 +3217,15 @@ BOOL LLModelPreview::render()                      fmp->childSetValue("upload_skin", true);                      mFirstSkinUpdate = false;                      upload_skin = true; -                    skin_weight = true; +                    show_skin_weight = true;                      mViewOption["show_skin_weight"] = true;                  }                  fmp->enableViewOption("show_skin_weight"); -                fmp->setViewOptionEnabled("show_joint_overrides", skin_weight); -                fmp->setViewOptionEnabled("show_joint_positions", skin_weight); +                fmp->setViewOptionEnabled("show_joint_overrides", show_skin_weight); +                fmp->setViewOptionEnabled("show_joint_positions", show_skin_weight);                  mFMP->childEnable("upload_skin"); -                mFMP->childSetValue("show_skin_weight", skin_weight); +                mFMP->childSetValue("show_skin_weight", show_skin_weight);              }              else if ((flags & LEGACY_RIG_FLAG_TOO_MANY_JOINTS) > 0) @@ -3244,11 +3248,12 @@ BOOL LLModelPreview::render()              fmp->disableViewOption("show_joint_overrides");              fmp->disableViewOption("show_joint_positions"); -            skin_weight = false; +            show_skin_weight = false;              mFMP->childSetValue("show_skin_weight", false); -            fmp->setViewOptionEnabled("show_skin_weight", skin_weight); +            fmp->setViewOptionEnabled("show_skin_weight", show_skin_weight);          }      } +    //if (this) return TRUE;      if (upload_skin && !has_skin_weights)      { //can't upload skin weights if model has no skin weights @@ -3291,7 +3296,7 @@ BOOL LLModelPreview::render()          mFMP->childSetEnabled("upload_joints", upload_skin);      } -    F32 explode = mFMP->childGetValue("physics_explode").asReal(); +    F32 physics_explode = mFMP->childGetValue("physics_explode").asReal();      LLGLDepthTest gls_depth(GL_TRUE); // SL-12781 re-enable z-buffer for 3D model preview @@ -3311,7 +3316,7 @@ BOOL LLModelPreview::render()      F32 z_near = 0.001f;      F32 z_far = mCameraDistance*10.0f + mPreviewScale.magVec() + mCameraOffset.magVec(); -    if (skin_weight) +    if (show_skin_weight)      {          target_pos = getPreviewAvatar()->getPositionAgent() + offset;          z_near = 0.01f; @@ -3321,7 +3326,7 @@ BOOL LLModelPreview::render()          refresh();      } -    gObjectPreviewProgram.bind(skin_weight); +    gObjectPreviewProgram.bind(show_skin_weight);      gGL.loadIdentity();      gPipeline.enableLightsPreview(); @@ -3330,7 +3335,7 @@ BOOL LLModelPreview::render()          LLQuaternion(mCameraYaw, LLVector3::z_axis);      LLQuaternion av_rot = camera_rot; -    F32 camera_distance = skin_weight ? SKIN_WEIGHT_CAMERA_DISTANCE : mCameraDistance; +    F32 camera_distance = show_skin_weight ? SKIN_WEIGHT_CAMERA_DISTANCE : mCameraDistance;      LLViewerCamera::getInstance()->setOriginAndLookAt(          target_pos + ((LLVector3(camera_distance, 0.f, 0.f) + offset) * av_rot),        // camera          LLVector3::z_axis,                                                                  // up @@ -3346,9 +3351,9 @@ BOOL LLModelPreview::render()      gGL.pushMatrix();      gGL.color4fv(PREVIEW_EDGE_COL.mV); -    if (!mBaseModel.empty() && mVertexBuffer[5].empty()) +    if (!mBaseModel.empty() && mVertexBuffer[LLModel::NUM_LODS].empty())      { -        genBuffers(-1, skin_weight); +        genBuffers(-1, show_skin_weight);          //genBuffers(3);      } @@ -3363,7 +3368,7 @@ BOOL LLModelPreview::render()              if (!vb_vec.empty())              {                  const LLVertexBuffer* buff = vb_vec[0]; -                regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; +                regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != show_skin_weight;              }              else              { @@ -3374,15 +3379,15 @@ BOOL LLModelPreview::render()          if (regen)          { -            genBuffers(mPreviewLOD, skin_weight); +            genBuffers(mPreviewLOD, show_skin_weight);          } -        if (physics && mVertexBuffer[LLModel::LOD_PHYSICS].empty()) +        if (show_physics && mVertexBuffer[LLModel::LOD_PHYSICS].empty())          {              genBuffers(LLModel::LOD_PHYSICS, false);          } -        if (!skin_weight) +        if (!show_skin_weight)          {              for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)              { @@ -3404,11 +3409,7 @@ BOOL LLModelPreview::render()                  U32 num_models = mVertexBuffer[mPreviewLOD][model].size();                  for (U32 i = 0; i < num_models; ++i)                  { -                    LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - -                    buffer->setBuffer(); - -                    if (textures) +                    if (show_textures)                      {                          int materialCnt = instance.mModel->mMaterialList.size();                          if (i < materialCnt) @@ -3432,10 +3433,16 @@ BOOL LLModelPreview::render()                          gGL.diffuseColor4fv(PREVIEW_BASE_COL.mV);                      } +                    // Zero this variable for an obligatory buffer initialization +                    // See https://github.com/secondlife/viewer/issues/912 +                    LLVertexBuffer::sGLRenderBuffer = 0; +                    LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; +                    buffer->setBuffer();                      buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); +                      gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);                      gGL.diffuseColor4fv(PREVIEW_EDGE_COL.mV); -                    if (edges) +                    if (show_edges)                      {                          glLineWidth(PREVIEW_EDGE_WIDTH);                          glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -3448,7 +3455,7 @@ BOOL LLModelPreview::render()                  gGL.popMatrix();              } -            if (physics) +            if (show_physics)              {                  glClear(GL_DEPTH_BUFFER_BIT); @@ -3514,12 +3521,12 @@ BOOL LLModelPreview::render()                                      for (U32 i = 0; i < physics.mMesh.size(); ++i)                                      { -                                        if (explode > 0.f) +                                        if (physics_explode > 0.f)                                          {                                              gGL.pushMatrix();                                              LLVector3 offset = model->mHullCenter[i] - model->mCenterOfHullCenters; -                                            offset *= explode; +                                            offset *= physics_explode;                                              gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);                                          } @@ -3534,7 +3541,7 @@ BOOL LLModelPreview::render()                                          gGL.diffuseColor4ubv(hull_colors[i].mV);                                          LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions); -                                        if (explode > 0.f) +                                        if (physics_explode > 0.f)                                          {                                              gGL.popMatrix();                                          } @@ -3549,14 +3556,17 @@ BOOL LLModelPreview::render()                          if (render_mesh)                          {                              U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); -                            if (pass > 0){ +                            if (pass > 0) +                            {                                  for (U32 i = 0; i < num_models; ++i)                                  { -                                    LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; -                                      gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);                                      gGL.diffuseColor4fv(PREVIEW_PSYH_FILL_COL.mV); +                                    // Zero this variable for an obligatory buffer initialization +                                    // See https://github.com/secondlife/viewer/issues/912 +                                    LLVertexBuffer::sGLRenderBuffer = 0; +                                    LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];                                      buffer->setBuffer();                                      buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); @@ -3616,10 +3626,11 @@ BOOL LLModelPreview::render()                                      U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();                                      for (U32 v = 0; v < num_models; ++v)                                      { +                                        // Zero this variable for an obligatory buffer initialization +                                        // See https://github.com/secondlife/viewer/issues/912 +                                        LLVertexBuffer::sGLRenderBuffer = 0;                                          LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][v]; -                                          buffer->setBuffer(); -                                          LLStrider<LLVector3> pos_strider;                                          buffer->getVertexStrider(pos_strider, 0);                                          LLVector4a* pos = (LLVector4a*)pos_strider.get(); @@ -3683,7 +3694,7 @@ BOOL LLModelPreview::render()                          U32 joint_count = LLSkinningUtil::getMeshJointCount(skin);                          U32 bind_count = skin->mAlternateBindMatrix.size(); -                        if (joint_overrides +                        if (show_joint_overrides                              && bind_count > 0                              && joint_count == bind_count)                          { @@ -3726,16 +3737,15 @@ BOOL LLModelPreview::render()                              }                          } -                        for (U32 i = 0, e = mVertexBuffer[mPreviewLOD][model].size(); i < e; ++i) +                        std::size_t size = mVertexBuffer[mPreviewLOD][model].size(); +                        for (U32 i = 0; i < size; ++i)                          { -                            LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; -                              model->mSkinInfo.updateHash();                              LLRenderPass::uploadMatrixPalette(mPreviewAvatar, &model->mSkinInfo);                              gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -                            if (textures) +                            if (show_textures)                              {                                  int materialCnt = instance.mModel->mMaterialList.size();                                  if (i < materialCnt) @@ -3759,10 +3769,14 @@ BOOL LLModelPreview::render()                                  gGL.diffuseColor4fv(PREVIEW_BASE_COL.mV);                              } +                            // Zero this variable for an obligatory buffer initialization +                            // See https://github.com/secondlife/viewer/issues/912 +                            LLVertexBuffer::sGLRenderBuffer = 0; +                            LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];                              buffer->setBuffer();                              buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); -                            if (edges) +                            if (show_edges)                              {                                  gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);                                  gGL.diffuseColor4fv(PREVIEW_EDGE_COL.mV); @@ -3777,7 +3791,7 @@ BOOL LLModelPreview::render()                  }              } -            if (joint_positions) +            if (show_joint_positions)              {                  LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;                  if (shader) diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 0870211a8e..84e646a93a 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -925,12 +925,12 @@ void LLOutfitListBase::onIdleRefreshList()          {              std::string name = cat->getName();              updateChangedCategoryName(cat, name); -        }          curent_time = LLTimer::getTotalSeconds();          if (curent_time >= end_time)              return;      } +    }      sortOutfits();      highlightBaseOutfit(); diff --git a/indra/newview/llpanelemojicomplete.cpp b/indra/newview/llpanelemojicomplete.cpp index e6e3a10e13..c7c0627009 100644 --- a/indra/newview/llpanelemojicomplete.cpp +++ b/indra/newview/llpanelemojicomplete.cpp @@ -68,6 +68,9 @@ LLPanelEmojiComplete::LLPanelEmojiComplete(const LLPanelEmojiComplete::Params& p      {          LLScrollbar::Params sbparams;          sbparams.orientation(LLScrollbar::VERTICAL); +        sbparams.doc_size(mTotalEmojis); +        sbparams.doc_pos(0); +        sbparams.page_size(mVisibleEmojis);          sbparams.change_callback([this](S32 index, LLScrollbar*) { onScrollbarChange(index); });          mScrollbar = LLUICtrlFactory::create<LLScrollbar>(sbparams);          addChild(mScrollbar); diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 38af68bfff..5e5d5f42d4 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -5230,7 +5230,7 @@ void LLPanelFace::LLSelectedTE::getFace(LLFace*& face_to_return, bool& identical  void LLPanelFace::LLSelectedTE::getImageFormat(LLGLenum& image_format_to_return, bool& identical_face)  { -    LLGLenum image_format; +    LLGLenum image_format{};      struct LLSelectedTEGetImageFormat : public LLSelectedTEGetFunctor<LLGLenum>      {          LLGLenum get(LLViewerObject* object, S32 te_index) @@ -5496,4 +5496,3 @@ void LLPanelFace::LLSelectedTE::getMaxDiffuseRepeats(F32& repeats, bool& identic      } max_diff_repeats_func;      identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_diff_repeats_func, repeats );  } - diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index da53b4a14c..318c7ccd24 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -396,7 +396,7 @@ private:          ReturnType (LLMaterial::* const MaterialGetFunc)() const  >      static void getTEMaterialValue(DataType& data_to_return, bool& identical,DataType default_value, bool has_tolerance = false, DataType tolerance = DataType())      { -        DataType data_value; +        DataType data_value{};          struct GetTEMaterialVal : public LLSelectedTEGetFunctor<DataType>          {              GetTEMaterialVal(DataType default_value) : _default(default_value) {} @@ -429,7 +429,7 @@ private:          ReturnType (LLTextureEntry::* const TEGetFunc)() const >      static void getTEValue(DataType& data_to_return, bool& identical, DataType default_value, bool has_tolerance = false, DataType tolerance = DataType())      { -        DataType data_value; +        DataType data_value {};          struct GetTEVal : public LLSelectedTEGetFunctor<DataType>          {              GetTEVal(DataType default_value) : _default(default_value) {} @@ -622,4 +622,3 @@ public:  };  #endif - diff --git a/indra/newview/llphysicsshapebuilderutil.cpp b/indra/newview/llphysicsshapebuilderutil.cpp index 37534feadc..eb0df1194e 100644 --- a/indra/newview/llphysicsshapebuilderutil.cpp +++ b/indra/newview/llphysicsshapebuilderutil.cpp @@ -28,6 +28,26 @@  #include "llphysicsshapebuilderutil.h" +#include "llmeshrepository.h" + +bool LLPhysicsVolumeParams::hasDecomposition() const + { +    if (!isMeshSculpt()) +    { +        return false; +    } + +    LLUUID mesh_id = getSculptID(); +    if (mesh_id.isNull()) +    { +        return false; +    } + +    LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id); + +    return decomp != NULL; +} +  /* static */  void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumeParams& volume_params, const LLVector3& scale, PhysicsShapeSpecification& specOut)  { @@ -200,19 +220,32 @@ void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumePara      {          specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX;      } -    else if (volume_params.isMeshSculpt() && -             // Check overall dimensions, not individual triangles. -             (scale.mV[0] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE || -              scale.mV[1] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE || -              scale.mV[2] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE -              ) ) +    else if (volume_params.isMeshSculpt())      { -        // Server distinguishes between user-specified or default convex mesh, vs server's thin-triangle override, but we don't. -        specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX; +        // Check overall dimensions, not individual triangles. +        if (scale.mV[0] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE +            || scale.mV[1] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE +            || scale.mV[2] < SHAPE_BUILDER_USER_MESH_CONVEXIFICATION_SIZE +            ) +        { +            if (volume_params.hasDecomposition()) +            { +                specOut.mType = PhysicsShapeSpecification::USER_MESH; +            } +            else +            { +                // Server distinguishes between user-specified or default convex mesh, vs server's thin-triangle override, but we don't. +                specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX; +            } +        } +        else +        { +            specOut.mType = PhysicsShapeSpecification::USER_MESH; +        }      } -    else if ( volume_params.isSculpt() ) // Is a sculpt of any kind (mesh or legacy) +    else if ( volume_params.isSculpt() )      { -        specOut.mType = volume_params.isMeshSculpt() ? PhysicsShapeSpecification::USER_MESH : PhysicsShapeSpecification::SCULPT; +        specOut.mType = PhysicsShapeSpecification::SCULPT;      }      else // Resort to mesh      { diff --git a/indra/newview/llphysicsshapebuilderutil.h b/indra/newview/llphysicsshapebuilderutil.h index 0f3baa2c7f..25b44bbbb5 100644 --- a/indra/newview/llphysicsshapebuilderutil.h +++ b/indra/newview/llphysicsshapebuilderutil.h @@ -78,6 +78,8 @@ public:      bool shouldForceConvex() const { return mForceConvex; } +    bool hasDecomposition() const; +  private:      bool mForceConvex;  }; diff --git a/indra/newview/lltoastalertpanel.h b/indra/newview/lltoastalertpanel.h index 2a9aaf8ce2..9721a4b1b6 100644 --- a/indra/newview/lltoastalertpanel.h +++ b/indra/newview/lltoastalertpanel.h @@ -82,14 +82,10 @@ private:      struct ButtonData      { -        ButtonData() -        : mWidth(0) -        {} - -        LLButton* mButton; +        LLButton* mButton = nullptr;          std::string mURL; -        U32 mURLExternal; -        S32 mWidth; +        U32 mURLExternal = 0; +        S32 mWidth = 0;      };      std::vector<ButtonData> mButtonData; diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index fa3bfe6e2a..30a465d568 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -407,10 +407,16 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w                  F32* vw = (F32*) vertex_weightsp.get();                  F32* cw = (F32*) clothing_weightsp.get(); -                S32 tc_size = (num_verts*2*sizeof(F32)+0xF) & ~0xF; -                LLVector4a::memcpyNonAliased16(tc, (F32*) mMesh->getTexCoords(), tc_size); -                S32 vw_size = (num_verts*sizeof(F32)+0xF) & ~0xF; -                LLVector4a::memcpyNonAliased16(vw, (F32*) mMesh->getWeights(), vw_size); +                //S32 tc_size = (num_verts*2*sizeof(F32)+0xF) & ~0xF; +                //LLVector4a::memcpyNonAliased16(tc, (F32*) mMesh->getTexCoords(), tc_size); +                //S32 vw_size = (num_verts*sizeof(F32)+0xF) & ~0xF; +                //LLVector4a::memcpyNonAliased16(vw, (F32*) mMesh->getWeights(), vw_size); + +                // Both allocated in LLPolyMeshSharedData::allocateVertexData(unsigned int) + +                memcpy(tc, mMesh->getTexCoords(), num_verts*2*sizeof(F32) ); +                memcpy(vw, mMesh->getWeights(), num_verts*sizeof(F32) ); +                  LLVector4a::memcpyNonAliased16(cw, (F32*) mMesh->getClothingWeights(), num_verts*4*sizeof(F32));              } diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 66182684ad..c8b7a9c29b 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1723,8 +1723,6 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_          std::string user_data_path_cache = gDirUtilp->getCacheDir(false);          user_data_path_cache += gDirUtilp->getDirDelimiter(); -        std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef_log.txt"); -          // See if the plugin executable exists          llstat s;          if(LLFile::stat(launcher_name, &s)) @@ -1733,14 +1731,13 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_          }          else if(LLFile::stat(plugin_name, &s))          { -#if !LL_LINUX              LL_WARNS_ONCE("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; -#endif          }          else          {              media_source = new LLPluginClassMedia(owner);              media_source->setSize(default_width, default_height); +            std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.log");              media_source->setUserDataPath(user_data_path_cache, gDirUtilp->getUserName(), user_data_path_cef_log);              media_source->setLanguageCode(LLUI::getLanguage());              media_source->setZoomFactor(zoom_factor); @@ -1768,6 +1765,11 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_              bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging");              media_source->enableMediaPluginDebugging( media_plugin_debugging_enabled  || clean_browser); +#if LL_LINUX +            bool media_plugin_pipewire_volume_catcher = gSavedSettings.getBOOL("MediaPluginPipeWireVolumeCatcher"); +            media_source->enablePipeWireVolumeCatcher( media_plugin_pipewire_volume_catcher ); +#endif +              // need to set agent string here before instance created              media_source->setBrowserUserAgent(LLViewerMedia::getInstance()->getCurrentUserAgent()); @@ -1789,9 +1791,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_              }          }      } -#if !LL_LINUX      LL_WARNS_ONCE("Plugin") << "plugin initialization failed for mime type: " << media_type << LL_ENDL; -#endif      if(gAgent.isInitialized())      { diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index ac107aa15e..26c8483223 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3038,24 +3038,33 @@ void LLViewerObject::fetchInventoryFromServer()          delete mInventory;          mInventory = NULL; -        // Results in processTaskInv -        LLMessageSystem* msg = gMessageSystem; -        msg->newMessageFast(_PREHASH_RequestTaskInventory); -        msg->nextBlockFast(_PREHASH_AgentData); -        msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -        msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -        msg->nextBlockFast(_PREHASH_InventoryData); -        msg->addU32Fast(_PREHASH_LocalID, mLocalID); -        msg->sendReliable(mRegionp->getHost()); -          // This will get reset by doInventoryCallback or processTaskInv          mInvRequestState = INVENTORY_REQUEST_PENDING; + +        if (mRegionp && !mRegionp->getCapability("RequestTaskInventory").empty()) +        { +            LLCoros::instance().launch("LLViewerObject::fetchInventoryFromCapCoro()", +                                       boost::bind(&LLViewerObject::fetchInventoryFromCapCoro, mID)); +        } +        else +        { +            LL_WARNS() << "Using old task inventory path!" << LL_ENDL; +            // Results in processTaskInv +            LLMessageSystem *msg = gMessageSystem; +            msg->newMessageFast(_PREHASH_RequestTaskInventory); +            msg->nextBlockFast(_PREHASH_AgentData); +            msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +            msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +            msg->nextBlockFast(_PREHASH_InventoryData); +            msg->addU32Fast(_PREHASH_LocalID, mLocalID); +            msg->sendReliable(mRegionp->getHost()); +        }      }  }  void LLViewerObject::fetchInventoryDelayed(const F64 &time_seconds)  { -    // unless already waiting, drop previous request and shedule an update +    // unless already waiting, drop previous request and schedule an update      if (mInvRequestState != INVENTORY_REQUEST_WAIT)      {          if (mInvRequestXFerId != 0) @@ -3086,6 +3095,80 @@ void LLViewerObject::fetchInventoryDelayedCoro(const LLUUID task_inv, const F64      }  } +//static +void LLViewerObject::fetchInventoryFromCapCoro(const LLUUID task_inv) +{ +    LLViewerObject *obj = gObjectList.findObject(task_inv); +    if (obj) +    { +        LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +        LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +                                   httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TaskInventoryRequest", httpPolicy)); +        LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +        std::string url = obj->mRegionp->getCapability("RequestTaskInventory") + "?task_id=" + obj->mID.asString(); +        // If we already have a copy of the inventory then add it so the server won't re-send something we already have. +        // We expect this case to crop up in the case of failed inventory mutations, but it might happen otherwise as well. +        if (obj->mInventorySerialNum && obj->mInventory) +            url += "&inventory_serial=" + std::to_string(obj->mInventorySerialNum); + +        obj->mInvRequestState = INVENTORY_XFER; +        LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + +        LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +        LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +        // Object may have gone away while we were suspended, double-check that it still exists +        obj = gObjectList.findObject(task_inv); +        if (!obj) +        { +            LL_WARNS() << "Object " << task_inv << " went away while fetching inventory, dropping result" << LL_ENDL; +            return; +        } + +        bool potentially_stale = false; +        if (status) +        { +            // Dealing with inventory serials is kind of funky. They're monotonically increasing and 16 bits, +            // so we expect them to overflow, but we can use inv serial < expected serial as a signal that we may +            // have mutated the task inventory since we kicked off the request, and those mutations may have not +            // been taken into account yet. Of course, those mutations may have actually failed which would result +            // in the inv serial never increasing. +            // +            // When we detect this case, set the expected inv serial to the inventory serial we actually received +            // and kick off a re-request after a slight delay. +            S16 serial = (S16)result["inventory_serial"].asInteger(); +            potentially_stale = serial < obj->mExpectedInventorySerialNum; +            LL_INFOS() << "Inventory loaded for " << task_inv << LL_ENDL; +            obj->mInventorySerialNum = serial; +            obj->mExpectedInventorySerialNum = serial; +            obj->loadTaskInvLLSD(result); +        } +        else if (status.getType() == 304) +        { +            LL_INFOS() << "Inventory wasn't changed on server!" << LL_ENDL; +            obj->mInvRequestState = INVENTORY_REQUEST_STOPPED; +            // Even though it wasn't necessary to send a response, we still may have mutated +            // the inventory since we kicked off the request, check for that case. +            potentially_stale = obj->mInventorySerialNum < obj->mExpectedInventorySerialNum; +            // Set this to what we already have so that we don't re-request a second time. +            obj->mExpectedInventorySerialNum = obj->mInventorySerialNum; +        } +        else +        { +            // Not sure that there's anything sensible we can do to recover here, retrying in a loop would be bad. +            LL_WARNS() << "Error status while requesting task inventory: " << status.toString() << LL_ENDL; +            obj->mInvRequestState = INVENTORY_REQUEST_STOPPED; +        } + +        if (potentially_stale) +        { +            // Stale? I guess we can use what we got for now, but we'll have to re-request +            LL_WARNS() << "Stale inv_serial? Re-requesting." << LL_ENDL; +            obj->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_OUTDATED); +        } +    } +} +  LLControlAvatar *LLViewerObject::getControlAvatar()  {      return getRootEdit()->mControlAvatar.get(); @@ -3261,6 +3344,20 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)      S16 serial = 0;      msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, serial); +    if (object->mRegionp && !object->mRegionp->getCapability("RequestTaskInventory").empty()) +    { +        // It seems that simulator may ask us to re-download the task inventory if an update to the inventory +        // happened out-of-band while we had the object selected (like if a script is saved.) +        // +        // If we're meant to use the HTTP capability, ignore the contents of the UDP message and fetch the +        // inventory via the CAP so that we don't flow down the UDP inventory request path unconditionally here. +        // We shouldn't need to wait, as any updates should already be ready to fetch by this point. +        LL_INFOS() << "Handling unsolicited ReplyTaskInventory for " << task_id << LL_ENDL; +        object->mExpectedInventorySerialNum = serial; +        object->fetchInventoryFromServer(); +        return; +    } +      if (serial == object->mInventorySerialNum          && serial < object->mExpectedInventorySerialNum)      { @@ -3468,6 +3565,47 @@ BOOL LLViewerObject::loadTaskInvFile(const std::string& filename)      return TRUE;  } +void LLViewerObject::loadTaskInvLLSD(const LLSD& inv_result) +{ +    if (inv_result.has("contents")) +    { +        if(mInventory) +        { +            mInventory->clear(); // will deref and delete it +        } +        else +        { +            mInventory = new LLInventoryObject::object_list_t; +        } + +        // Synthesize the "Contents" category, the viewer expects it, but it isn't sent. +        LLPointer<LLInventoryObject> inv = new LLInventoryObject(mID, LLUUID::null, LLAssetType::AT_CATEGORY, "Contents"); +        mInventory->push_front(inv); + +        const LLSD& inventory = inv_result["contents"]; +        for (const auto& inv_entry : llsd::inArray(inventory)) +        { +            if (inv_entry.has("item_id")) +            { +                LLPointer<LLViewerInventoryItem> inv = new LLViewerInventoryItem; +                inv->unpackMessage(inv_entry); +                mInventory->push_front(inv); +            } +            else +            { +                LL_WARNS_ONCE() << "Unknown inventory entry while reading from inventory file. Entry: '" +                                << inv_entry << "'" << LL_ENDL; +            } +        } +    } +    else +    { +        LL_WARNS() << "unable to load task inventory: " << inv_result << LL_ENDL; +        return; +    } +    doInventoryCallback(); +} +  void LLViewerObject::doInventoryCallback()  {      for (callback_list_t::iterator iter = mInventoryCallbacks.begin(); diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index a01e0b435f..ad7b3072c8 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -675,6 +675,7 @@ private:      // forms task inventory request after some time passed, marks request as pending      void fetchInventoryDelayed(const F64 &time_seconds);      static void fetchInventoryDelayedCoro(const LLUUID task_inv, const F64 time_seconds); +    static void fetchInventoryFromCapCoro(const LLUUID task_inv);  public:      // @@ -806,6 +807,7 @@ protected:      static void processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status);      BOOL loadTaskInvFile(const std::string& filename); +    void loadTaskInvLLSD(const LLSD &inv_result);      void doInventoryCallback();      BOOL isOnMap(); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index d24e15a7d3..a71746f3d3 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -3190,6 +3190,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)      capabilityNames.append("FetchInventory2");      capabilityNames.append("FetchInventoryDescendents2");      capabilityNames.append("IncrementCOFVersion"); +    capabilityNames.append("RequestTaskInventory");      AISAPI::getCapNames(capabilityNames);      capabilityNames.append("InterestList"); diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 62b4c390d0..b6935aa16a 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -827,6 +827,8 @@ void send_viewer_stats(bool include_preferences)      LL_INFOS("LogViewerStatsPacket") << "Sending viewer statistics: " << body << LL_ENDL; + +    // <ND> Do those lines even do anything sane in regard of debug logging?      LL_DEBUGS("LogViewerStatsPacket");      std::string filename("viewer_stats_packet.xml");      llofstream of(filename.c_str()); diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index 88edb96fbb..2e4002479d 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -317,5 +317,3 @@ F32 LLViewerStatsRecorder::getTimeSinceStart()  {      return (F32) (LLFrameTimer::getTotalSeconds() - mFileOpenTime);  } - - diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 3bb23bf126..89a6734339 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -1009,6 +1009,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon()              std::string old_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SLVoice.old");              if (gDirUtilp->fileExists(new_log))              { +                LLFile::remove(old_log, ENOENT);                  LLFile::rename(new_log, old_log);              } diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 2459f8cd58..fe95aa80e3 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5831,8 +5831,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)                      {                          type = LLDrawPool::POOL_GLTF_PBR;                      } -                    else -                    if (type != LLDrawPool::POOL_ALPHA && force_simple) +                    else if (type != LLDrawPool::POOL_ALPHA && force_simple)                      {                          type = LLDrawPool::POOL_SIMPLE;                      } diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 1cd72a1cc5..5dc2df7bed 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -384,7 +384,7 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const      mCertStore = gSavedSettings.getString("CertStore");      httpOpts->setSSLVerifyPeer( vefifySSLCert ); -    httpOpts->setSSLVerifyHost( vefifySSLCert ? 2 : 0); +    httpOpts->setSSLVerifyHost( vefifySSLCert );      // LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer      httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()); diff --git a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml index e4b8f13df7..f642ca93b7 100644 --- a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml +++ b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml @@ -13,7 +13,6 @@      chrome="true"      height="350"      width="304"> -  <floater.string name="title_for_recently_used" value="Recently used"/>    <floater.string name="title_for_frequently_used" value="Frequently used"/>    <floater.string name="text_no_emoji_for_filter" value="No emoji found for '[FILTER]'"/>    <scroll_container diff --git a/indra/newview/skins/default/xui/en/floater_fast_timers.xml b/indra/newview/skins/default/xui/en/floater_fast_timers.xml index f5852fdfaf..4dc9876ac8 100644 --- a/indra/newview/skins/default/xui/en/floater_fast_timers.xml +++ b/indra/newview/skins/default/xui/en/floater_fast_timers.xml @@ -74,6 +74,8 @@          orientation="vertical"          step_size="16"          doc_size="3000" +        page_size="50" +        doc_pos="0"            />      </layout_panel>      <layout_panel name="timers_panel" diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml index 94c889f4e4..b9259256a6 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml @@ -170,7 +170,7 @@      height="16"      increment="1"      initial_value="12" -    label="Max. # of non-impostors:" +    label="Max. # animated avatars:"      label_width="185"      layout="topleft"      left="30" diff --git a/indra/newview/skins/default/xui/en/floater_world_map.xml b/indra/newview/skins/default/xui/en/floater_world_map.xml index 7efa81d263..19d61eb43b 100644 --- a/indra/newview/skins/default/xui/en/floater_world_map.xml +++ b/indra/newview/skins/default/xui/en/floater_world_map.xml @@ -34,7 +34,8 @@     top="16"     left="0"     right="-1" -   bottom="-1"> +   bottom="-1" +   orientation="horizontal">      <layout_panel       name="map_lp"       width="385" diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index f3d44cf647..ec0d4e1768 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -4107,16 +4107,6 @@ function="World.EnvPreset"          <menu_item_separator/> -        <menu_item_check -         label="HTTP Textures" -         name="HTTP Textures"> -            <menu_item_check.on_check -             function="CheckControl" -             parameter="ImagePipelineUseHTTP" /> -            <menu_item_check.on_click -             function="ToggleControl" -             parameter="ImagePipelineUseHTTP" /> -        </menu_item_check>          <menu_item_call           label="Compress Images"           name="Compress Images"> diff --git a/indra/newview/skins/default/xui/en/mime_types_linux.xml b/indra/newview/skins/default/xui/en/mime_types_linux.xml index d0ecd0a11c..87284f564b 100644 --- a/indra/newview/skins/default/xui/en/mime_types_linux.xml +++ b/indra/newview/skins/default/xui/en/mime_types_linux.xml @@ -7,7 +7,7 @@  		none  	</defaultwidget>  	<defaultimpl> -		media_plugin_webkit +		media_plugin_cef  	</defaultimpl>  	<widgetset name="web">  		<label name="web_label"> @@ -130,7 +130,7 @@  			movie  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</scheme>  	<mimetype name="blank"> @@ -141,7 +141,7 @@  			none  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype name="none/none"> @@ -152,7 +152,7 @@  			none  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype name="audio/*"> @@ -163,7 +163,7 @@  			audio  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  	<mimetype name="video/*"> @@ -174,7 +174,7 @@  			movie  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  	<mimetype name="image/*"> @@ -185,7 +185,7 @@  			image  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype menu="1" name="video/vnd.secondlife.qt.legacy"> @@ -196,7 +196,7 @@  			movie  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  	<mimetype name="application/javascript"> @@ -207,7 +207,7 @@  			web  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype name="application/ogg"> @@ -218,7 +218,7 @@  			audio  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  	<mimetype name="application/pdf"> @@ -229,7 +229,7 @@  			image  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype name="application/postscript"> @@ -240,7 +240,7 @@  			image  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype name="application/rtf"> @@ -251,7 +251,7 @@  			image  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype name="application/smil"> @@ -262,7 +262,7 @@  			movie  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype name="application/xhtml+xml"> @@ -273,7 +273,7 @@  			web  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype name="application/x-director"> @@ -284,7 +284,7 @@  			image  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype name="audio/mid"> @@ -295,7 +295,7 @@  			audio  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  	<mimetype name="audio/mpeg"> @@ -306,7 +306,7 @@  			audio  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  	<mimetype name="audio/x-aiff"> @@ -317,7 +317,7 @@  			audio  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  	<mimetype name="audio/x-wav"> @@ -328,7 +328,7 @@  			audio  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  	<mimetype menu="1" name="image/bmp"> @@ -339,7 +339,7 @@  			image  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype menu="1" name="image/gif"> @@ -350,7 +350,7 @@  			image  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype menu="1" name="image/jpeg"> @@ -361,7 +361,7 @@  			image  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype menu="1" name="image/png"> @@ -372,7 +372,7 @@  			image  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype name="image/svg+xml"> @@ -383,7 +383,7 @@  			image  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype menu="1" name="image/tiff"> @@ -394,7 +394,7 @@  			image  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype menu="1" name="text/html"> @@ -405,7 +405,7 @@  			web  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype menu="1" name="text/plain"> @@ -416,7 +416,7 @@  			text  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype name="text/xml"> @@ -427,7 +427,7 @@  			text  		</widgettype>  		<impl> -			media_plugin_webkit +			media_plugin_cef  		</impl>  	</mimetype>  	<mimetype menu="1" name="video/mpeg"> @@ -438,7 +438,7 @@  			movie  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  	<mimetype name="video/mp4"> @@ -449,7 +449,7 @@  			movie  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  	<mimetype menu="1" name="video/quicktime"> @@ -460,7 +460,7 @@  			movie  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  	<mimetype name="video/x-ms-asf"> @@ -471,7 +471,7 @@  			movie  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  	<mimetype name="video/x-ms-wmv"> @@ -482,7 +482,7 @@  			movie  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  	<mimetype menu="1" name="video/x-msvideo"> @@ -493,7 +493,7 @@  			movie  		</widgettype>  		<impl> -			media_plugin_libvlc +			media_plugin_gstreamer  		</impl>  	</mimetype>  </mimetypes> diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index 1801ae1f49..27b74a46ce 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -145,7 +145,6 @@      control_name="RememberPassword"      follows="left|top"      font="SansSerifMedium" -    text_color="EmphasisColor"      height="24"      left="408"      bottom_delta="0" diff --git a/indra/newview/skins/default/xui/en/panel_login_first.xml b/indra/newview/skins/default/xui/en/panel_login_first.xml index c906e2f96c..d6ac71db94 100644 --- a/indra/newview/skins/default/xui/en/panel_login_first.xml +++ b/indra/newview/skins/default/xui/en/panel_login_first.xml @@ -179,7 +179,6 @@              control_name="RememberPassword"              follows="left|top"              font="SansSerifLarge" -            text_color="EmphasisColor"              height="24"              left="262"              bottom_delta="0" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml index adc0337edd..a19c9dd288 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml @@ -210,26 +210,60 @@      increment="8"      initial_value="160"      label="Draw distance:" -    label_width="90" +    label_width="187"      layout="topleft"      left="30"      min_val="64"      max_val="512"      name="DrawDistance"      top_delta="40" -    width="330" /> +    width="427" />    <text      type="string"      length="1"      follows="left|top"      height="12"      layout="topleft" -    left_delta="330" +    left_delta="427"      name="DrawDistanceMeterText2"      top_delta="0"      width="128">       m    </text> +  <slider +    control_name="IndirectMaxNonImpostors" +    name="IndirectMaxNonImpostors" +    decimal_digits="0" +    increment="1" +    initial_value="12" +    show_text="false" +    min_val="1" +    max_val="66" +    label="Maximum number of animated avatars:" +    follows="left|top" +    layout="topleft" +    height="16" +    label_width="240" +    left="30" +    top_delta="40" +    width="393"> +      <slider.commit_callback +        function="Pref.UpdateIndirectMaxNonImpostors" +        parameter="IndirectNonImpostorsText" /> +  </slider> +  <text +    type="string" +    length="1" +    follows="left|top" +    height="16" +    layout="topleft" +    top_delta="0" +    left_delta="397" +    text_readonly_color="LabelDisabledColor" +    name="IndirectMaxNonImpostorsText" +    width="65"> +      0 +  </text>    <button    height="23" diff --git a/indra/newview/skins/default/xui/en/panel_region_environment.xml b/indra/newview/skins/default/xui/en/panel_region_environment.xml index 6d23592948..6531233696 100644 --- a/indra/newview/skins/default/xui/en/panel_region_environment.xml +++ b/indra/newview/skins/default/xui/en/panel_region_environment.xml @@ -264,8 +264,7 @@                                  top_pad="1"                                  halign="right"                                  name="txt_alt1"> -                            Sky [INDEX] -                            [ALTITUDE]m +                            Sky [INDEX]
[ALTITUDE]m                          </text>                          <line_editor                                  follows="left|top" @@ -310,8 +309,7 @@                                  top_pad="1"                                  halign="right"                                  name="txt_alt2"> -                            Sky [INDEX] -                            [ALTITUDE]m +                            Sky [INDEX]
[ALTITUDE]m                          </text>                          <line_editor                                  follows="left|top" @@ -356,8 +354,7 @@                                  top_pad="1"                                  halign="right"                                  name="txt_alt3"> -                            Sky [INDEX] -                            [ALTITUDE]m +                            Sky [INDEX]
[ALTITUDE]m                          </text>                          <line_editor                                  follows="left|top" diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 37dee9ac1d..682dc253ee 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -59,12 +59,14 @@ class ViewerManifest(LLManifest):          # files during the build (see copy_w_viewer_manifest          # and copy_l_viewer_manifest targets)          return 'package' in self.args['actions'] -     +      def construct(self):          super(ViewerManifest, self).construct()          self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg")          self.path(src="../../etc/message.xml", dst="app_settings/message.xml") +        os.environ["XZ_DEFAULTS"] = "-T0" +          if self.is_packaging_viewer():              with self.prefix(src_dst="app_settings"):                  self.exclude("logcontrol.xml") @@ -87,7 +89,7 @@ class ViewerManifest(LLManifest):                  # ... and the entire image filters directory                  self.path("filters") -             +                  # ... and the included spell checking dictionaries                  pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')                  with self.prefix(src=pkgdir): @@ -260,14 +262,14 @@ class ViewerManifest(LLManifest):      def app_name_oneword(self):          return ''.join(self.app_name().split()) -     +      def icon_path(self):          return "icons/" + self.channel_type()      def extract_names(self,src):          """Extract contributor names from source file, returns string"""          try: -            with open(src, 'r') as contrib_file:  +            with open(src, 'r') as contrib_file:                  lines = contrib_file.readlines()          except IOError:              print("Failed to open '%s'" % src) @@ -491,7 +493,7 @@ class Windows_x86_64_Manifest(ViewerManifest):                  raise Exception("Directories are not supported by test_CRT_and_copy_action()")          else:              print("Doesn't exist:", src) -         +      def construct(self):          super().construct() @@ -543,7 +545,7 @@ class Windows_x86_64_Manifest(ViewerManifest):          self.path2basename(os.path.join(os.pardir,                                          'llplugin', 'slplugin', self.args['configuration']),                             "slplugin.exe") -         +          # Get shared libs from the shared libs staging directory          with self.prefix(src=os.path.join(self.args['build'], os.pardir,                                            'sharedlibs', self.args['buildtype'])): @@ -578,7 +580,7 @@ class Windows_x86_64_Manifest(ViewerManifest):              # Vivox libraries              self.path("vivoxsdk_x64.dll")              self.path("ortp_x64.dll") -             +              # OpenSSL              self.path("libcrypto-1_1-x64.dll")              self.path("libssl-1_1-x64.dll") @@ -705,7 +707,7 @@ class Windows_x86_64_Manifest(ViewerManifest):                  self.path("plugins/")          if not self.is_packaging_viewer(): -            self.package_file = "copied_deps"     +            self.package_file = "copied_deps"      def nsi_file_commands(self, install=True):          def INSTDIR(path): @@ -764,7 +766,7 @@ class Windows_x86_64_Manifest(ViewerManifest):          installer_file = self.installer_base_name() + '_Setup.exe'          substitution_strings['installer_file'] = installer_file -         +          version_vars = """          !define INSTEXE "SLVersionChecker.exe"          !define VERSION "%(version_short)s" @@ -773,7 +775,7 @@ class Windows_x86_64_Manifest(ViewerManifest):          !define VERSION_REGISTRY "%(version_registry)s"          !define VIEWER_EXE "%(final_exe)s"          """ % substitution_strings -         +          if self.channel_type() == 'release':              substitution_strings['caption'] = CHANNEL_VENDOR_BASE          else: @@ -904,7 +906,7 @@ class Darwin_x86_64_Manifest(ViewerManifest):                  # yields a slightly smaller binary but makes crash                  # logs mostly useless. This may be desirable for the                  # final release. Or not. -                if ("package" in self.args['actions'] or  +                if ("package" in self.args['actions'] or                      "unpacked" in self.args['actions']):                      self.run_command(                          ['strip', '-S', executable]) @@ -929,7 +931,7 @@ class Darwin_x86_64_Manifest(ViewerManifest):                  with self.prefix(src=relpkgdir, dst=""):                      self.path("libndofdev.dylib") -                    self.path("libhunspell-*.dylib")    +                    self.path("libhunspell-*.dylib")                  with self.prefix(src_dst="cursors_mac"):                      self.path("*.tif") @@ -1198,6 +1200,9 @@ class LinuxManifest(ViewerManifest):          super(LinuxManifest, self).construct()          pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') +        if "package_dir" in self.args: +            pkgdir = self.args['package_dir'] +          relpkgdir = os.path.join(pkgdir, "lib", "release")          debpkgdir = os.path.join(pkgdir, "lib", "debug") @@ -1216,49 +1221,123 @@ class LinuxManifest(ViewerManifest):          with self.prefix(dst="bin"):              self.path("secondlife-bin","do-not-directly-run-secondlife-bin") -            self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin") +            #self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin")              self.path2basename("../llplugin/slplugin", "SLPlugin")              #this copies over the python wrapper script, associated utilities and required libraries, see SL-321, SL-322 and SL-323 -            with self.prefix(src="../viewer_components/manager", dst=""): -                self.path("*.py") +            #with self.prefix(src="../viewer_components/manager", dst=""): +            #    self.path("*.py")          # recurses, packaged again          self.path("res-sdl") +        # We  copy ll_icon.BMP in CMakeLists.txt to newview/res-sdl and this will let the above self.path step take  care of copying +        # the correct branded icon          # Get the icons based on the channel type          icon_path = self.icon_path() -        print("DEBUG: icon_path '%s'" % icon_path) +        #print("DEBUG: icon_path '%s'" % icon_path)          with self.prefix(src=icon_path) :              self.path("secondlife_256.png","secondlife_icon.png")              with self.prefix(dst="res-sdl") :                  self.path("secondlife_256.BMP","ll_icon.BMP")          # plugins -        with self.prefix(src="../media_plugins", dst="bin/llplugin"): -            self.path("gstreamer010/libmedia_plugin_gstreamer010.so", -                      "libmedia_plugin_gstreamer.so") -            self.path2basename("libvlc", "libmedia_plugin_libvlc.so") - -        with self.prefix(src=os.path.join(pkgdir, 'lib', 'vlc', 'plugins'), dst="bin/llplugin/vlc/plugins"): -            self.path( "plugins.dat" ) -            self.path( "*/*.so" ) - -        with self.prefix(src=os.path.join(pkgdir, 'lib' ), dst="lib"): -            self.path( "libvlc*.so*" ) - -        # llcommon -        if not self.path("../llcommon/libllcommon.so", "lib/libllcommon.so"): -            print("Skipping llcommon.so (assuming llcommon was linked statically)") +        with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins'), dst="bin/llplugin"): +            self.path("gstreamer10/libmedia_plugin_gstreamer10.so", "libmedia_plugin_gstreamer.so") + + +        with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins'), dst="bin/llplugin"): +            self.path("cef/libmedia_plugin_cef.so", "libmedia_plugin_cef.so" ) +        with self.prefix(src=os.path.join(pkgdir, 'lib', 'release'), dst="lib"): +            self.path( "libcef.so" ) + +            self.path( "libEGL*" ) +            self.path( "libvulkan*" ) +            self.path( "libvk_swiftshader*" ) +            self.path( "libGLESv2*" ) +            self.path( "vk_swiftshader_icd.json") + +        with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="bin"): +            self.path( "chrome-sandbox" ) +            self.path( "dullahan_host" ) +            self.path( "snapshot_blob.bin" ) +            self.path( "v8_context_snapshot.bin" ) +        with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="lib"): +            self.path( "snapshot_blob.bin" ) +            self.path( "v8_context_snapshot.bin" ) + +        with self.prefix(src=os.path.join(pkgdir, 'resources'), dst="lib"): +            self.path( "chrome_100_percent.pak" ) +            self.path( "chrome_200_percent.pak" ) +            self.path( "resources.pak" ) +            self.path( "icudtl.dat" ) + +        with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst=os.path.join('lib', 'locales')): +            self.path("am.pak") +            self.path("ar.pak") +            self.path("bg.pak") +            self.path("bn.pak") +            self.path("ca.pak") +            self.path("cs.pak") +            self.path("da.pak") +            self.path("de.pak") +            self.path("el.pak") +            self.path("en-GB.pak") +            self.path("en-US.pak") +            self.path("es-419.pak") +            self.path("es.pak") +            self.path("et.pak") +            self.path("fa.pak") +            self.path("fi.pak") +            self.path("fil.pak") +            self.path("fr.pak") +            self.path("gu.pak") +            self.path("he.pak") +            self.path("hi.pak") +            self.path("hr.pak") +            self.path("hu.pak") +            self.path("id.pak") +            self.path("it.pak") +            self.path("ja.pak") +            self.path("kn.pak") +            self.path("ko.pak") +            self.path("lt.pak") +            self.path("lv.pak") +            self.path("ml.pak") +            self.path("mr.pak") +            self.path("ms.pak") +            self.path("nb.pak") +            self.path("nl.pak") +            self.path("pl.pak") +            self.path("pt-BR.pak") +            self.path("pt-PT.pak") +            self.path("ro.pak") +            self.path("ru.pak") +            self.path("sk.pak") +            self.path("sl.pak") +            self.path("sr.pak") +            self.path("sv.pak") +            self.path("sw.pak") +            self.path("ta.pak") +            self.path("te.pak") +            self.path("th.pak") +            self.path("tr.pak") +            self.path("uk.pak") +            self.path("vi.pak") +            self.path("zh-CN.pak") +            self.path("zh-TW.pak")          self.path("featuretable_linux.txt")          self.path("cube.dae") -        with self.prefix(src=pkgdir): +        with self.prefix(src=pkgdir, dst="bin"):              self.path("ca-bundle.crt")      def package_finish(self):          installer_name = self.installer_base_name() +        # When running as a GitHub Action job, RUNNER_TEMP is defined as the tmp dir +        RUNNER_TEMP = os.getenv('RUNNER_TEMP') +          self.strip_binaries()          # Fix access permissions @@ -1273,93 +1352,79 @@ class LinuxManifest(ViewerManifest):          # temporarily move directory tree so that it has the right          # name in the tarfile          realname = self.get_dst_prefix() -        tempname = self.build_path_of(installer_name) -        self.run_command(["mv", realname, tempname]) +        versionedName = self.build_path_of(installer_name) + +        tarName = versionedName + ".tar.xz" + +        # If using a github runner we divert packaging a little. Considering this wil be a VM/docker image +        # we can just pack the final installer into RUNNER_TEMP and not into the usual stop we'd pick when +        # not building a GHA release +        if RUNNER_TEMP: +            tarName = os.path.join(RUNNER_TEMP, self.package_file) + +        self.run_command(["mv", realname, versionedName]) +          try:              # only create tarball if it's a release build.              if self.args['buildtype'].lower() == 'release': -                # --numeric-owner hides the username of the builder for -                # security etc.                  self.run_command(['tar', '-C', self.get_build_prefix(),                                    '--numeric-owner', '-cJf', -                                 tempname + '.tar.xz', installer_name]) +                                 tarName, installer_name]) +                self.set_github_output_path('viewer_app', tarName)              else:                  print("Skipping %s.tar.xz for non-Release build (%s)" % \                        (installer_name, self.args['buildtype']))          finally: -            self.run_command(["mv", tempname, realname]) +            self.run_command(["mv", versionedName, realname])      def strip_binaries(self): +        doStrip = False          if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer(): -            print("* Going strip-crazy on the packaged binaries, since this is a RELEASE build") +            doStrip = True +        # In case of flatpak flatpak-build will call strip, disable doStrip here to get a flatpak symbol package. Increases flatpak size by about 1G +        if "FLATPAK_DEST" in os.environ: +            doStrip = True + +        if doStrip: +            print("* Going strip-crazy on the packaged binaries, since this is a Release build")              # makes some small assumptions about our packaged dir structure              self.run_command(                  ["find"] +                  [os.path.join(self.get_dst_prefix(), dir) for dir in ('bin', 'lib')] +                  ['-type', 'f', '!', '-name', '*.py', +                 '!', '-name', '*.pak', +                 '!', '-name', '*.bin', +                 '!', '-name', '*.dat', +                 '!', '-name', '*.crt', +                 '!', '-name', '*.dll', +                 '!', '-name', '*.lib',                   '!', '-name', 'update_install', '-exec', 'strip', '-S', '{}', ';']) -class Linux_i686_Manifest(LinuxManifest): -    address_size = 32 +class Linux_x86_64_Manifest(LinuxManifest): +    address_size = 64      def construct(self): -        super(Linux_i686_Manifest, self).construct() +        super(Linux_x86_64_Manifest, self).construct()          pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') +        if "package_dir" in self.args: +            pkgdir = self.args['package_dir'] +          relpkgdir = os.path.join(pkgdir, "lib", "release")          debpkgdir = os.path.join(pkgdir, "lib", "debug")          with self.prefix(src=relpkgdir, dst="lib"): -            self.path("libapr-1.so") -            self.path("libapr-1.so.0") -            self.path("libapr-1.so.0.4.5") -            self.path("libaprutil-1.so") -            self.path("libaprutil-1.so.0") -            self.path("libaprutil-1.so.0.4.1") -            self.path("libdb*.so") +            self.path("libapr-1.so*") +            self.path("libaprutil-1.so*")              self.path("libexpat.so.*") -            self.path("libuuid.so*") -            self.path("libSDL-1.2.so.*") -            self.path("libdirectfb-1.*.so.*") -            self.path("libfusion-1.*.so.*") -            self.path("libdirect-1.*.so.*") -            self.path("libopenjp2.so*") -            self.path("libdirectfb-1.4.so.5") -            self.path("libfusion-1.4.so.5") -            self.path("libdirect-1.4.so.5*") -            self.path("libhunspell-1.3.so*") -            self.path("libalut.so*") -            self.path("libopenal.so*") -            self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname -            # KLUDGE: As of 2012-04-11, the 'fontconfig' package installs -            # libfontconfig.so.1.4.4, along with symlinks libfontconfig.so.1 -            # and libfontconfig.so. Before we added support for library-file -            # wildcards, though, this self.path() call specifically named -            # libfontconfig.so.1.4.4 WITHOUT also copying the symlinks. When I -            # (nat) changed the call to self.path("libfontconfig.so.*"), we -            # ended up with the libfontconfig.so.1 symlink in the target -            # directory as well. But guess what! At least on Ubuntu 10.04, -            # certain viewer fonts look terrible with libfontconfig.so.1 -            # present in the target directory. Removing that symlink suffices -            # to improve them. I suspect that means we actually do better when -            # the viewer fails to find our packaged libfontconfig.so*, falling -            # back on the system one instead -- but diagnosing and fixing that -            # is a bit out of scope for the present project. Meanwhile, this -            # particular wildcard specification gets us exactly what the -            # previous call did, without having to explicitly state the -            # version number. -            self.path("libfontconfig.so.*.*") - -            # Include libfreetype.so. but have it work as libfontconfig does. -            self.path("libfreetype.so.*.*") +            self.path_optional("libSDL*.so.*") -            try: -                self.path("libtcmalloc.so*") #formerly called google perf tools -                pass -            except: -                print("tcmalloc files not found, skipping") -                pass +            self.path_optional("libjemalloc*.so") +            self.path("libhunspell-1.3.so*") +            self.path_optional("libalut.so*") +            self.path_optional("libopenal.so*") +            self.path_optional("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname              if self.args['fmodstudio'] == 'ON':                  try:                      self.path("libfmod.so.11.7") @@ -1380,17 +1445,6 @@ class Linux_i686_Manifest(LinuxManifest):              self.path("libvivoxsdk.so")          self.strip_binaries() - - -class Linux_x86_64_Manifest(LinuxManifest): -    address_size = 64 - -    def construct(self): -        super(Linux_x86_64_Manifest, self).construct() - -        # support file for valgrind debug tool -        self.path("secondlife-i686.supp") -  ################################################################  if __name__ == "__main__": diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index 4a0a8716c4..3dcddf9dc2 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -9,7 +9,6 @@ include(Linking)  include(Tut)  include(LLAddBuildTest)  include(bugsplat) -include(GoogleMock)  set(test_SOURCE_FILES      io.cpp @@ -65,7 +64,6 @@ target_link_libraries(lltest          llxml          llcommon          llcorehttp -        ll::googlemock          )  if (WINDOWS) diff --git a/indra/test/test.cpp b/indra/test/test.cpp index 61a4eb07c5..cc2c130072 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -36,6 +36,7 @@  #include "linden_common.h"  #include "llerrorcontrol.h" +#include "llexception.h"  #include "lltut.h"  #include "chained_callback.h"  #include "stringize.h" @@ -53,11 +54,6 @@  #   include "ctype_workaround.h"  #endif -#ifndef LL_WINDOWS -#include <gmock/gmock.h> -#include <gtest/gtest.h> -#endif -  #if LL_MSVC  #pragma warning (push)  #pragma warning (disable : 4702) // warning C4702: unreachable code @@ -68,11 +64,6 @@  #pragma warning (pop)  #endif -#include <boost/scoped_ptr.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/make_shared.hpp> -#include <boost/foreach.hpp> -  #include <fstream>  void wouldHaveCrashed(const std::string& message); @@ -181,10 +172,6 @@ public:      LLTestCallback(bool verbose_mode, std::ostream *stream,                     std::shared_ptr<LLReplayLog> replayer) :          mVerboseMode(verbose_mode), -        mTotalTests(0), -        mPassedTests(0), -        mFailedTests(0), -        mSkippedTests(0),          // By default, capture a shared_ptr to std::cout, with a no-op "deleter"          // so that destroying the shared_ptr makes no attempt to delete std::cout.          mStream(std::shared_ptr<std::ostream>(&std::cout, [](std::ostream*){})), @@ -220,6 +207,8 @@ public:      virtual void group_started(const std::string& name) {          LL_INFOS("TestRunner")<<"Unit test group_started name=" << name << LL_ENDL;          *mStream << "Unit test group_started name=" << name << std::endl; +        mGroup = name; +        mGroupTests = 0;          super::group_started(name);      } @@ -232,6 +221,7 @@ public:      virtual void test_completed(const tut::test_result& tr)      {          ++mTotalTests; +        ++mGroupTests;          // If this test failed, dump requested log messages BEFORE stating the          // test result. @@ -319,12 +309,15 @@ public:          super::run_completed();      } +    std::string mGroup; +    int mGroupTests{ 0 }; +  protected: -    bool mVerboseMode; -    int mTotalTests; -    int mPassedTests; -    int mFailedTests; -    int mSkippedTests; +    bool mVerboseMode{ false }; +    int mTotalTests{ 0 }; +    int mPassedTests{ 0 }; +    int mFailedTests{ 0 }; +    int mSkippedTests{ 0 };      std::shared_ptr<std::ostream> mStream;      std::shared_ptr<LLReplayLog> mReplayer;  }; @@ -522,12 +515,6 @@ static LLTrace::ThreadRecorder* sMasterThreadRecorder = NULL;  int main(int argc, char **argv)  { -    // The following line must be executed to initialize Google Mock -    // (and Google Test) before running the tests. -#ifndef LL_WINDOWS -    ::testing::InitGoogleMock(&argc, argv); -#endif -      ll_init_apr();      apr_getopt_t* os = NULL;      if(APR_SUCCESS != apr_getopt_init(&os, gAPRPoolp, argc, argv)) @@ -658,14 +645,47 @@ int main(int argc, char **argv)      // a chained_callback subclass must be linked with previous      mycallback->link(); -    if(test_group.empty()) -    { -        tut::runner.get().run_tests(); -    } -    else -    { -        tut::runner.get().run_tests(test_group); -    } +    LL::seh::catcher( +        // __try +        [test_group] +        { +            if(test_group.empty()) +            { +                tut::runner.get().run_tests(); +            } +            else +            { +                tut::runner.get().run_tests(test_group); +            } +        }, +        // __except +        [mycallback](U32 code, const std::string& /*stacktrace*/) +        { +            static std::map<U32, const char*> codes = { +                { 0xC0000005, "Access Violation" }, +                { 0xC00000FD, "Stack Overflow" }, +                // ... continue filling in as desired +            }; + +            auto found{ codes.find(code) }; +            const char* name = ((found == codes.end())? "unknown" : found->second); +            auto msg{ stringize("test threw ", std::hex, code, " (", name, ")") }; + +            // Instead of bombing the whole test run, report this as a test +            // failure. Arguably, catching structured exceptions should be +            // hacked into TUT itself. +            mycallback->test_completed(tut::test_result( +                mycallback->mGroup, +                mycallback->mGroupTests+1, // test within group +                "unknown",                 // test name +                tut::test_result::ex,      // result: exception +                // we don't have to throw this exception subclass to use it to +                // populate the test_result struct +                Windows_SEH_exception(msg))); +            // we've left the TUT framework -- finish up by hand +            mycallback->group_completed(mycallback->mGroup); +            mycallback->run_completed(); +        });      bool success = (mycallback->getFailedTests() == 0);  | 
