diff options
150 files changed, 6630 insertions, 7190 deletions
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 44f32c1c5d..42dc364ed3 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -11,11 +11,18 @@ jobs: build: strategy: matrix: - runner: [windows-large, macos-12-xl] - configuration: [Release] + runner: [windows-large, macos-12-xl, linux-large] + configuration: [Release, ReleaseOS] include: - runner: macos-12-xl developer_dir: "/Applications/Xcode_14.0.1.app/Contents/Developer" + exclude: + - runner: windows-large + configuration: ReleaseOS + - runner: macos-12-xl + configuration: ReleaseOS + - runner: linux-large + configuration: Release runs-on: ${{ matrix.runner }} outputs: viewer_channel: ${{ steps.build.outputs.viewer_channel }} @@ -91,6 +98,17 @@ 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 + - name: Install windows dependencies if: runner.os == 'Windows' run: choco install nsis-unicode @@ -198,6 +216,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 @@ -219,13 +244,14 @@ jobs: echo "artifact=$RUNNER_OS$cfg_suffix" >> $GITHUB_OUTPUT - name: Upload executable - if: matrix.configuration != 'ReleaseOS' && steps.build.outputs.viewer_app + if: (matrix.configuration != 'ReleaseOS' && 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 @@ -363,7 +389,11 @@ jobs: - uses: actions/download-artifact@v4 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 @@ -392,7 +422,7 @@ jobs: append_body: true fail_on_unmatched_files: true files: | - macOS-installer/*.dmg + macOS-installer/*.dmg Windows-installer/*.exe *-autobuild-package.xml *-viewer_version.txt 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 13c9e7ec35..926d53aee9 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> @@ -455,18 +535,6 @@ </map> <key>emoji_shortcodes</key> <map> - <key>canonical_repo</key> - <string>https://github.com/secondlife/3p-emoji-shortcodes</string> - <key>copyright</key> - <string>Copyright 2017-2019 Miles Johnson.</string> - <key>description</key> - <string>Emoji shortcodes</string> - <key>license</key> - <string>MIT</string> - <key>license_file</key> - <string>LICENSES/emojibase-license.txt</string> - <key>name</key> - <string>emoji_shortcodes</string> <key>platforms</key> <map> <key>darwin64</key> @@ -481,6 +549,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> @@ -494,8 +576,20 @@ <string>windows64</string> </map> </map> + <key>license</key> + <string>MIT</string> + <key>license_file</key> + <string>LICENSES/emojibase-license.txt</string> + <key>copyright</key> + <string>Copyright 2017-2019 Miles Johnson.</string> <key>version</key> <string>6.1.0.579438</string> + <key>name</key> + <string>emoji_shortcodes</string> + <key>canonical_repo</key> + <string>https://github.com/secondlife/3p-emoji-shortcodes</string> + <key>description</key> + <string>Emoji shortcodes</string> </map> <key>expat</key> <map> @@ -623,48 +717,8 @@ <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>copyright</key> - <string>Copyright 2006, 2007, 2008, 2009, 2010 by David Turner, Robert Wilhelm, and Werner Lemberg.</string> - <key>description</key> - <string>Font rendering library</string> - <key>license</key> - <string>FreeType</string> - <key>license_file</key> - <string>LICENSES/freetype.txt</string> - <key>name</key> - <string>freetype</string> <key>platforms</key> <map> <key>darwin64</key> @@ -686,11 +740,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> @@ -724,8 +778,18 @@ <string>windows64</string> </map> </map> + <key>license</key> + <string>FreeType</string> + <key>license_file</key> + <string>LICENSES/freetype.txt</string> + <key>copyright</key> + <string>Copyright 2006, 2007, 2008, 2009, 2010 by David Turner, Robert Wilhelm, and Werner Lemberg.</string> <key>version</key> <string>2.12.1.557becd</string> + <key>name</key> + <string>freetype</string> + <key>description</key> + <string>Font rendering library</string> </map> <key>glext</key> <map> @@ -865,34 +929,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> @@ -917,10 +953,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> @@ -957,18 +997,6 @@ </map> <key>icu4c</key> <map> - <key>canonical_repo</key> - <string>https://bitbucket.org/lindenlab/3p-icu4c</string> - <key>copyright</key> - <string>Copyright (c) 1995-2011 International Business Machines Corporation and others <http://source.icu-project.org></string> - <key>description</key> - <string>ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications. ICU is widely portable and gives applications the same results on all platforms and between C/C++ and Java software.</string> - <key>license</key> - <string>ICU, permissive non-copyleft free software license</string> - <key>license_file</key> - <string>LICENSES/icu.txt</string> - <key>name</key> - <string>icu4c</string> <key>platforms</key> <map> <key>darwin64</key> @@ -999,9 +1027,35 @@ <key>name</key> <string>windows64</string> </map> + <key>linux64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>bdd74e2a02c7b78fded9222140d197da4af9904e</string> + <key>hash_algorithm</key> + <string>sha1</string> + <key>url</key> + <string>https://github.com/secondlife/3p-icu4c/releases/download/v4.8.1-8bff176/icu4c-4.8.1-linux64-8512575562.tar.zst</string> + </map> + <key>name</key> + <string>linux64</string> + </map> </map> + <key>license</key> + <string>ICU, permissive non-copyleft free software license</string> + <key>license_file</key> + <string>LICENSES/icu.txt</string> + <key>copyright</key> + <string>Copyright (c) 1995-2011 International Business Machines Corporation and others <http://source.icu-project.org></string> <key>version</key> <string>4.8.1-7d08d82</string> + <key>name</key> + <string>icu4c</string> + <key>canonical_repo</key> + <string>https://bitbucket.org/lindenlab/3p-icu4c</string> + <key>description</key> + <string>ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications. ICU is widely portable and gives applications the same results on all platforms and between C/C++ and Java software.</string> </map> <key>jpegencoderbasic</key> <map> @@ -1026,11 +1080,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> @@ -1142,11 +1196,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> @@ -1173,7 +1227,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> @@ -1390,9 +1444,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> @@ -1478,11 +1534,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> @@ -1509,7 +1565,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> @@ -1776,6 +1832,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> @@ -1932,18 +2002,6 @@ </map> <key>nanosvg</key> <map> - <key>canonical_repo</key> - <string>https://bitbucket.org/lindenlab/3p-nanosvg</string> - <key>copyright</key> - <string>Copyright (c) 2013-14 Mikko Mononen</string> - <key>description</key> - <string>NanoSVG is a simple single-header-file SVG parser and rasterizer</string> - <key>license</key> - <string>Zlib</string> - <key>license_file</key> - <string>LICENSES/nanosvg.txt</string> - <key>name</key> - <string>nanosvg</string> <key>platforms</key> <map> <key>darwin64</key> @@ -1983,8 +2041,20 @@ <string>windows64</string> </map> </map> + <key>license</key> + <string>Zlib</string> + <key>license_file</key> + <string>LICENSES/nanosvg.txt</string> + <key>copyright</key> + <string>Copyright (c) 2013-14 Mikko Mononen</string> <key>version</key> <string>2022.09.27</string> + <key>name</key> + <string>nanosvg</string> + <key>canonical_repo</key> + <string>https://bitbucket.org/lindenlab/3p-nanosvg</string> + <key>description</key> + <string>NanoSVG is a simple single-header-file SVG parser and rasterizer</string> </map> <key>nghttp2</key> <map> @@ -2104,9 +2174,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> @@ -2133,7 +2205,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> @@ -2141,6 +2213,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> @@ -2148,7 +2237,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> @@ -2163,11 +2252,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> @@ -2357,9 +2446,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> @@ -2386,7 +2477,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> @@ -2477,11 +2568,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> @@ -2580,6 +2671,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> @@ -2694,16 +2799,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> </map> <key>viewer-fonts</key> <map> - <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>description</key> - <string>Viewer fonts</string> - <key>license</key> - <string>Various open source</string> - <key>license_file</key> - <string>LICENSES/fonts.txt</string> - <key>name</key> - <string>viewer-fonts</string> <key>platforms</key> <map> <key>darwin64</key> @@ -2730,9 +2825,33 @@ 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> + <key>license_file</key> + <string>LICENSES/fonts.txt</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> + <string>Viewer fonts</string> </map> <key>viewer-manager</key> <map> @@ -3287,6 +3406,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 @@ -186,6 +202,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" @@ -198,14 +215,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" @@ -238,7 +255,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 ] @@ -311,7 +328,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}" ] @@ -433,7 +450,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 @@ -498,7 +515,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 24534c98d9..2b6129590c 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}") @@ -87,7 +88,7 @@ if (WINDOWS) if( ADDRESS_SIZE EQUAL 32 ) add_compile_options( /arch:SSE2 ) endif() - + # Are we using the crummy Visual Studio KDU build workaround? if (NOT VS_DISABLE_FATAL_WARNINGS) add_compile_options(/WX) @@ -105,51 +106,90 @@ if (WINDOWS) endif() 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 ) - if (ADDRESS_SIZE EQUAL 32) - add_compile_options(-march=pentium4) - endif (ADDRESS_SIZE EQUAL 32) + set(CLANG_WARNINGS + ${GCC_CLANG_COMPATIBLE_WARNINGS} + # Put clang specific warning configuration here + ) + + set(GCC_WARNINGS + ${GCC_CLANG_COMPATIBLE_WARNINGS} + -Wno-dangling-pointer + ) + + 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) @@ -171,20 +211,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 05c51c018d..3a7fe7302e 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 diff --git a/indra/cmake/ConfigurePkgConfig.cmake b/indra/cmake/ConfigurePkgConfig.cmake deleted file mode 100644 index 55d865392e..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 9f79c13a97..9f577bc9bc 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -224,17 +224,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/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/ICU4C.cmake b/indra/cmake/ICU4C.cmake index 7b27665483..8382ceef1e 100644 --- a/indra/cmake/ICU4C.cmake +++ b/indra/cmake/ICU4C.cmake @@ -12,8 +12,8 @@ if (WINDOWS) target_link_libraries( ll::icu4c INTERFACE icuuc) elseif(DARWIN) target_link_libraries( ll::icu4c INTERFACE icuuc) -#elseif(LINUX) -## target_link_libraries( ll::icu4c INTERFACE ) +elseif(LINUX) + target_link_libraries( ll::icu4c INTERFACE ${LIBS_PREBUILT_DIR}/lib/libicuuc.a) else() message(FATAL_ERROR "Invalid platform") endif() 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..6e948c2186 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -1,4 +1,11 @@ # -*- cmake -*- + +include_guard() + +if( NOT LL_TESTS ) + return() +endif() + include(00-Common) include(LLTestCommand) include(GoogleMock) diff --git a/indra/cmake/LLWindow.cmake b/indra/cmake/LLWindow.cmake index b36e970560..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) - - use_system_binary(SDL) - use_prebuilt_binary(SDL) - - target_include_directories( ll::SDL SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include) - target_link_libraries( ll::SDL INTERFACE SDL directfb fusion direct X11) -endif (LINUX) + target_compile_definitions( ll::SDL INTERFACE LL_SDL_VERSION=2 LL_SDL) + #find_package(SDL2 REQUIRED) + #target_link_libraries( ll::SDL INTERFACE SDL2::SDL2 SDL2::SDL2main 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 8b70192efc..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 af1f16d04d..c037d657eb 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -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 4092d43fc5..22182d32a4 100644 --- a/indra/linux_crash_logger/llcrashloggerlinux.cpp +++ b/indra/linux_crash_logger/llcrashloggerlinux.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcrashloggerlinux.cpp * @brief Linux crash logger implementation * * $LicenseInfo:firstyear=2003&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$ */ @@ -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 dab14851c8..79b879b487 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/llerror.h b/indra/llcommon/llerror.h index 6f6b349cf5..a70b5cef3a 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -1,4 +1,4 @@ -/** +/** * @file llerror.h * @date December 2006 * @brief error message system @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&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$ */ @@ -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 @@ -103,12 +108,12 @@ const int LL_ERR_NOERR = 0; /** Error Logging Facility Information for most users: - + Code can log messages with constructions like this: - + LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id << " denied due to timeout" << LL_ENDL; - + Messages can be logged to one of four increasing levels of concern, using one of four "streams": @@ -116,45 +121,45 @@ const int LL_ERR_NOERR = 0; LL_INFOS("StringTag") - informational messages that are normal shown LL_WARNS("StringTag") - warning messages that signal a problem LL_ERRS("StringTag") - error messages that are major, unrecoverable failures - + The later (LL_ERRS("StringTag")) automatically crashes the process after the message is logged. - + Note that these "streams" are actually #define magic. Rules for use: * they cannot be used as normal streams, only to start a message * messages written to them MUST be terminated with LL_ENDL * between the opening and closing, the << operator is indeed writing onto a std::ostream, so all conversions and stream formating are available - + These messages are automatically logged with function name, and (if enabled) file and line of the message. (Note: Existing messages that already include the function name don't get name printed twice.) - + If you have a class, adding LOG_CLASS line to the declaration will cause all messages emitted from member functions (normal and static) to be tagged with the proper class name as well as the function name: - + class LLFoo { LOG_CLASS(LLFoo); public: ... }; - + void LLFoo::doSomething(int i) { if (i > 100) { - LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL; + LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL; } ... } - + will result in messages like: - + WARN #FooBarTag# llcommon/llfoo(100) LLFoo::doSomething : called with a big value for i: 283 - + the syntax is: <timestamp> SPACE <level> SPACE <tags> SPACE <location> SPACE <function> SPACE COLON SPACE <message> @@ -169,7 +174,7 @@ const int LL_ERR_NOERR = 0; A copy of that file named logcontrol-dev.xml can be made in the users personal settings directory; that will override the installed default file. See the logcontrol.xml file or http://wiki.secondlife.com/wiki/Logging_System_Overview for configuration details. - + Lastly, logging is now very efficient in both compiled code and execution when skipped. There is no need to wrap messages, even debugging ones, in #ifdef _DEBUG constructs. LL_DEBUGS("StringTag") messages are compiled into all builds, @@ -182,12 +187,12 @@ namespace LLError { LEVEL_ALL = 0, // used to indicate that all messages should be logged - + LEVEL_DEBUG = 0, LEVEL_INFO = 1, LEVEL_WARN = 2, LEVEL_ERROR = 3, // used to be called FATAL - + LEVEL_NONE = 4 // not really a level // used to indicate that no messages should be logged @@ -223,13 +228,13 @@ namespace LLError // Represents a specific place in the code where a message is logged // This is public because it is used by the macros below. It is not // intended for public use. - CallSite(ELevel level, - const char* file, + CallSite(ELevel level, + const char* file, int line, - const std::type_info& class_info, - const char* function, - bool print_once, - const char** tags, + const std::type_info& class_info, + const char* function, + bool print_once, + const char** tags, size_t tag_count); ~CallSite(); @@ -238,16 +243,16 @@ namespace LLError bool shouldLog(); #else // LL_LIBRARY_INCLUDE bool shouldLog() - { - return mCached - ? mShouldLog - : Log::shouldLog(*this); + { + return mCached + ? mShouldLog + : Log::shouldLog(*this); } // this member function needs to be in-line for efficiency #endif // LL_LIBRARY_INCLUDE - + void invalidate(); - + // these describe the call site and never change const ELevel mLevel; const char* const mFile; @@ -263,22 +268,22 @@ namespace LLError mTagString; bool mCached, mShouldLog; - + friend class Log; }; - - + + class End { }; inline std::ostream& operator<<(std::ostream& s, const End&) { return s; } // used to indicate the end of a message - + class LL_COMMON_API NoClassInfo { }; // used to indicate no class info known for logging //LLCallStacks keeps track of call stacks and output the call stacks to log file // - //Note: to be simple, efficient and necessary to keep track of correct call stacks, + //Note: to be simple, efficient and necessary to keep track of correct call stacks, //LLCallStacks is designed not to be thread-safe. //so try not to use it in multiple parallel threads at same time. //Used in a single thread at a time is fine. @@ -287,8 +292,8 @@ namespace LLError private: typedef std::vector<std::string> StringVector; static StringVector sBuffer ; - - public: + + public: static void push(const char* function, const int line) ; static void insert(std::ostream& out, const char* function, const int line) ; static void print() ; @@ -326,7 +331,7 @@ namespace LLError }; } -//this is cheaper than llcallstacks if no need to output other variables to call stacks. +//this is cheaper than llcallstacks if no need to output other variables to call stacks. #define LL_PUSH_CALLSTACKS() LLError::LLCallStacks::push(__FUNCTION__, __LINE__) #define llcallstacks \ @@ -341,7 +346,7 @@ namespace LLError } #define LL_CLEAR_CALLSTACKS() LLError::LLCallStacks::clear() -#define LL_PRINT_CALLSTACKS() LLError::LLCallStacks::print() +#define LL_PRINT_CALLSTACKS() LLError::LLCallStacks::print() /* Class type information for logging @@ -350,7 +355,7 @@ namespace LLError #define LOG_CLASS(s) typedef s _LL_CLASS_TO_LOG // Declares class to tag logged messages with. // See top of file for example of how to use this - + typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; // Outside a class declaration, or in class without LOG_CLASS(), this // typedef causes the messages to not be associated with any class. @@ -392,7 +397,7 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; //Use this construct if you need to do computation in the middle of a //message: -// +// // LL_INFOS("AgentGesture") << "the agent " << agend_id; // switch (f) // { @@ -401,17 +406,23 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; // case FOP_SAYS: LL_CONT << "says " << message; break; // } // LL_CONT << " for " << t << " seconds" << LL_ENDL; -// +// //Such computation is done iff the message will be logged. #define LL_CONT _out #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(); \ @@ -510,7 +521,7 @@ LL_ENDL; LL_DEBUGS("SomeTag") performs the locking and map-searching ONCE, then caches the result in a static variable. -*/ +*/ // used by LLERROR_CRASH void crashdriver(void (*)(int*)); diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 28f8bc2b93..4cdc3d7519 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() - { - get_proc_cpuinfo(); - } + LLProcessorInfoLinuxImpl() { + get_proc_cpuinfo(); + } + + virtual ~LLProcessorInfoLinuxImpl() {} - 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,31 +870,24 @@ 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 mhz; - if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz) - && 200.0 < mhz && mhz < 10000.0) - { - setInfo(eFrequency,(F64)(mhz)); - } + F64 mhzFromSys = getCPUMaxMHZ(); + F64 mhzFromProc {}; + if( !LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhzFromProc ) ) + mhzFromProc = 0.0; + if (mhzFromSys > 1.0 && mhzFromSys > mhzFromProc ) + { + setInfo( eFrequency, mhzFromSys ); + } + else if ( 200.0 < mhzFromProc && mhzFromProc < 10000.0) + { + setInfo(eFrequency,(F64)(mhzFromProc)); + } LLPI_SET_INFO_STRING(eBrandName, "model name"); LLPI_SET_INFO_STRING(eVendor, "vendor_id"); @@ -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 e98fc0285a..4d5fb0d818 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsdutil.cpp * @author Phoenix * @date 2006-05-24 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&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$ */ @@ -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); @@ -324,7 +324,7 @@ BOOL compare_llsd_with_template( return TRUE; } -// filter_llsd_with_template() is a direct clone (copy-n-paste) of +// filter_llsd_with_template() is a direct clone (copy-n-paste) of // compare_llsd_with_template with the following differences: // (1) bool vs BOOL return types // (2) A map with the key value "*" is a special value and maps any key in the @@ -386,7 +386,7 @@ bool filter_llsd_with_template( else { // Traditional compare_llsd_with_template matching - + for (template_iter = template_llsd.beginArray(); template_iter != template_llsd.endArray() && test_iter != llsd_to_test.endArray(); @@ -417,7 +417,7 @@ bool filter_llsd_with_template( else if (llsd_to_test.isMap()) { resultant_llsd = LLSD::emptyMap(); - + //now we loop over the keys of the two maps //any excess is taken from the template //excess is ignored in the test @@ -464,7 +464,7 @@ bool filter_llsd_with_template( { LLSD sub_value; LLSD::map_const_iterator test_iter; - + for (test_iter = llsd_to_test.beginMap(); test_iter != llsd_to_test.endMap(); ++test_iter) @@ -944,9 +944,9 @@ LLSD drill(const LLSD& blob, const LLSD& path) } // namespace llsd -// Construct a deep partial clone of of an LLSD object. primitive types share +// Construct a deep partial clone of of an LLSD object. primitive types share // references, however maps, arrays and binary objects are duplicated. An optional -// filter may be include to exclude/include keys in a map. +// filter may be include to exclude/include keys in a map. LLSD llsd_clone(LLSD value, LLSD filter) { LL_PROFILE_ZONE_SCOPED diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 42400e90af..e53c82ad2b 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsys.cpp * @brief Implementation of the basic system query functions. * * $LicenseInfo:firstyear=2002&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$ */ @@ -96,7 +96,7 @@ static const F32 MEM_INFO_THROTTLE = 20; static const F32 MEM_INFO_WINDOW = 10*60; LLOSInfo::LLOSInfo() : - mMajorVer(0), mMinorVer(0), mBuild(0), mOSVersionString("") + mMajorVer(0), mMinorVer(0), mBuild(0), mOSVersionString("") { #if LL_WINDOWS @@ -186,7 +186,7 @@ LLOSInfo::LLOSInfo() : if (NULL != pGNSI) //check if it has failed pGNSI(&si); //success else - GetSystemInfo(&si); //if it fails get regular system info + GetSystemInfo(&si); //if it fails get regular system info //(Warning: If GetSystemInfo it may result in incorrect information in a WOW64 machine, if the kernel fails to load) // Try calling GetVersionEx using the OSVERSIONINFOEX structure. @@ -266,12 +266,12 @@ LLOSInfo::LLOSInfo() : LLStringUtil::trim(mOSString); #elif LL_DARWIN - + // Initialize mOSStringSimple to something like: // "Mac OS X 10.6.7" { const char * DARWIN_PRODUCT_NAME = "Mac OS X"; - + int64_t major_version, minor_version, bugfix_version = 0; if (LLGetDarwinOSInfo(major_version, minor_version, bugfix_version)) @@ -282,7 +282,7 @@ LLOSInfo::LLOSInfo() : std::stringstream os_version_string; os_version_string << DARWIN_PRODUCT_NAME << " " << mMajorVer << "." << mMinorVer << "." << mBuild; - + // Put it in the OS string we are compiling mOSStringSimple.append(os_version_string.str()); } @@ -291,12 +291,12 @@ LLOSInfo::LLOSInfo() : mOSStringSimple.append("Unable to collect OS info"); } } - + // Initialize mOSString to something like: // "Mac OS X 10.6.7 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386" struct utsname un; if(uname(&un) != -1) - { + { mOSString = mOSStringSimple; mOSString.append(" "); mOSString.append(un.sysname); @@ -311,9 +311,9 @@ LLOSInfo::LLOSInfo() : { mOSString = mOSStringSimple; } - + #elif LL_LINUX - + struct utsname un; if(uname(&un) != -1) { @@ -353,7 +353,7 @@ LLOSInfo::LLOSInfo() : if ( ll_regex_match(glibc_version, matched, os_version_parse) ) { LL_INFOS("AppInit") << "Using glibc version '" << glibc_version << "' as OS version" << LL_ENDL; - + std::string version_value; if ( matched[1].matched ) // Major version @@ -367,7 +367,7 @@ LLOSInfo::LLOSInfo() : else { LL_ERRS("AppInit") - << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION + << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION << "' returned true, but major version [1] did not match" << LL_ENDL; } @@ -383,7 +383,7 @@ LLOSInfo::LLOSInfo() : else { LL_ERRS("AppInit") - << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION + << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION << "' returned true, but minor version [1] did not match" << LL_ENDL; } @@ -409,7 +409,7 @@ LLOSInfo::LLOSInfo() : } #else - + struct utsname un; if(uname(&un) != -1) { @@ -509,57 +509,46 @@ const S32 LLOSInfo::getOSBitness() const return mOSBitness; } -//static -U32 LLOSInfo::getProcessVirtualSizeKB() -{ - U32 virtual_size = 0; +namespace { + + U32 readFromProcStat( std::string entryName ) + { + U32 val{}; #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 */ + constexpr U32 STATUS_SIZE = 2048; - size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); - buff[nbytes] = '\0'; + LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); + if (status_filep) + { + char buff[STATUS_SIZE]; /* Flawfinder: ignore */ - // All these guys return numbers in KB - char *memp = strstr(buff, "VmSize:"); - if (memp) - { - numRead += sscanf(memp, "%*s %u", &virtual_size); - } - fclose(status_filep); - } + 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); + } #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 @@ -577,7 +566,7 @@ bool LLOSInfo::is64Bit() #endif #else // ! LL_WINDOWS // we only build a 64-bit mac viewer and currently we don't build for linux at all - return true; + return true; #endif } @@ -1001,11 +990,11 @@ LLSD LLMemoryInfo::loadStatsMap() #elif LL_DARWIN const vm_size_t pagekb(vm_page_size / 1024); - + // // Collect the vm_stat's // - + { vm_statistics64_data_t vmstat; mach_msg_type_number_t vmstatCount = HOST_VM_INFO64_COUNT; @@ -1025,16 +1014,16 @@ LLSD LLMemoryInfo::loadStatsMap() stats.add("Page reactivations", vmstat.reactivations); stats.add("Page-ins", vmstat.pageins); stats.add("Page-outs", vmstat.pageouts); - + stats.add("Faults", vmstat.faults); stats.add("Faults copy-on-write", vmstat.cow_faults); - + stats.add("Cache lookups", vmstat.lookups); stats.add("Cache hits", vmstat.hits); - + stats.add("Page purgeable count", vmstat.purgeable_count); stats.add("Page purges", vmstat.purges); - + stats.add("Page speculative reads", vmstat.speculative_count); } } @@ -1046,7 +1035,7 @@ LLSD LLMemoryInfo::loadStatsMap() { task_events_info_data_t taskinfo; unsigned taskinfoSize = sizeof(taskinfo); - + if (task_info(mach_task_self(), TASK_EVENTS_INFO, (task_info_t) &taskinfo, &taskinfoSize) != KERN_SUCCESS) { LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL; @@ -1061,8 +1050,8 @@ LLSD LLMemoryInfo::loadStatsMap() stats.add("Task unix system call count", taskinfo.syscalls_unix); stats.add("Task context switch count", taskinfo.csw); } - } - + } + // // Collect the basic task info // @@ -1348,8 +1337,8 @@ BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile) goto err; } } while(gzeof(src) == 0); - fclose(dst); - dst = NULL; + fclose(dst); + dst = NULL; if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */ retval = TRUE; err: 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 fd59daad3d..d7011e416b 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -166,7 +166,7 @@ bool ImageRequest::processRequest() { return true; // done (failed) } - if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents())) + if (0 == (mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents())) { return true; // done (failed) } diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index 6c06c6de38..d0351a553c 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 dff5bf3af3..663764ce04 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 c51883ee3d..97b2d3aa5f 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 749e599c66..17f0d9f345 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/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/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 2c357e1ac5..de305ba15f 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -63,7 +63,7 @@ #include <boost/regex.hpp> #include <boost/algorithm/string/replace.hpp> -std::string colladaVersion[VERSIONTYPE_COUNT+1] = +std::string colladaVersion[VERSIONTYPE_COUNT+1] = { "1.4.0", "1.4.1", @@ -1117,22 +1117,20 @@ bool LLDAELoader::OpenFile(const std::string& filename) { //add skinned meshes as instances domSkin* skin = NULL; db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); - + 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 7b0d2632aa..9c7a7c29fc 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] ); - - for (std::vector<LLVolumeFace>::iterator faceIt = mVolumeFaces.begin(); faceIt != mVolumeFaces.end(); ) + LLVector4a pivot(pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ]); + + 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 040257e00e..4700a82ab5 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 fc826727e1..e35aa0572f 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 fbc74554a0..0c766e0b53 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 f4f08248b8..35da0794e2 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 d87fb5245c..f9363fe5a8 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfontfreetype.cpp * @brief Freetype font library wrapper * * $LicenseInfo:firstyear=2002&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$ */ @@ -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; @@ -63,7 +65,7 @@ FT_Library gFTLibrary = NULL; //static void LLFontManager::initClass() { - if (!gFontManagerp) + if (!gFontManagerp) { gFontManagerp = new LLFontManager; } @@ -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, @@ -196,7 +198,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v FT_Done_Face(mFTFace); mFTFace = NULL; } - + int error; #ifdef LL_WINDOWS error = ftOpenFace(filename, face_n); @@ -294,7 +296,7 @@ S32 LLFontFreetype::getNumFaces(const std::string& filename) #ifdef LL_WINDOWS int error = ftOpenFace(filename, 0); - + if (error) { return 0; @@ -303,7 +305,7 @@ S32 LLFontFreetype::getNumFaces(const std::string& filename) { num_faces = mFTFace->num_faces; } - + FT_Done_Face(mFTFace); clearFontStreams(); mFTFace = NULL; @@ -490,9 +492,9 @@ LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type } } } - + std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); - char_glyph_info_map_t::iterator iter = + char_glyph_info_map_t::iterator iter = std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; }); if (iter == range_it.second) { @@ -609,7 +611,7 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l } else { llassert(false); } - + LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_glyph_type, bitmap_num); LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_glyph_type, bitmap_num); image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight()); @@ -683,7 +685,7 @@ void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) co void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi) { - resetBitmapCache(); + resetBitmapCache(); loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mIsFallback, 0); if (!mIsFallback) { @@ -713,7 +715,7 @@ void LLFontFreetype::resetBitmapCache() mCharGlyphInfoMap.clear(); mFontBitmapCachep->reset(); - // Adding default glyph is skipped for fallback fonts here as well as in loadFace(). + // Adding default glyph is skipped for fallback fonts here as well as in loadFace(). // This if was added as fix for EXT-4971. if(!mIsFallback) { @@ -810,7 +812,7 @@ void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 llassert(!mIsFallback); llassert(image_raw && (image_raw->getComponents() == 2)); - + U8 *target = image_raw->getData(); llassert(target); diff --git a/indra/llrender/llfontfreetypesvg.cpp b/indra/llrender/llfontfreetypesvg.cpp index 19d327a4c9..6c44fdd150 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 b5f541991a..26a533682e 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 a4a56af981..53b65a5b99 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -1,30 +1,30 @@ -/** +/** * @file llgl.cpp * @brief LLGL implementation * * $LicenseInfo:firstyear=2001&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$ */ -// This file sets some global GL parameters, and implements some +// This file sets some global GL parameters, and implements some // useful functions for GL operations. #define GLH_EXT_SINGLE_FILE @@ -178,7 +178,7 @@ void ll_init_fail_log(std::string filename) void ll_fail(std::string msg) { - + if (gDebugSession) { std::vector<std::string> lines; @@ -188,7 +188,7 @@ void ll_fail(std::string msg) gFailLog << "Stack Trace:" << std::endl; ll_get_stack_trace(lines); - + for(size_t i = 0; i < lines.size(); ++i) { gFailLog << lines[i] << std::endl; @@ -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; @@ -1003,7 +999,7 @@ LLGLManager::LLGLManager() : mDriverVersionRelease(0), mGLVersion(1.0f), mGLSLVersionMajor(0), - mGLSLVersionMinor(0), + mGLSLVersionMinor(0), mVRAM(0), mGLMaxVertexRange(0), mGLMaxIndexRange(0) @@ -1030,7 +1026,7 @@ void LLGLManager::initWGL() LL_WARNS("RenderInit") << "No ARB create context extensions" << LL_ENDL; } - // For retreiving information per AMD adapter, + // For retreiving information per AMD adapter, // because we can't trust curently selected/default one when there are multiple mHasAMDAssociations = ExtensionExists("WGL_AMD_gpu_association", gGLHExts.mSysExts); if (mHasAMDAssociations) @@ -1083,7 +1079,7 @@ bool LLGLManager::initGL() str << ext << " "; LL_DEBUGS("GLExtensions") << ext << LL_ENDL; } - + { PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0; wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); @@ -1098,7 +1094,7 @@ bool LLGLManager::initGL() gGLHExts.mSysExts = strdup(extensions.c_str()); } #endif - + // Extract video card strings and convert to upper case to // work around driver-to-driver variation in capitalization. mGLVendor = ll_safe_string((const char *)glGetString(GL_VENDOR)); @@ -1107,9 +1103,9 @@ bool LLGLManager::initGL() mGLRenderer = ll_safe_string((const char *)glGetString(GL_RENDERER)); LLStringUtil::toUpper(mGLRenderer); - parse_gl_version( &mDriverVersionMajor, - &mDriverVersionMinor, - &mDriverVersionRelease, + parse_gl_version( &mDriverVersionMajor, + &mDriverVersionMinor, + &mDriverVersionRelease, &mDriverVersionVendorString, &mGLVersionString); @@ -1139,7 +1135,7 @@ bool LLGLManager::initGL() { //GL version is < 3.0, always disable texture compression LLImageGL::sCompressTextures = false; } - + // Trailing space necessary to keep "nVidia Corpor_ati_on" cards // from being recognized as ATI. // NOTE: AMD has been pretty good about not breaking this check, do not rename without good reason @@ -1169,7 +1165,7 @@ bool LLGLManager::initGL() { mGLVendorShort = "MISC"; } - + // This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture. initExtensions(); @@ -1293,12 +1289,12 @@ std::string LLGLManager::getGLInfoString() info_str += std::string("GL_VERSION ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n"); } -#if !LL_MESA_HEADLESS +#if !LL_MESA_HEADLESS std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts)); LLStringUtil::replaceChar(all_exts, ' ', '\n'); info_str += std::string("GL_EXTENSIONS:\n") + all_exts + std::string("\n"); #endif - + return info_str; } @@ -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{""}; @@ -1398,9 +1397,9 @@ void LLGLManager::initExtensions() #endif // NOTE: version checks against mGLVersion should bias down by 0.01 because of F32 errors - + // OpenGL 4.x capabilities - mHasCubeMapArray = mGLVersion >= 3.99f; + mHasCubeMapArray = mGLVersion >= 3.99f; mHasTransformFeedback = mGLVersion >= 3.99f; mHasDebugOutput = mGLVersion >= 4.29f; @@ -1411,10 +1410,9 @@ void LLGLManager::initExtensions() mInited = TRUE; -#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS - LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL; - #if LL_WINDOWS + LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL; + // 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 @@ -2249,7 +2245,7 @@ void LLGLManager::initExtensions() glMultiDrawArraysIndirectCount = (PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiDrawArraysIndirectCount"); glMultiDrawElementsIndirectCount = (PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiDrawElementsIndirectCount"); glPolygonOffsetClamp = (PFNGLPOLYGONOFFSETCLAMPPROC)GLH_EXT_GET_PROC_ADDRESS("glPolygonOffsetClamp"); - + #endif } @@ -2272,7 +2268,7 @@ void log_glerror() { return ; } - // Create or update texture to be used with this data + // Create or update texture to be used with this data GLenum error; error = glGetError(); while (LL_UNLIKELY(error)) @@ -2280,7 +2276,7 @@ void log_glerror() GLubyte const * gl_error_msg = gluErrorString(error); if (NULL != gl_error_msg) { - LL_WARNS() << "GL Error: " << error << " GL Error String: " << gl_error_msg << LL_ENDL ; + LL_WARNS() << "GL Error: " << error << " GL Error String: " << gl_error_msg << LL_ENDL ; } else { @@ -2294,7 +2290,7 @@ void log_glerror() void do_assert_glerror() { - // Create or update texture to be used with this data + // Create or update texture to be used with this data GLenum error; error = glGetError(); BOOL quit = FALSE; @@ -2351,7 +2347,7 @@ void assert_glerror() } */ - if (!gDebugGL) + if (!gDebugGL) { //funny looking if for branch prediction -- gDebugGL is almost always false and assert_glerror is called often } @@ -2360,7 +2356,7 @@ void assert_glerror() do_assert_glerror(); } } - + void clear_glerror() { @@ -2381,11 +2377,11 @@ GLenum LLGLDepthTest::sDepthFunc = GL_LESS; // OpenGL default GLboolean LLGLDepthTest::sWriteEnabled = GL_TRUE; // OpenGL default //static -void LLGLState::initClass() +void LLGLState::initClass() { sStateMap[GL_DITHER] = GL_TRUE; // sStateMap[GL_TEXTURE_2D] = GL_TRUE; - + //make sure multisample defaults to disabled sStateMap[GL_MULTISAMPLE] = GL_FALSE; glDisable(GL_MULTISAMPLE); @@ -2404,7 +2400,7 @@ void LLGLState::resetTextureStates() { gGL.flush(); GLint maxTextureUnits; - + glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextureUnits); for (S32 j = maxTextureUnits-1; j >=0; j--) { @@ -2414,7 +2410,7 @@ void LLGLState::resetTextureStates() } } -void LLGLState::dumpStates() +void LLGLState::dumpStates() { LL_INFOS("RenderState") << "GL States:" << LL_ENDL; for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); @@ -2437,15 +2433,15 @@ void LLGLState::checkStates(GLboolean writeAlpha) glGetIntegerv(GL_BLEND_DST, &dst); llassert_always(src == GL_SRC_ALPHA); llassert_always(dst == GL_ONE_MINUS_SRC_ALPHA); - + // disable for now until usage is consistent //GLboolean colorMask[4]; //glGetBooleanv(GL_COLOR_WRITEMASK, colorMask); //llassert_always(colorMask[0]); //llassert_always(colorMask[1]); //llassert_always(colorMask[2]); - // llassert_always(colorMask[3] == writeAlpha); - + // llassert_always(colorMask[3] == writeAlpha); + for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); iter != sStateMap.end(); ++iter) { @@ -2499,7 +2495,7 @@ void LLGLState::setEnabled(S32 enabled) mIsEnabled = enabled; } -LLGLState::~LLGLState() +LLGLState::~LLGLState() { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; if (mState) @@ -2548,7 +2544,7 @@ void LLGLManager::initGLStates() void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string ) { - // GL_VERSION returns a null-terminated string with the format: + // GL_VERSION returns a null-terminated string with the format: // <major>.<minor>[.<release>] [<vendor specific>] const char* version = (const char*) glGetString(GL_VERSION); @@ -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); @@ -2631,13 +2628,13 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor void parse_glsl_version(S32& major, S32& minor) { - // GL_SHADING_LANGUAGE_VERSION returns a null-terminated string with the format: + // GL_SHADING_LANGUAGE_VERSION returns a null-terminated string with the format: // <major>.<minor>[.<release>] [<vendor specific>] const char* version = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION); major = 0; minor = 0; - + if( !version ) { return; @@ -2706,7 +2703,7 @@ void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d) { glh::matrix4f& P = mProjection; glh::matrix4f& M = mModelview; - + glh::matrix4f invtrans_MVP = (P * M).inverse().transpose(); glh::vec4f oplane(a,b,c,d); glh::vec4f cplane; @@ -2737,7 +2734,7 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G : mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled) { stop_glerror(); - + checkState(); if (!depth_enabled) @@ -2860,7 +2857,7 @@ LLGLSquashToFarClip::~LLGLSquashToFarClip() } - + LLGLSyncFence::LLGLSyncFence() { mSync = 0; @@ -2910,7 +2907,7 @@ void LLGLSyncFence::wait() LLGLSPipelineSkyBox::LLGLSPipelineSkyBox() : mCullFace(GL_CULL_FACE) , mSquashClip() -{ +{ } LLGLSPipelineSkyBox::~LLGLSPipelineSkyBox() @@ -2925,20 +2922,18 @@ LLGLSPipelineDepthTestSkyBox::LLGLSPipelineDepthTestSkyBox(bool depth_test, bool } LLGLSPipelineBlendSkyBox::LLGLSPipelineBlendSkyBox(bool depth_test, bool depth_write) -: LLGLSPipelineDepthTestSkyBox(depth_test, depth_write) +: LLGLSPipelineDepthTestSkyBox(depth_test, depth_write) , mBlend(GL_BLEND) -{ +{ gGL.setSceneBlendType(LLRender::BT_ALPHA); } #if LL_WINDOWS // Expose desired use of high-performance graphics processor to Optimus driver and to AMD driver // https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm -extern "C" -{ +extern "C" +{ __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; } #endif - - diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index b80680a3d2..fe7625236d 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 ccfb8f69be..8749976921 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 34720ff64e..f55e0a0819 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llkeyboard.cpp * @brief Handler for assignable key bindings * * $LicenseInfo:firstyear=2001&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$ */ @@ -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 // @@ -122,7 +121,7 @@ LLKeyboard::LLKeyboard() : mCallbacks(NULL) addKeyName(KEY_BUTTON13, "PAD_BUTTON13" ); addKeyName(KEY_BUTTON14, "PAD_BUTTON14" ); addKeyName(KEY_BUTTON15, "PAD_BUTTON15" ); - + addKeyName(KEY_BACKSPACE, "Backsp" ); addKeyName(KEY_DELETE, "Del" ); addKeyName(KEY_SHIFT, "Shift" ); @@ -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; @@ -250,7 +246,7 @@ BOOL LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask repeated = TRUE; mKeyRepeated[translated_key] = TRUE; } - + mKeyDown[translated_key] = TRUE; mCurTranslatedKey = (KEY)translated_key; handled = mCallbacks->handleTranslatedKeyDown(translated_key, translated_mask, repeated); @@ -259,12 +255,12 @@ BOOL LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask BOOL LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask) -{ +{ BOOL handled = FALSE; if( mKeyLevel[translated_key] ) { mKeyLevel[translated_key] = FALSE; - + // Only generate key up events if the key is thought to // be down. This allows you to call resetKeys() in the // middle of a frame and ignore subsequent KEY_UP @@ -273,7 +269,7 @@ BOOL LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask) mKeyUp[translated_key] = TRUE; handled = mCallbacks->handleTranslatedKeyUp(translated_key, translated_mask); } - + LL_DEBUGS("UserInput") << "keyup -" << translated_key << "-" << LL_ENDL; return handled; @@ -451,13 +447,13 @@ std::string LLKeyboard::stringFromAccelerator(MASK accel_mask) std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key ) { std::string res; - + // break early if this is a silly thing to do. if( KEY_NONE == key ) { return res; } - + res.append(stringFromAccelerator(accel_mask)); std::string key_string = LLKeyboard::stringFromKey(key); if ((accel_mask & MASK_NORMALKEYS) && @@ -468,7 +464,7 @@ std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key ) std::string keystr = stringFromKey( key ); res.append( keystr ); - + return res; } @@ -529,7 +525,7 @@ BOOL LLKeyboard::maskFromString(const std::string& str, MASK *mask) *mask = MASK_CONTROL | MASK_ALT | MASK_SHIFT; return TRUE; } - else + else { return FALSE; } diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index dad150e3c1..2c96df3b5b 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -1,25 +1,25 @@ -/** +/** * @file llkeyboard.h * @brief Handler for assignable key bindings * * $LicenseInfo:firstyear=2001&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$ */ @@ -34,7 +34,7 @@ #include "lltimer.h" #include "indra_constants.h" -enum EKeystate +enum EKeystate { KEYSTATE_DOWN, KEYSTATE_LEVEL, @@ -43,7 +43,7 @@ enum EKeystate typedef boost::function<bool(EKeystate keystate)> LLKeyFunc; typedef std::string (LLKeyStringTranslatorFunc)(const char *label); - + enum EKeyboardInsertMode { LL_KIM_INSERT, @@ -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,15 +72,14 @@ 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 NATIVE_KEY_TYPE key, MASK mask) = 0; + virtual BOOL handleKeyDown(const NATIVE_KEY_TYPE key, MASK mask) = 0; - virtual BOOL handleKeyUp(const U16 key, MASK mask) = 0; - virtual BOOL handleKeyDown(const U16 key, MASK mask) = 0; - #ifdef LL_DARWIN // We only actually use this for OS X. virtual void handleModifier(MASK mask) = 0; @@ -106,13 +110,13 @@ public: S32 getKeyElapsedFrameCount( KEY key ); // Returns time in frames since key was pressed. static void setStringTranslatorFunc( LLKeyStringTranslatorFunc *trans_func ); - + 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 @@ -125,7 +129,7 @@ protected: KEY mCurScanKey; // Used during the scanKeyboard() static LLKeyStringTranslatorFunc* mStringTranslator; // Used for l10n + PC/Mac/Linux accelerator labeling - + EKeyboardInsertMode mInsertMode; static std::map<KEY,std::string> sKeysToNames; diff --git a/indra/llwindow/llkeyboardheadless.cpp b/indra/llwindow/llkeyboardheadless.cpp index a1b6b294e0..0785410357 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 8ed28ace90..79c276fdbb 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 7c9aa1d340..b29b832011 100644 --- a/indra/llwindow/llkeyboardsdl.cpp +++ b/indra/llwindow/llkeyboardsdl.cpp @@ -1,324 +1,661 @@ -/** - * @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 * 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_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() { - // Set up key mapping for SDL - eventually can read this from a file? - // Anything not in the key map gets dropped - // Add default A-Z - - // Virtual key mappings from SDL_keysym.h ... - - // SDL maps the letter keys to the ASCII you'd expect, but it's lowercase... - U16 cur_char; - for (cur_char = 'A'; cur_char <= 'Z'; cur_char++) - { - mTranslateKeyMap[cur_char] = cur_char; - } - for (cur_char = 'a'; cur_char <= 'z'; cur_char++) - { - mTranslateKeyMap[cur_char] = (cur_char - 'a') + 'A'; - } - - for (cur_char = '0'; cur_char <= '9'; cur_char++) - { - mTranslateKeyMap[cur_char] = cur_char; - } - - // These ones are translated manually upon keydown/keyup because - // SDL doesn't handle their numlock transition. - //mTranslateKeyMap[SDLK_KP4] = KEY_PAD_LEFT; - //mTranslateKeyMap[SDLK_KP6] = KEY_PAD_RIGHT; - //mTranslateKeyMap[SDLK_KP8] = KEY_PAD_UP; - //mTranslateKeyMap[SDLK_KP2] = KEY_PAD_DOWN; - //mTranslateKeyMap[SDLK_KP_PERIOD] = KEY_DELETE; - //mTranslateKeyMap[SDLK_KP7] = KEY_HOME; - //mTranslateKeyMap[SDLK_KP1] = KEY_END; - //mTranslateKeyMap[SDLK_KP9] = KEY_PAGE_UP; - //mTranslateKeyMap[SDLK_KP3] = KEY_PAGE_DOWN; - //mTranslateKeyMap[SDLK_KP0] = KEY_INSERT; - - mTranslateKeyMap[SDLK_SPACE] = ' '; - 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; - mTranslateKeyMap[SDLK_DELETE] = KEY_DELETE; - mTranslateKeyMap[SDLK_LSHIFT] = KEY_SHIFT; - mTranslateKeyMap[SDLK_RSHIFT] = KEY_SHIFT; - mTranslateKeyMap[SDLK_LCTRL] = KEY_CONTROL; - mTranslateKeyMap[SDLK_RCTRL] = KEY_CONTROL; - mTranslateKeyMap[SDLK_LALT] = KEY_ALT; - mTranslateKeyMap[SDLK_RALT] = KEY_ALT; - mTranslateKeyMap[SDLK_HOME] = KEY_HOME; - mTranslateKeyMap[SDLK_END] = KEY_END; - mTranslateKeyMap[SDLK_PAGEUP] = KEY_PAGE_UP; - mTranslateKeyMap[SDLK_PAGEDOWN] = KEY_PAGE_DOWN; - mTranslateKeyMap[SDLK_MINUS] = KEY_HYPHEN; - mTranslateKeyMap[SDLK_EQUALS] = KEY_EQUALS; - mTranslateKeyMap[SDLK_KP_EQUALS] = KEY_EQUALS; - mTranslateKeyMap[SDLK_INSERT] = KEY_INSERT; - mTranslateKeyMap[SDLK_CAPSLOCK] = KEY_CAPSLOCK; - mTranslateKeyMap[SDLK_TAB] = KEY_TAB; - mTranslateKeyMap[SDLK_KP_PLUS] = KEY_ADD; - mTranslateKeyMap[SDLK_KP_MINUS] = KEY_SUBTRACT; - mTranslateKeyMap[SDLK_KP_MULTIPLY] = KEY_MULTIPLY; - mTranslateKeyMap[SDLK_KP_DIVIDE] = KEY_PAD_DIVIDE; - mTranslateKeyMap[SDLK_F1] = KEY_F1; - mTranslateKeyMap[SDLK_F2] = KEY_F2; - mTranslateKeyMap[SDLK_F3] = KEY_F3; - mTranslateKeyMap[SDLK_F4] = KEY_F4; - mTranslateKeyMap[SDLK_F5] = KEY_F5; - mTranslateKeyMap[SDLK_F6] = KEY_F6; - mTranslateKeyMap[SDLK_F7] = KEY_F7; - mTranslateKeyMap[SDLK_F8] = KEY_F8; - mTranslateKeyMap[SDLK_F9] = KEY_F9; - 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] = '\''; - - // Build inverse map - std::map<U16, KEY>::iterator iter; - for (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_PERIOD] = KEY_PAD_DEL; - - // build inverse numpad map - for (iter = mTranslateNumpadMap.begin(); - iter != mTranslateNumpadMap.end(); - iter++) - { - mInvTranslateNumpadMap[iter->second] = iter->first; - } + // Set up key mapping for SDL - eventually can read this from a file? + // Anything not in the key map gets dropped + // Add default A-Z + + // 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++) + { + mTranslateKeyMap[cur_char] = cur_char; + } + for (cur_char = 'a'; cur_char <= 'z'; cur_char++) + { + mTranslateKeyMap[cur_char] = (cur_char - 'a') + 'A'; + } + + for (cur_char = '0'; cur_char <= '9'; cur_char++) + { + mTranslateKeyMap[cur_char] = cur_char; + } + + // These ones are translated manually upon keydown/keyup because + // SDL doesn't handle their numlock transition. + //mTranslateKeyMap[SDLK_KP4] = KEY_PAD_LEFT; + //mTranslateKeyMap[SDLK_KP6] = KEY_PAD_RIGHT; + //mTranslateKeyMap[SDLK_KP8] = KEY_PAD_UP; + //mTranslateKeyMap[SDLK_KP2] = KEY_PAD_DOWN; + //mTranslateKeyMap[SDLK_KP_PERIOD] = KEY_DELETE; + //mTranslateKeyMap[SDLK_KP7] = KEY_HOME; + //mTranslateKeyMap[SDLK_KP1] = KEY_END; + //mTranslateKeyMap[SDLK_KP9] = KEY_PAGE_UP; + //mTranslateKeyMap[SDLK_KP3] = KEY_PAGE_DOWN; + //mTranslateKeyMap[SDLK_KP0] = KEY_INSERT; + + 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_KP_ENTER] = KEY_RETURN; + mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE; + mTranslateKeyMap[SDLK_BACKSPACE] = KEY_BACKSPACE; + mTranslateKeyMap[SDLK_DELETE] = KEY_DELETE; + mTranslateKeyMap[SDLK_LSHIFT] = KEY_SHIFT; + mTranslateKeyMap[SDLK_RSHIFT] = KEY_SHIFT; + mTranslateKeyMap[SDLK_LCTRL] = KEY_CONTROL; + mTranslateKeyMap[SDLK_RCTRL] = KEY_CONTROL; + mTranslateKeyMap[SDLK_LALT] = KEY_ALT; + mTranslateKeyMap[SDLK_RALT] = KEY_ALT; + mTranslateKeyMap[SDLK_HOME] = KEY_HOME; + mTranslateKeyMap[SDLK_END] = KEY_END; + mTranslateKeyMap[SDLK_PAGEUP] = KEY_PAGE_UP; + mTranslateKeyMap[SDLK_PAGEDOWN] = KEY_PAGE_DOWN; + mTranslateKeyMap[SDLK_MINUS] = KEY_HYPHEN; + mTranslateKeyMap[SDLK_EQUALS] = KEY_EQUALS; + mTranslateKeyMap[SDLK_KP_EQUALS] = KEY_EQUALS; + mTranslateKeyMap[SDLK_INSERT] = KEY_INSERT; + mTranslateKeyMap[SDLK_CAPSLOCK] = KEY_CAPSLOCK; + mTranslateKeyMap[SDLK_TAB] = KEY_TAB; + mTranslateKeyMap[SDLK_KP_PLUS] = KEY_ADD; + mTranslateKeyMap[SDLK_KP_MINUS] = KEY_SUBTRACT; + mTranslateKeyMap[SDLK_KP_MULTIPLY] = KEY_MULTIPLY; + mTranslateKeyMap[SDLK_KP_DIVIDE] = KEY_PAD_DIVIDE; + mTranslateKeyMap[SDLK_F1] = KEY_F1; + mTranslateKeyMap[SDLK_F2] = KEY_F2; + mTranslateKeyMap[SDLK_F3] = KEY_F3; + mTranslateKeyMap[SDLK_F4] = KEY_F4; + mTranslateKeyMap[SDLK_F5] = KEY_F5; + mTranslateKeyMap[SDLK_F6] = KEY_F6; + mTranslateKeyMap[SDLK_F7] = KEY_F7; + mTranslateKeyMap[SDLK_F8] = KEY_F8; + mTranslateKeyMap[SDLK_F9] = KEY_F9; + mTranslateKeyMap[SDLK_F10] = KEY_F10; + mTranslateKeyMap[SDLK_F11] = KEY_F11; + mTranslateKeyMap[SDLK_F12] = KEY_F12; + 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 + for (auto iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) + { + mInvTranslateKeyMap[iter->second] = iter->first; + } + + // numpad map + 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 (auto iter = mTranslateNumpadMap.begin(); + iter != mTranslateNumpadMap.end(); + iter++) + { + mInvTranslateNumpadMap[iter->second] = iter->first; + } } void LLKeyboardSDL::resetMaskKeys() { - SDLMod 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. - // Is this the way it's supposed to work? - - if(mask & KMOD_SHIFT) - { - mKeyLevel[KEY_SHIFT] = TRUE; - } - - if(mask & KMOD_CTRL) - { - mKeyLevel[KEY_CONTROL] = TRUE; - } - - if(mask & KMOD_ALT) - { - mKeyLevel[KEY_ALT] = TRUE; - } + 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. + // Is this the way it's supposed to work? + + if(mask & KMOD_SHIFT) + { + mKeyLevel[KEY_SHIFT] = TRUE; + } + + if(mask & KMOD_CTRL) + { + mKeyLevel[KEY_CONTROL] = TRUE; + } + + if(mask & KMOD_ALT) + { + mKeyLevel[KEY_ALT] = TRUE; + } } MASK LLKeyboardSDL::updateModifiers(const U32 mask) { - // translate the mask - MASK out_mask = MASK_NONE; + // translate the mask + MASK out_mask = MASK_NONE; - if(mask & KMOD_SHIFT) - { - out_mask |= MASK_SHIFT; - } + if(mask & KMOD_SHIFT) + { + out_mask |= MASK_SHIFT; + } - if(mask & KMOD_CTRL) - { - out_mask |= MASK_CONTROL; - } + if(mask & KMOD_CTRL) + { + out_mask |= MASK_CONTROL; + } - if(mask & KMOD_ALT) - { - out_mask |= MASK_ALT; - } + if(mask & KMOD_ALT) + { + out_mask |= MASK_ALT; + } - return out_mask; + return out_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; - 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; - } - } - return rtn; + // SDL doesn't automatically adjust the keysym according to + // whether NUMLOCK is engaged, so we massage the keysym manually. + U32 rtn = key; + if (!(mask & KMOD_NUM)) + { + switch (key) + { + 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; - KEY translated_key = 0; - U32 translated_mask = MASK_NONE; - BOOL handled = FALSE; + U32 adjusted_nativekey; + KEY translated_key = 0; + U32 translated_mask = MASK_NONE; + BOOL handled = FALSE; + + adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); - adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); + translated_mask = updateModifiers(mask); - translated_mask = updateModifiers(mask); - - if(translateNumpadKey(adjusted_nativekey, &translated_key)) - { - handled = handleTranslatedKeyDown(translated_key, translated_mask); - } + if(translateNumpadKey(adjusted_nativekey, &translated_key)) + { + handled = handleTranslatedKeyDown(translated_key, translated_mask); + } - return handled; + return handled; } -BOOL LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask) +BOOL LLKeyboardSDL::handleKeyUp(const U32 key, const U32 mask) { - U16 adjusted_nativekey; - KEY translated_key = 0; - U32 translated_mask = MASK_NONE; - BOOL handled = FALSE; + U32 adjusted_nativekey; + KEY translated_key = 0; + U32 translated_mask = MASK_NONE; + BOOL handled = FALSE; - adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); + adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); - translated_mask = updateModifiers(mask); + translated_mask = updateModifiers(mask); - if(translateNumpadKey(adjusted_nativekey, &translated_key)) - { - handled = handleTranslatedKeyUp(translated_key, translated_mask); - } + if(translateNumpadKey(adjusted_nativekey, &translated_key)) + { + handled = handleTranslatedKeyUp(translated_key, translated_mask); + } - return handled; + return handled; } MASK LLKeyboardSDL::currentMask(BOOL for_mouse_event) { - MASK result = MASK_NONE; - SDLMod mask = SDL_GetModState(); - - 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; - } - - return result; + MASK result = MASK_NONE; + 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; + + // For keyboard events, consider Meta keys equivalent to Control + if (!for_mouse_event) + { + if (mask & KMOD_GUI) + result |= MASK_CONTROL; + } + + return result; } void LLKeyboardSDL::scanKeyboard() { - for (S32 key = 0; key < KEY_COUNT; key++) - { - // Generate callback if any event has occurred on this key this frame. - // Can't just test mKeyLevel, because this could be a slow frame and - // key might have gone down then up. JC - if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) - { - mCurScanKey = key; - mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); - } - } - - // Reset edges for next frame - for (S32 key = 0; key < KEY_COUNT; key++) - { - mKeyUp[key] = FALSE; - mKeyDown[key] = FALSE; - if (mKeyLevel[key]) - { - mKeyLevelFrameCount[key]++; - } - } + for (S32 key = 0; key < KEY_COUNT; key++) + { + // Generate callback if any event has occurred on this key this frame. + // Can't just test mKeyLevel, because this could be a slow frame and + // key might have gone down then up. JC + if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) + { + mCurScanKey = key; + mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); + } + } + + // Reset edges for next frame + for (S32 key = 0; key < KEY_COUNT; key++) + { + mKeyUp[key] = FALSE; + mKeyDown[key] = FALSE; + if (mKeyLevel[key]) + { + mKeyLevelFrameCount[key]++; + } + } } - -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); + return translateKey(os_key, translated_key); } U16 LLKeyboardSDL::inverseTranslateNumpadKey(const KEY translated_key) { - return inverseTranslateKey(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 02a71425f1..4453e15adc 100644 --- a/indra/llwindow/llkeyboardsdl.h +++ b/indra/llwindow/llkeyboardsdl.h @@ -1,55 +1,57 @@ -/** - * @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. - * + * * 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 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 { public: - LLKeyboardSDL(); - /*virtual*/ ~LLKeyboardSDL() {}; + LLKeyboardSDL(); + /*virtual*/ ~LLKeyboardSDL() {}; - /*virtual*/ BOOL handleKeyUp(const U16 key, MASK mask); - /*virtual*/ BOOL handleKeyDown(const U16 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(BOOL for_mouse_event); - /*virtual*/ void scanKeyboard(); + /*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(); protected: - MASK updateModifiers(const U32 mask); - void setModifierKeyLevel( KEY key, BOOL new_state ); - BOOL translateNumpadKey( const U16 os_key, KEY *translated_key ); - U16 inverseTranslateNumpadKey(const KEY translated_key); + MASK updateModifiers(const U32 mask); + void setModifierKeyLevel( KEY key, BOOL new_state ); + 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 7ea87f5884..b8b502508b 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llwindowsdl.cpp * @brief SDL implementation of LLWindow class * @author This module has many fathers, and it shows. @@ -6,27 +6,25 @@ * $LicenseInfo:firstyear=2001&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_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; @@ -64,7 +60,7 @@ extern BOOL gDebugWindowProc; const S32 MAX_NUM_RESOLUTIONS = 200; // static variable for ATI mouse cursor crash work-around: -static bool ATIbug = false; +static bool ATIbug = false; // // LLWindowSDL @@ -83,188 +79,360 @@ static LLWindowSDL *gWindowImplementation = NULL; void maybe_lock_display(void) { - if (gWindowImplementation && gWindowImplementation->Lock_Display) { - gWindowImplementation->Lock_Display(); - } + if (gWindowImplementation && gWindowImplementation->Lock_Display) { + gWindowImplementation->Lock_Display(); + } } void maybe_unlock_display(void) { - if (gWindowImplementation && gWindowImplementation->Unlock_Display) { - gWindowImplementation->Unlock_Display(); - } + if (gWindowImplementation && gWindowImplementation->Unlock_Display) { + gWindowImplementation->Unlock_Display(); + } } -#if LL_GTK -// Lazily initialize and check the runtime GTK version for goodness. -// static -bool LLWindowSDL::ll_try_gtk_init(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 (!done_setlocale) - { - LL_INFOS() << "Starting GTK Initialization." << LL_ENDL; - maybe_lock_display(); - gtk_disable_setlocale(); - maybe_unlock_display(); - done_setlocale = TRUE; - } - - if (!tried_gtk_init) - { - 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; - } - - if (gtk_is_good && !done_gtk_diag) - { - 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; - maybe_lock_display(); - const gchar* gtk_warning = gtk_check_version( - GTK_MAJOR_VERSION, - GTK_MINOR_VERSION, - GTK_MICRO_VERSION); - maybe_unlock_display(); - if (gtk_warning) - { - LL_WARNS() << "- GTK COMPATIBILITY WARNING: " << - gtk_warning << LL_ENDL; - gtk_is_good = FALSE; - } else { - LL_INFOS() << "- GTK version is good." << LL_ENDL; - } - - done_gtk_diag = TRUE; - } - - return gtk_is_good; -} -#endif // LL_GTK - - #if LL_X11 // static Window LLWindowSDL::get_SDL_XWindowID(void) { - if (gWindowImplementation) { - return gWindowImplementation->mSDL_XWindowID; - } - return None; + if (gWindowImplementation) { + return gWindowImplementation->mSDL_XWindowID; + } + return None; } //static Display* LLWindowSDL::get_SDL_Display(void) { - if (gWindowImplementation) { - return gWindowImplementation->mSDL_Display; - } - return NULL; + 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 ) + { + 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); + } + + void filterSelectionClearRequest( XEvent aEvent ) + { + 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; + } + + bool grab_property(Display* display, Window window, Atom selection, Atom target) + { + if( !display ) + return false; + + maybe_lock_display(); + + 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(); + + const auto start{ SDL_GetTicks() }; + const auto end{ start + 1000 }; + + XEvent xevent {}; + bool response = false; + + do + { + 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; + + 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; + + 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(); +} + +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; + + 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 (!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; + } + } + + maybe_unlock_display(); + + for( Atom atom : gSupportedAtoms ) + { + if(getSelectionText(selection, atom, text ) ) + return true; + } + + return false; +} + +bool LLWindowSDL::setSelectionText(Atom selection, const LLWString& text) +{ + 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; + } + 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 + 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) -{ - // Initialize the keyboard - gKeyboard = new LLKeyboardSDL(); - gKeyboard->setCallbacks(callbacks); - // Note that we can't set up key-repeat until after SDL has init'd video - - // Ignore use_gl for now, only used for drones on PC - mWindow = NULL; - mNeedsResize = FALSE; - mOverrideAspectRatio = 0.f; - mGrabbyKeyFlags = 0; - mReallyCapturedCount = 0; - mHaveInputFocus = -1; - mIsMinimized = -1; - mFSAASamples = fsaa_samples; + 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(); + gKeyboard->setCallbacks(callbacks); + // Note that we can't set up key-repeat until after SDL has init'd video + + // Ignore use_gl for now, only used for drones on PC + mWindow = NULL; + mContext = {}; + mNeedsResize = FALSE; + mOverrideAspectRatio = 0.f; + mGrabbyKeyFlags = 0; + mReallyCapturedCount = 0; + mHaveInputFocus = -1; + mIsMinimized = -1; + mFSAASamples = fsaa_samples; #if LL_X11 - mSDL_XWindowID = None; - mSDL_Display = NULL; + mSDL_XWindowID = None; + 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; + // Assume 4:3 aspect ratio until we know better + mOriginalAspectRatio = 1024.0 / 768.0; - if (title.empty()) - mWindowTitle = "SDL Window"; // *FIX: (?) - else - mWindowTitle = title; + if (title.empty()) + mWindowTitle = "SDL Window"; // *FIX: (?) + else + mWindowTitle = title; - // Create the GL context and set it up for windowed or fullscreen, as appropriate. - if(createContext(x, y, width, height, 32, fullscreen, disable_vsync)) - { - gGLManager.initGL(); + // Create the GL context and set it up for windowed or fullscreen, as appropriate. + if(createContext(x, y, width, height, 32, fullscreen, disable_vsync)) + { + gGLManager.initGL(); - //start with arrow cursor - initCursors(); - setCursor( UI_CURSOR_ARROW ); - } + //start with arrow cursor + initCursors(); + setCursor( UI_CURSOR_ARROW ); + } - stop_glerror(); + stop_glerror(); - // Stash an object pointer for OSMessageBox() - gWindowImplementation = this; + // Stash an object pointer for OSMessageBox() + gWindowImplementation = this; #if LL_X11 - mFlashing = FALSE; + mFlashing = FALSE; + initialiseX11Clipboard(); #endif // LL_X11 - mKeyScanCode = 0; - mKeyVirtualKey = 0; - mKeyModifiers = KMOD_NONE; + mKeyVirtualKey = 0; + mKeyModifiers = KMOD_NONE; } static SDL_Surface *Load_BMP_Resource(const char *basename) { - const int PATH_BUFFER_SIZE=1000; - char path_buffer[PATH_BUFFER_SIZE]; /* Flawfinder: ignore */ - - // 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); - path_buffer[PATH_BUFFER_SIZE-1] = '\0'; - - return SDL_LoadBMP(path_buffer); + const int PATH_BUFFER_SIZE=1000; + char path_buffer[PATH_BUFFER_SIZE]; /* Flawfinder: ignore */ + + // 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); + path_buffer[PATH_BUFFER_SIZE-1] = '\0'; + + return SDL_LoadBMP(path_buffer); } #if LL_X11 @@ -274,520 +442,513 @@ static SDL_Surface *Load_BMP_Resource(const char *basename) // '?' is the X11 display number derived from $DISPLAY static int x11_detect_VRAM_kb_fp(FILE *fp, const char *prefix_str) { - const int line_buf_size = 1000; - char line_buf[line_buf_size]; - while (fgets(line_buf, line_buf_size, fp)) - { - //LL_DEBUGS() << "XLOG: " << line_buf << LL_ENDL; - - // Why the ad-hoc parser instead of using a regex? Our - // favourite regex implementation - libboost_regex - is - // quite a heavy and troublesome dependency for the client, so - // it seems a shame to introduce it for such a simple task. - // *FIXME: libboost_regex is a dependency now anyway, so we may - // as well use it instead of this hand-rolled nonsense. - const char *part1_template = prefix_str; - const char part2_template[] = " kB"; - char *part1 = strstr(line_buf, part1_template); - if (part1) // found start of matching line - { - part1 = &part1[strlen(part1_template)]; // -> after - char *part2 = strstr(part1, part2_template); - if (part2) // found end of matching line - { - // now everything between part1 and part2 is - // supposed to be numeric, describing the - // number of kB of Video RAM supported - int rtn = 0; - for (; part1 < part2; ++part1) - { - if (*part1 < '0' || *part1 > '9') - { - // unexpected char, abort parse - rtn = 0; - break; - } - rtn *= 10; - rtn += (*part1) - '0'; - } - if (rtn > 0) - { - // got the kB number. return it now. - return rtn; - } - } - } - } - return 0; // 'could not detect' + const int line_buf_size = 1000; + char line_buf[line_buf_size]; + while (fgets(line_buf, line_buf_size, fp)) + { + //LL_DEBUGS() << "XLOG: " << line_buf << LL_ENDL; + + // Why the ad-hoc parser instead of using a regex? Our + // favourite regex implementation - libboost_regex - is + // quite a heavy and troublesome dependency for the client, so + // it seems a shame to introduce it for such a simple task. + // *FIXME: libboost_regex is a dependency now anyway, so we may + // as well use it instead of this hand-rolled nonsense. + const char *part1_template = prefix_str; + const char part2_template[] = " kB"; + char *part1 = strstr(line_buf, part1_template); + if (part1) // found start of matching line + { + part1 = &part1[strlen(part1_template)]; // -> after + char *part2 = strstr(part1, part2_template); + if (part2) // found end of matching line + { + // now everything between part1 and part2 is + // supposed to be numeric, describing the + // number of kB of Video RAM supported + int rtn = 0; + for (; part1 < part2; ++part1) + { + if (*part1 < '0' || *part1 > '9') + { + // unexpected char, abort parse + rtn = 0; + break; + } + rtn *= 10; + rtn += (*part1) - '0'; + } + if (rtn > 0) + { + // got the kB number. return it now. + return rtn; + } + } + } + } + return 0; // 'could not detect' } static int x11_detect_VRAM_kb() { - std::string x_log_location("/var/log/"); - std::string fname; - int rtn = 0; // 'could not detect' - int display_num = 0; - FILE *fp; - char *display_env = getenv("DISPLAY"); // e.g. :0 or :0.0 or :1.0 etc - // parse DISPLAY number so we can go grab the right log file - if (display_env[0] == ':' && - display_env[1] >= '0' && display_env[1] <= '9') - { - display_num = display_env[1] - '0'; - } - - // *TODO: we could be smarter and see which of Xorg/XFree86 has the - // freshest time-stamp. - - // Try Xorg log first - fname = x_log_location; - fname += "Xorg."; - fname += ('0' + display_num); - fname += ".log"; - fp = fopen(fname.c_str(), "r"); - if (fp) - { - LL_INFOS() << "Looking in " << fname - << " for VRAM info..." << LL_ENDL; - rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); - fclose(fp); - if (0 == rtn) - { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Video RAM: "); - fclose(fp); - if (0 == rtn) - { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); - fclose(fp); - } - } - } - } - } - else - { - LL_INFOS() << "Could not open " << fname - << " - skipped." << LL_ENDL; - // Try old XFree86 log otherwise - fname = x_log_location; - fname += "XFree86."; - fname += ('0' + display_num); - fname += ".log"; - fp = fopen(fname.c_str(), "r"); - if (fp) - { - LL_INFOS() << "Looking in " << fname - << " for VRAM info..." << LL_ENDL; - rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); - fclose(fp); - if (0 == rtn) - { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); - fclose(fp); - } - } - } - else - { - LL_INFOS() << "Could not open " << fname - << " - skipped." << LL_ENDL; - } - } - return rtn; + std::string x_log_location("/var/log/"); + std::string fname; + int rtn = 0; // 'could not detect' + int display_num = 0; + FILE *fp; + char *display_env = getenv("DISPLAY"); // e.g. :0 or :0.0 or :1.0 etc + // parse DISPLAY number so we can go grab the right log file + if (display_env[0] == ':' && + display_env[1] >= '0' && display_env[1] <= '9') + { + display_num = display_env[1] - '0'; + } + + // *TODO: we could be smarter and see which of Xorg/XFree86 has the + // freshest time-stamp. + + // Try Xorg log first + fname = x_log_location; + fname += "Xorg."; + fname += ('0' + display_num); + fname += ".log"; + fp = fopen(fname.c_str(), "r"); + if (fp) + { + LL_INFOS() << "Looking in " << fname + << " for VRAM info..." << LL_ENDL; + rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); + fclose(fp); + if (0 == rtn) + { + fp = fopen(fname.c_str(), "r"); + if (fp) + { + rtn = x11_detect_VRAM_kb_fp(fp, ": Video RAM: "); + fclose(fp); + if (0 == rtn) + { + fp = fopen(fname.c_str(), "r"); + if (fp) + { + rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); + fclose(fp); + } + } + } + } + } + else + { + LL_INFOS() << "Could not open " << fname + << " - skipped." << LL_ENDL; + // Try old XFree86 log otherwise + fname = x_log_location; + fname += "XFree86."; + fname += ('0' + display_num); + fname += ".log"; + fp = fopen(fname.c_str(), "r"); + if (fp) + { + LL_INFOS() << "Looking in " << fname + << " for VRAM info..." << LL_ENDL; + rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); + fclose(fp); + if (0 == rtn) + { + fp = fopen(fname.c_str(), "r"); + if (fp) + { + rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); + fclose(fp); + } + } + } + else + { + LL_INFOS() << "Could not open " << fname + << " - 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; - - // captures don't survive contexts - mGrabbyKeyFlags = 0; - mReallyCapturedCount = 0; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) - { - LL_INFOS() << "sdl_init() failed! " << SDL_GetError() << LL_ENDL; - setupFailure("sdl_init() failure, window creation error", "error", OSMB_OK); - return false; - } - - 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(); - LL_INFOS() << " Running against SDL " - << 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 (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; - } - - SDL_EnableUNICODE(1); - SDL_WM_SetCaption(mWindowTitle.c_str(), mWindowTitle.c_str()); - - // Set the application icon. - SDL_Surface *bmpsurface; - bmpsurface = Load_BMP_Resource("ll_icon.BMP"); - if (bmpsurface) - { - // 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; - } - - // 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); - - // *FIX: try to toggle vsync here? - - mFullscreen = fullscreen; - - int sdlflags = SDL_OPENGL | SDL_RESIZABLE | SDL_ANYFORMAT; - - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - - if (mFSAASamples > 0) - { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, mFSAASamples); - } - - mSDLFlags = sdlflags; - - if (mFullscreen) - { - 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; - } - - 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) - { - mFullscreen = TRUE; - mFullscreenWidth = mWindow->w; - mFullscreenHeight = mWindow->h; - mFullscreenBits = mWindow->format->BitsPerPixel; - mFullscreenRefresh = -1; - - LL_INFOS() << "Running at " << mFullscreenWidth - << "x" << mFullscreenHeight - << "x" << mFullscreenBits - << " @ " << mFullscreenRefresh - << LL_ENDL; - } - else - { - LL_WARNS() << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << LL_ENDL; - // No fullscreen support - mFullscreen = FALSE; - mFullscreenWidth = -1; - mFullscreenHeight = -1; - mFullscreenBits = -1; - mFullscreenRefresh = -1; - - std::string error = llformat("Unable to run fullscreen at %d x %d.\nRunning in window.", width, height); - OSMessageBox(error, "Error", OSMB_OK); - } - } - - if(!mFullscreen && (mWindow == NULL)) - { - 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)) - { - LL_INFOS() << "createContext: SKIPPING - !fullscreen, but +mWindow " << width << "x" << height << "x" << bits << LL_ENDL; - } - - // Detect video memory size. + //bool glneedsinit = false; + + LL_INFOS() << "createContext, fullscreen=" << fullscreen << + " size=" << width << "x" << height << LL_ENDL; + + // captures don't survive contexts + mGrabbyKeyFlags = 0; + mReallyCapturedCount = 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"}, + }; + + for( auto hint: hintList ) + { + 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; + 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; + + if (width == 0) + width = 1024; + if (height == 0) + width = 768; + + mFullscreen = fullscreen; + + int sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; + + if( mFullscreen ) + { + sdlflags |= SDL_WINDOW_FULLSCREEN; + tryFindFullscreenSize( width, height ); + } + + mSDLFlags = sdlflags; + + GLint redBits{8}, greenBits{8}, blueBits{8}, alphaBits{8}; + + GLint depthBits{(bits <= 16) ? 16 : 24}, stencilBits{8}; + + 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); + + if (mFSAASamples > 0) + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, mFSAASamples); + } + + 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( mWindow ) + { + mContext = SDL_GL_CreateContext( mWindow ); + + if( mContext == 0 ) + { + 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 ); + } + + + if( mFullscreen ) + { + if (mSurface) + { + mFullscreen = TRUE; + mFullscreenWidth = mSurface->w; + mFullscreenHeight = mSurface->h; + mFullscreenBits = mSurface->format->BitsPerPixel; + mFullscreenRefresh = -1; + + LL_INFOS() << "Running at " << mFullscreenWidth + << "x" << mFullscreenHeight + << "x" << mFullscreenBits + << " @ " << mFullscreenRefresh + << LL_ENDL; + } + else + { + LL_WARNS() << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << LL_ENDL; + // No fullscreen support + mFullscreen = FALSE; + mFullscreenWidth = -1; + mFullscreenHeight = -1; + mFullscreenBits = -1; + mFullscreenRefresh = -1; + + std::string error = llformat("Unable to run fullscreen at %d x %d.\nRunning in window.", width, height); + OSMessageBox(error, "Error", OSMB_OK); + return FALSE; + } + } + else + { + if (!mWindow) + { + LL_WARNS() << "createContext: window creation failure. SDL: " << SDL_GetError() << LL_ENDL; + setupFailure("Window creation error", "Error", OSMB_OK); + return FALSE; + } + } + + // Set the application icon. + SDL_Surface *bmpsurface; + bmpsurface = Load_BMP_Resource("ll_icon.BMP"); + if (bmpsurface) + { + SDL_SetWindowIcon(mWindow, bmpsurface); + SDL_FreeSurface(bmpsurface); + bmpsurface = NULL; + } + + // Detect video memory size. # if LL_X11 - gGLManager.mVRAM = x11_detect_VRAM_kb() / 1024; - if (gGLManager.mVRAM != 0) - { - LL_INFOS() << "X11 log-parser detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; - } else + gGLManager.mVRAM = x11_detect_VRAM_kb() / 1024; + if (gGLManager.mVRAM != 0) + { + LL_INFOS() << "X11 log-parser detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; + } else # endif // LL_X11 - { - // 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; - if (gGLManager.mVRAM != 0) - { - LL_INFOS() << "SDL detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; - } - } - // If VRAM is not detected, that is handled later - - // *TODO: Now would be an appropriate time to check for some - // 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); - - 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; - - GLint colorBits = redBits + greenBits + blueBits + alphaBits; - // fixme: actually, it's REALLY important for picking that we get at - // least 8 bits each of red,green,blue. Alpha we can be a bit more - // relaxed about if we have to. - if (colorBits < 32) - { - 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); - return FALSE; - } -#endif + { + // 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 = 0; + if (gGLManager.mVRAM != 0) + { + LL_INFOS() << "SDL detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; + } + } + // If VRAM is not detected, that is handled later + + // *TODO: Now would be an appropriate time to check for some + // explicitly unsupported cards. + //const char* RENDERER = (const char*) glGetString(GL_RENDERER); + + 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; + + GLint colorBits = redBits + greenBits + blueBits + alphaBits; + // fixme: actually, it's REALLY important for picking that we get at + // least 8 bits each of red,green,blue. Alpha we can be a bit more + // relaxed about if we have to. + if (colorBits < 32) + { + 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 LL_X11 - /* Grab the window manager specific information */ - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - if ( SDL_GetWMInfo(&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; - } - else - { - LL_WARNS() << "We're not running under X11? Wild." - << LL_ENDL; - } - } - else - { - LL_WARNS() << "We're not running under any known WM. Wild." - << LL_ENDL; - } + /* Grab the window manager specific information */ + SDL_SysWMinfo info; + SDL_VERSION(&info.version); + 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.window; + } + else + { + LL_WARNS() << "We're not running under X11? Wild." + << LL_ENDL; + } + } + else + { + LL_WARNS() << "We're not running under any known WM. Wild." + << LL_ENDL; + } #endif // LL_X11 - //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; + SDL_StartTextInput(); + //make sure multisampling is disabled by default + glDisable(GL_MULTISAMPLE_ARB); - // Don't need to get the current gamma, since there's a call that restores it to the system defaults. - return TRUE; + // Don't need to get the current gamma, since there's a call that restores it to the system defaults. + return TRUE; } // changing fullscreen resolution, or switching between windowed and fullscreen mode. BOOL LLWindowSDL::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) { - const BOOL needsRebuild = TRUE; // Just nuke the context and start over. - BOOL result = true; + const BOOL needsRebuild = TRUE; // Just nuke the context and start over. + BOOL result = true; - LL_INFOS() << "switchContext, fullscreen=" << fullscreen << LL_ENDL; - stop_glerror(); - if(needsRebuild) - { - destroyContext(); - result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); - if (result) - { - gGLManager.initGL(); + LL_INFOS() << "switchContext, fullscreen=" << fullscreen << LL_ENDL; + stop_glerror(); + if(needsRebuild) + { + destroyContext(); + result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); + if (result) + { + gGLManager.initGL(); - //start with arrow cursor - initCursors(); - setCursor( UI_CURSOR_ARROW ); - } - } + //start with arrow cursor + initCursors(); + setCursor( UI_CURSOR_ARROW ); + } + } - stop_glerror(); + stop_glerror(); - return result; + return result; } void LLWindowSDL::destroyContext() { - LL_INFOS() << "destroyContext begins" << LL_ENDL; + LL_INFOS() << "destroyContext begins" << LL_ENDL; + SDL_StopTextInput(); #if LL_X11 - mSDL_Display = NULL; - mSDL_XWindowID = None; - Lock_Display = NULL; - Unlock_Display = NULL; + mSDL_Display = NULL; + mSDL_XWindowID = None; + Lock_Display = NULL; + Unlock_Display = NULL; #endif // LL_X11 - // Clean up remaining GL state before blowing away window - LL_INFOS() << "shutdownGL begins" << LL_ENDL; - gGLManager.shutdownGL(); - LL_INFOS() << "SDL_QuitSS/VID begins" << LL_ENDL; - SDL_QuitSubSystem(SDL_INIT_VIDEO); // *FIX: this might be risky... + // Clean up remaining GL state before blowing away window + LL_INFOS() << "shutdownGL begins" << LL_ENDL; + gGLManager.shutdownGL(); + LL_INFOS() << "SDL_QuitSS/VID begins" << LL_ENDL; + SDL_QuitSubSystem(SDL_INIT_VIDEO); // *FIX: this might be risky... - mWindow = NULL; + mWindow = NULL; } LLWindowSDL::~LLWindowSDL() { - quitCursors(); - destroyContext(); + quitCursors(); + destroyContext(); - if(mSupportedResolutions != NULL) - { - delete []mSupportedResolutions; - } + if(mSupportedResolutions != NULL) + { + delete []mSupportedResolutions; + } - gWindowImplementation = NULL; + gWindowImplementation = NULL; } @@ -818,87 +979,87 @@ void LLWindowSDL::restore() // Usually called from LLWindowManager::destroyWindow() void LLWindowSDL::close() { - // Is window is already closed? - // if (!mWindow) - // { - // return; - // } + // Is window is already closed? + // if (!mWindow) + // { + // return; + // } - // Make sure cursor is visible and we haven't mangled the clipping state. - setMouseClipping(FALSE); - showCursor(); + // Make sure cursor is visible and we haven't mangled the clipping state. + setMouseClipping(FALSE); + showCursor(); - destroyContext(); + destroyContext(); } BOOL LLWindowSDL::isValid() { - return (mWindow != NULL); + return (mWindow != NULL); } BOOL LLWindowSDL::getVisible() { - BOOL result = FALSE; + BOOL result = FALSE; // *FIX: This isn't really right... - // Then what is? - if (mWindow) - { - result = TRUE; - } + // Then what is? + if (mWindow) + { + result = TRUE; + } - return(result); + return(result); } BOOL LLWindowSDL::getMinimized() { - BOOL result = FALSE; + BOOL result = FALSE; - if (mWindow && (1 == mIsMinimized)) - { - result = TRUE; - } - return(result); + if (mWindow && (1 == mIsMinimized)) + { + result = TRUE; + } + return(result); } BOOL LLWindowSDL::getMaximized() { - BOOL result = FALSE; + BOOL result = FALSE; - if (mWindow) - { - // TODO - } + if (mWindow) + { + // TODO + } - return(result); + return(result); } BOOL LLWindowSDL::maximize() { - // TODO - return FALSE; + // TODO + return FALSE; } BOOL LLWindowSDL::getFullscreen() { - return mFullscreen; + return mFullscreen; } BOOL LLWindowSDL::getPosition(LLCoordScreen *position) { // *FIX: can anything be done with this? - position->mX = 0; - position->mY = 0; + position->mX = 0; + position->mY = 0; return TRUE; } 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 +1067,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); @@ -918,94 +1079,91 @@ BOOL LLWindowSDL::getSize(LLCoordWindow *size) BOOL LLWindowSDL::setPosition(const LLCoordScreen position) { - if(mWindow) - { + if(mWindow) + { // *FIX: (?) - //MacMoveWindow(mWindow, position.mX, position.mY, false); - } + //MacMoveWindow(mWindow, position.mX, position.mY, false); + } - return TRUE; + 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; + + auto nFlags = SDL_GetWindowFlags( pWin ); - return TRUE; - } - - 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 ); } void LLWindowSDL::swapBuffers() { - if (mWindow) - { - SDL_GL_SwapBuffers(); - } + if (mWindow) + { + SDL_GL_SwapWindow( mWindow ); + } } U32 LLWindowSDL::getFSAASamples() { - return mFSAASamples; + return mFSAASamples; } void LLWindowSDL::setFSAASamples(const U32 samples) { - mFSAASamples = samples; + mFSAASamples = samples; } F32 LLWindowSDL::getGamma() { - return 1/mGamma; + return 1/mGamma; } BOOL LLWindowSDL::restoreGamma() { - //CGDisplayRestoreColorSyncSettings(); - SDL_SetGamma(1.0f, 1.0f, 1.0f); - return true; + //CGDisplayRestoreColorSyncSettings(); + // SDL_SetGamma(1.0f, 1.0f, 1.0f); + return true; } BOOL LLWindowSDL::setGamma(const F32 gamma) { - mGamma = gamma; - if (mGamma == 0) mGamma = 0.1f; - mGamma = 1/mGamma; - SDL_SetGamma(mGamma, mGamma, mGamma); - return true; + mGamma = gamma; + if (mGamma == 0) mGamma = 0.1f; + mGamma = 1/mGamma; + // SDL_SetGamma(mGamma, mGamma, mGamma); + return true; } BOOL LLWindowSDL::isCursorHidden() { - return mCursorHidden; + return mCursorHidden; } @@ -1019,110 +1177,98 @@ void LLWindowSDL::setMouseClipping( BOOL b ) // virtual void LLWindowSDL::setMinSize(U32 min_width, U32 min_height, bool enforce_immediately) { - LLWindow::setMinSize(min_width, min_height, enforce_immediately); + LLWindow::setMinSize(min_width, min_height, enforce_immediately); #if LL_X11 - // Set the minimum size limits for X11 window - // so the window manager doesn't allow resizing below those limits. - XSizeHints* hints = XAllocSizeHints(); - hints->flags |= PMinSize; - hints->min_width = mMinWindowWidth; - hints->min_height = mMinWindowHeight; + // Set the minimum size limits for X11 window + // so the window manager doesn't allow resizing below those limits. + XSizeHints* hints = XAllocSizeHints(); + hints->flags |= PMinSize; + hints->min_width = mMinWindowWidth; + hints->min_height = mMinWindowHeight; - XSetWMNormalHints(mSDL_Display, mSDL_XWindowID, hints); + XSetWMNormalHints(mSDL_Display, mSDL_XWindowID, hints); - XFree(hints); + XFree(hints); #endif } BOOL LLWindowSDL::setCursorPosition(const LLCoordWindow position) { - BOOL result = TRUE; - LLCoordScreen screen_pos; + BOOL result = TRUE; + LLCoordScreen screen_pos; - if (!convertCoords(position, &screen_pos)) - { - return FALSE; - } + if (!convertCoords(position, &screen_pos)) + { + return FALSE; + } - //LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; + //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); - - //LL_INFOS() << llformat("llcw %d,%d -> scr %d,%d", position.mX, position.mY, screen_pos.mX, screen_pos.mY) << LL_ENDL; + // do the actual forced cursor move. + SDL_WarpMouseInWindow(mWindow, screen_pos.mX, screen_pos.mY); - return result; + //LL_INFOS() << llformat("llcw %d,%d -> scr %d,%d", position.mX, position.mY, screen_pos.mX, screen_pos.mY) << LL_ENDL; + + return result; } BOOL LLWindowSDL::getCursorPosition(LLCoordWindow *position) { - //Point cursor_point; - LLCoordScreen screen_pos; + //Point cursor_point; + LLCoordScreen screen_pos; - //GetMouse(&cursor_point); + //GetMouse(&cursor_point); int x, y; SDL_GetMouseState(&x, &y); - screen_pos.mX = x; - screen_pos.mY = y; + screen_pos.mX = x; + screen_pos.mY = y; - return convertCoords(screen_pos, position); + return convertCoords(screen_pos, 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); - + // 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. - 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. - - // New assumptions: - // - pixels are square (the only reasonable choice, really) - // - The user runs their display at a native resolution, so the resolution of the display - // when the app is launched has an aspect ratio that matches the monitor. + // New assumptions: + // - pixels are square (the only reasonable choice, really) + // - The user runs their display at a native resolution, so the resolution of the display + // when the app is launched has an aspect ratio that matches the monitor. - //RN: actually, the assumption that there are no ridiculous resolutions (above the display's native capabilities) has - // been born out in my experience. - // Pixels are often not square (just ask the people who run their LCDs at 1024x768 or 800x600 when running fullscreen, like me) - // The ordering of display list is a blind assumption though, so we should check for max values - // Things might be different on the Mac though, so I'll defer to MBW + //RN: actually, the assumption that there are no ridiculous resolutions (above the display's native capabilities) has + // been born out in my experience. + // Pixels are often not square (just ask the people who run their LCDs at 1024x768 or 800x600 when running fullscreen, like me) + // The ordering of display list is a blind assumption though, so we should check for max values + // Things might be different on the Mac though, so I'll defer to MBW - // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution - // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. + // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution + // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. - if (mOverrideAspectRatio > 0.f) - { - return mOverrideAspectRatio; - } + if (mOverrideAspectRatio > 0.f) + { + return mOverrideAspectRatio; + } - return mOriginalAspectRatio; + return mOriginalAspectRatio; } F32 LLWindowSDL::getPixelAspectRatio() { - F32 pixel_aspect = 1.f; - if (getFullscreen()) - { - LLCoordScreen screen_size; - if (getSize(&screen_size)) - { - pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; - } - } + F32 pixel_aspect = 1.f; + if (getFullscreen()) + { + LLCoordScreen screen_size; + if (getSize(&screen_size)) + { + pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; + } + } - return pixel_aspect; + return pixel_aspect; } @@ -1130,67 +1276,61 @@ F32 LLWindowSDL::getPixelAspectRatio() // dialogs are still usable in fullscreen. void LLWindowSDL::beforeDialog() { - bool running_x11 = false; + bool running_x11 = false; #if LL_X11 - running_x11 = (mSDL_XWindowID != None); + running_x11 = (mSDL_XWindowID != None); #endif //LL_X11 - LL_INFOS() << "LLWindowSDL::beforeDialog()" << LL_ENDL; - - if (SDLReallyCaptureInput(FALSE)) // must ungrab input so popup works! - { - if (mFullscreen) - { - // need to temporarily go non-fullscreen; bless SDL - // for providing a SDL_WM_ToggleFullScreen() - though - // it only works in X11 - if (running_x11 && mWindow) - { - SDL_WM_ToggleFullScreen(mWindow); - } - } - } + LL_INFOS() << "LLWindowSDL::beforeDialog()" << LL_ENDL; + + if (SDLReallyCaptureInput(FALSE)) // must ungrab input so popup works! + { + if (mFullscreen) + { + // need to temporarily go non-fullscreen; bless SDL + // for providing a SDL_WM_ToggleFullScreen() - though + // it only works in X11 + if (running_x11 && mWindow) + { + SDL_SetWindowFullscreen( mWindow, 0 ); + } + } + } #if LL_X11 - if (mSDL_Display) - { - // Everything that we/SDL asked for should happen before we - // potentially hand control over to GTK. - maybe_lock_display(); - XSync(mSDL_Display, False); - maybe_unlock_display(); - } + if (mSDL_Display) + { + // Everything that we/SDL asked for should happen before we + // potentially hand control over to GTK. + maybe_lock_display(); + XSync(mSDL_Display, False); + maybe_unlock_display(); + } #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(); + maybe_lock_display(); } void LLWindowSDL::afterDialog() { - bool running_x11 = false; + bool running_x11 = false; #if LL_X11 - running_x11 = (mSDL_XWindowID != None); + running_x11 = (mSDL_XWindowID != None); #endif //LL_X11 - LL_INFOS() << "LLWindowSDL::afterDialog()" << LL_ENDL; + LL_INFOS() << "LLWindowSDL::afterDialog()" << LL_ENDL; - maybe_unlock_display(); + maybe_unlock_display(); - if (mFullscreen) - { - // need to restore fullscreen mode after dialog - only works - // in X11 - if (running_x11 && mWindow) - { - SDL_WM_ToggleFullScreen(mWindow); - } - } + if (mFullscreen) + { + // need to restore fullscreen mode after dialog - only works + // in X11 + if (running_x11 && mWindow) + { + SDL_SetWindowFullscreen( mWindow, 0 ); + } + } } @@ -1198,210 +1338,120 @@ void LLWindowSDL::afterDialog() // set/reset the XWMHints flag for 'urgency' that usually makes the icon flash void LLWindowSDL::x11_set_urgent(BOOL urgent) { - if (mSDL_Display && !mFullscreen) - { - XWMHints *wm_hints; - - LL_INFOS() << "X11 hint for urgency, " << urgent << LL_ENDL; + if (mSDL_Display && !mFullscreen) + { + XWMHints *wm_hints; - maybe_lock_display(); - wm_hints = XGetWMHints(mSDL_Display, mSDL_XWindowID); - if (!wm_hints) - wm_hints = XAllocWMHints(); + LL_INFOS() << "X11 hint for urgency, " << urgent << LL_ENDL; - if (urgent) - wm_hints->flags |= XUrgencyHint; - else - wm_hints->flags &= ~XUrgencyHint; + maybe_lock_display(); + wm_hints = XGetWMHints(mSDL_Display, mSDL_XWindowID); + if (!wm_hints) + wm_hints = XAllocWMHints(); - XSetWMHints(mSDL_Display, mSDL_XWindowID, wm_hints); - XFree(wm_hints); - XSync(mSDL_Display, False); - maybe_unlock_display(); - } + if (urgent) + wm_hints->flags |= XUrgencyHint; + else + wm_hints->flags &= ~XUrgencyHint; + + XSetWMHints(mSDL_Display, mSDL_XWindowID, wm_hints); + XFree(wm_hints); + XSync(mSDL_Display, False); + maybe_unlock_display(); + } } #endif // LL_X11 void LLWindowSDL::flashIcon(F32 seconds) { + if (getMinimized()) + { #if !LL_X11 - LL_INFOS() << "Stub LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; -#else - 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); - - 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 -} + LL_INFOS() << "Stub LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; +#else + 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); -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 + x11_set_urgent(TRUE); + mFlashing = TRUE; +#endif // LL_X11 + } } -#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) - { - mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; - mNumSupportedResolutions = 0; + if (!mSupportedResolutions) + { + 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++; } } } - } + } - num_resolutions = mNumSupportedResolutions; - return mSupportedResolutions; + num_resolutions = mNumSupportedResolutions; + return mSupportedResolutions; } BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to) @@ -1409,10 +1459,10 @@ BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to) if (!to) return FALSE; - to->mX = from.mX; - to->mY = mWindow->h - from.mY - 1; + to->mX = from.mX; + to->mY = mSurface->h - from.mY - 1; - return TRUE; + return TRUE; } BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) @@ -1420,46 +1470,46 @@ BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) if (!to) return FALSE; - to->mX = from.mX; - to->mY = mWindow->h - from.mY - 1; + to->mX = from.mX; + to->mY = mSurface->h - from.mY - 1; - return TRUE; + return TRUE; } BOOL LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) { if (!to) - return FALSE; + return FALSE; - // In the fullscreen case, window and screen coordinates are the same. - to->mX = from.mX; - to->mY = from.mY; + // In the fullscreen case, window and screen coordinates are the same. + to->mX = from.mX; + to->mY = from.mY; return (TRUE); } BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) { if (!to) - return FALSE; + return FALSE; - // In the fullscreen case, window and screen coordinates are the same. - to->mX = from.mX; - to->mY = from.mY; + // In the fullscreen case, window and screen coordinates are the same. + to->mX = from.mX; + to->mY = from.mY; return (TRUE); } BOOL LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to) { - LLCoordWindow window_coord; + LLCoordWindow window_coord; - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); } BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to) { - LLCoordWindow window_coord; + LLCoordWindow window_coord; - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); } @@ -1467,226 +1517,216 @@ BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to) void LLWindowSDL::setupFailure(const std::string& text, const std::string& caption, U32 type) { - destroyContext(); + destroyContext(); - OSMessageBox(text, caption, type); + OSMessageBox(text, caption, type); } BOOL LLWindowSDL::SDLReallyCaptureInput(BOOL capture) { - // note: this used to be safe to call nestedly, but in the - // end that's not really a wise usage pattern, so don't. - - if (capture) - mReallyCapturedCount = 1; - else - mReallyCapturedCount = 0; - - SDL_GrabMode wantmode, newmode; - if (mReallyCapturedCount <= 0) // uncapture - { - wantmode = SDL_GRAB_OFF; - } else // capture - { - wantmode = SDL_GRAB_ON; - } - - if (mReallyCapturedCount < 0) // yuck, imbalance. - { - mReallyCapturedCount = 0; - LL_WARNS() << "ReallyCapture count was < 0" << LL_ENDL; - } - - if (!mFullscreen) /* only bother if we're windowed anyway */ - { + // note: this used to be safe to call nestedly, but in the + // end that's not really a wise usage pattern, so don't. + + if (capture) + mReallyCapturedCount = 1; + else + mReallyCapturedCount = 0; + + bool wantGrab; + if (mReallyCapturedCount <= 0) // uncapture + { + wantGrab = false; + } else // capture + { + wantGrab = true; + } + + if (mReallyCapturedCount < 0) // yuck, imbalance. + { + mReallyCapturedCount = 0; + LL_WARNS() << "ReallyCapture count was < 0" << LL_ENDL; + } + + bool newGrab = wantGrab; + #if LL_X11 - if (mSDL_Display) - { - /* we dirtily mix raw X11 with SDL so that our pointer - isn't (as often) constrained to the limits of the - window while grabbed, which feels nicer and - hopefully eliminates some reported 'sticky pointer' - problems. We use raw X11 instead of - SDL_WM_GrabInput() because the latter constrains - the pointer to the window and also steals all - *keyboard* input from the window manager, which was - frustrating users. */ - int result; - if (wantmode == SDL_GRAB_ON) - { - //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); - maybe_unlock_display(); - if (GrabSuccess == result) - newmode = SDL_GRAB_ON; - else - newmode = SDL_GRAB_OFF; - } else if (wantmode == SDL_GRAB_OFF) - { - //LL_INFOS() << "X11 POINTER UNGRABBY" << LL_ENDL; - newmode = SDL_GRAB_OFF; - //newmode = SDL_WM_GrabInput(SDL_GRAB_OFF); - - 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; + if (!mFullscreen) /* only bother if we're windowed anyway */ + { + if (mSDL_Display) + { + /* we dirtily mix raw X11 with SDL so that our pointer + isn't (as often) constrained to the limits of the + window while grabbed, which feels nicer and + hopefully eliminates some reported 'sticky pointer' + problems. We use raw X11 instead of + SDL_WM_GrabInput() because the latter constrains + the pointer to the window and also steals all + *keyboard* input from the window manager, which was + frustrating users. */ + int result; + if (wantGrab == true) + { + maybe_lock_display(); + result = XGrabPointer(mSDL_Display, mSDL_XWindowID, + True, 0, GrabModeAsync, + GrabModeAsync, + None, None, CurrentTime); + maybe_unlock_display(); + if (GrabSuccess == result) + newGrab = true; + else + newGrab = false; + } + else + { + newGrab = false; + + maybe_lock_display(); + XUngrabPointer(mSDL_Display, CurrentTime); + // Make sure the ungrab happens RIGHT NOW. + XSync(mSDL_Display, False); + maybe_unlock_display(); + } + } + } #endif // LL_X11 - } else { - // pretend we got what we wanted, when really we don't care. - newmode = wantmode; - } - - // return boolean success for whether we ended up in the desired state - return (capture && SDL_GRAB_ON==newmode) || - (!capture && SDL_GRAB_OFF==newmode); -} - -U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey 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 - spoil their day by acquiring the exclusive X11 mouse lock for as - long as ALT is held down, so the window manager can't easily - see what's happening. Tested successfully with Metacity. - And... do the same with CTRL, for other darn WMs. We don't - care about other metakeys as SL doesn't use them with dragging - (for now). */ - - /* We maintain a bitmap of critical keys which are up and down - instead of simply key-counting, because SDL sometimes reports - misbalanced keyup/keydown event pairs to us for whatever reason. */ - - 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; - } - - if (gain) - mGrabbyKeyFlags |= mask; - else - mGrabbyKeyFlags &= ~mask; - - //LL_INFOS() << "mGrabbyKeyFlags=" << mGrabbyKeyFlags << LL_ENDL; - - /* 0 means we don't need to mousegrab, otherwise grab. */ - return mGrabbyKeyFlags; + // return boolean success for whether we ended up in the desired state + return capture == newGrab; +} + +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 + spoil their day by acquiring the exclusive X11 mouse lock for as + long as ALT is held down, so the window manager can't easily + see what's happening. Tested successfully with Metacity. + And... do the same with CTRL, for other darn WMs. We don't + care about other metakeys as SL doesn't use them with dragging + (for now). */ + + /* We maintain a bitmap of critical keys which are up and down + instead of simply key-counting, because SDL sometimes reports + misbalanced keyup/keydown event pairs to us for whatever reason. */ + + 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; + } + + if (gain) + mGrabbyKeyFlags |= mask; + else + mGrabbyKeyFlags &= ~mask; + + //LL_INFOS() << "mGrabbyKeyFlags=" << mGrabbyKeyFlags << LL_ENDL; + + /* 0 means we don't need to mousegrab, otherwise grab. */ + return mGrabbyKeyFlags; } void check_vm_bloat() { #if LL_LINUX - // watch our own VM and RSS sizes, warn if we bloated rapidly - static const std::string STATS_FILE = "/proc/self/stat"; - FILE *fp = fopen(STATS_FILE.c_str(), "r"); - if (fp) - { - static long long last_vm_size = 0; - static long long last_rss_size = 0; - const long long significant_vm_difference = 250 * 1024*1024; - const long long significant_rss_difference = 50 * 1024*1024; - long long this_vm_size = 0; - long long this_rss_size = 0; - - ssize_t res; - size_t dummy; - char *ptr = NULL; - for (int i=0; i<22; ++i) // parse past the values we don't want - { - res = getdelim(&ptr, &dummy, ' ', fp); - if (-1 == res) - { - LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; - goto finally; - } - free(ptr); - ptr = NULL; - } - // 23rd space-delimited entry is vsize - res = getdelim(&ptr, &dummy, ' ', fp); - llassert(ptr); - if (-1 == res) - { - LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; - goto finally; - } - this_vm_size = atoll(ptr); - free(ptr); - ptr = NULL; - // 24th space-delimited entry is RSS - res = getdelim(&ptr, &dummy, ' ', fp); - llassert(ptr); - if (-1 == res) - { - LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; - goto finally; - } - this_rss_size = getpagesize() * atoll(ptr); - free(ptr); - ptr = NULL; - - LL_INFOS() << "VM SIZE IS NOW " << (this_vm_size/(1024*1024)) << " MB, RSS SIZE IS NOW " << (this_rss_size/(1024*1024)) << " MB" << LL_ENDL; - - if (llabs(last_vm_size - this_vm_size) > - significant_vm_difference) - { - if (this_vm_size > last_vm_size) - { - LL_WARNS() << "VM size grew by " << (this_vm_size - last_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; - } - else - { - LL_INFOS() << "VM size shrank by " << (last_vm_size - this_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; - } - } - - if (llabs(last_rss_size - this_rss_size) > - significant_rss_difference) - { - if (this_rss_size > last_rss_size) - { - LL_WARNS() << "RSS size grew by " << (this_rss_size - last_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; - } - else - { - LL_INFOS() << "RSS size shrank by " << (last_rss_size - this_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; - } - } - - last_rss_size = this_rss_size; - last_vm_size = this_vm_size; - -finally: - if (NULL != ptr) - { - free(ptr); - ptr = NULL; - } - fclose(fp); - } + // watch our own VM and RSS sizes, warn if we bloated rapidly + static const std::string STATS_FILE = "/proc/self/stat"; + FILE *fp = fopen(STATS_FILE.c_str(), "r"); + if (fp) + { + static long long last_vm_size = 0; + static long long last_rss_size = 0; + const long long significant_vm_difference = 250 * 1024*1024; + const long long significant_rss_difference = 50 * 1024*1024; + long long this_vm_size = 0; + long long this_rss_size = 0; + + ssize_t res; + size_t dummy; + char *ptr = NULL; + for (int i=0; i<22; ++i) // parse past the values we don't want + { + res = getdelim(&ptr, &dummy, ' ', fp); + if (-1 == res) + { + LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; + goto finally; + } + free(ptr); + ptr = NULL; + } + // 23rd space-delimited entry is vsize + res = getdelim(&ptr, &dummy, ' ', fp); + llassert(ptr); + if (-1 == res) + { + LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; + goto finally; + } + this_vm_size = atoll(ptr); + free(ptr); + ptr = NULL; + // 24th space-delimited entry is RSS + res = getdelim(&ptr, &dummy, ' ', fp); + llassert(ptr); + if (-1 == res) + { + LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; + goto finally; + } + this_rss_size = getpagesize() * atoll(ptr); + free(ptr); + ptr = NULL; + + LL_INFOS() << "VM SIZE IS NOW " << (this_vm_size/(1024*1024)) << " MB, RSS SIZE IS NOW " << (this_rss_size/(1024*1024)) << " MB" << LL_ENDL; + + if (llabs(last_vm_size - this_vm_size) > + significant_vm_difference) + { + if (this_vm_size > last_vm_size) + { + LL_WARNS() << "VM size grew by " << (this_vm_size - last_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + } + else + { + LL_INFOS() << "VM size shrank by " << (last_vm_size - this_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + } + } + + if (llabs(last_rss_size - this_rss_size) > + significant_rss_difference) + { + if (this_rss_size > last_rss_size) + { + LL_WARNS() << "RSS size grew by " << (this_rss_size - last_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + } + else + { + LL_INFOS() << "RSS size shrank by " << (last_rss_size - this_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + } + } + + last_rss_size = this_rss_size; + last_vm_size = this_vm_size; + + finally: + if (NULL != ptr) + { + free(ptr); + ptr = NULL; + } + fclose(fp); + } #endif // LL_LINUX } @@ -1694,38 +1734,22 @@ 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")) { - check_vm_bloat(); + check_vm_bloat(); } } @@ -1743,43 +1767,83 @@ 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); LLCoordGL openGlCoord; convertCoords(winCoord, &openGlCoord); - MASK mask = gKeyboard->currentMask(TRUE); - mCallbacks->handleMouseMove(this, openGlCoord, mask); + MASK mask = gKeyboard->currentMask(TRUE); + mCallbacks->handleMouseMove(this, openGlCoord, mask); + 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; - - 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); - - if (event.key.keysym.unicode) - { - handleUnicodeUTF16(event.key.keysym.unicode, - gKeyboard->currentMask(FALSE)); - } + mKeyVirtualKey = event.key.keysym.sym; + mKeyModifiers = event.key.keysym.mod; + mInputType = "keydown"; + + // 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); + 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"; + + // treat all possible Enter/Return keys the same + if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) + { + mKeyVirtualKey = SDLK_RETURN; + } - if (SDLCheckGrabbyKeys(event.key.keysym.sym, FALSE) == 0) - SDLReallyCaptureInput(FALSE); // part of the fix for SL-13243 + if (SDLCheckGrabbyKeys(mKeyVirtualKey, FALSE) == 0) + SDLReallyCaptureInput(FALSE); // part of the fix for SL-13243 - gKeyboard->handleKeyUp(event.key.keysym.sym, event.key.keysym.mod); - break; + gKeyboard->handleKeyUp(mKeyVirtualKey,mKeyModifiers); + break; case SDL_MOUSEBUTTONDOWN: { @@ -1787,7 +1851,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 +1863,7 @@ void LLWindowSDL::gatherInput() if (++leftClick >= 2) { leftClick = 0; - isDoubleClick = true; + isDoubleClick = true; } } lastLeftDown = now; @@ -1814,7 +1878,7 @@ void LLWindowSDL::gatherInput() if (++rightClick >= 2) { rightClick = 0; - isDoubleClick = true; + isDoubleClick = true; } } lastRightDown = now; @@ -1823,24 +1887,24 @@ void LLWindowSDL::gatherInput() if (event.button.button == SDL_BUTTON_LEFT) // left { if (isDoubleClick) - mCallbacks->handleDoubleClick(this, openGlCoord, mask); + mCallbacks->handleDoubleClick(this, openGlCoord, mask); else - mCallbacks->handleMouseDown(this, openGlCoord, mask); + mCallbacks->handleMouseDown(this, openGlCoord, mask); } 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 - { - mCallbacks->handleMiddleMouseDown(this, openGlCoord, mask); - } + { + mCallbacks->handleMiddleMouseDown(this, openGlCoord, mask); + } else if (event.button.button == 4) // mousewheel up...thanks to X11 for making SDL consider these "buttons". - mCallbacks->handleScrollWheel(this, -1); + mCallbacks->handleScrollWheel(this, -1); else if (event.button.button == 5) // mousewheel down...thanks to X11 for making SDL consider these "buttons". - mCallbacks->handleScrollWheel(this, 1); + mCallbacks->handleScrollWheel(this, 1); break; } @@ -1850,365 +1914,346 @@ 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; - - S32 width = llmax(event.resize.w, (S32)mMinWindowWidth); - S32 height = llmax(event.resize.h, (S32)mMinWindowHeight); - - // *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; - } + 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; - mCallbacks->handleResize(this, width, height); - break; - } - case SDL_ACTIVEEVENT: - if (event.active.state & SDL_APPINPUTFOCUS) + 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! + // <FS:ND> I think is is not + // SDL_SetWindowSize(mWindow, width, height); + // + + 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; - - if (mHaveInputFocus) - mCallbacks->handleFocus(this); - else - mCallbacks->handleFocusLost(this); - } + // 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; + + mCallbacks->handleFocus(this); } - if (event.active.state & SDL_APPACTIVE) + else if( event.window.event == SDL_WINDOWEVENT_FOCUS_LOST ) // <FS:ND> What about SDL_WINDOWEVENT_LEAVE (mouse focus) { - // Change in iconification/minimization state. - if ((!event.active.gain) != mIsMinimized) - { - mIsMinimized = (!event.active.gain); - - 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; - } + // 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); } - break; + 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 ) + { + mIsMinimized = (event.window.event == SDL_WINDOWEVENT_MINIMIZED); + mCallbacks->handleActivate(this, !mIsMinimized); + LL_INFOS() << "SDL deiconification state switched to " << mIsMinimized << LL_ENDL; + } + + break; + } case SDL_QUIT: - if(mCallbacks->handleCloseRequest(this)) - { - // Get the app to initiate cleanup. - mCallbacks->handleQuit(this); - // The app is responsible for calling destroyWindow when done with GL - } + 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; + default: + //LL_INFOS() << "Unhandled SDL event type " << event.type << LL_ENDL; break; - default: - //LL_INFOS() << "Unhandled SDL event type " << event.type << LL_ENDL; - break; } } - - updateCursor(); + + updateCursor(); #if LL_X11 // This is a good time to stop flashing the icon if our mFlashTimer has // expired. if (mFlashing && mFlashTimer.hasExpired()) { - x11_set_urgent(FALSE); - mFlashing = FALSE; + x11_set_urgent(FALSE); + mFlashing = FALSE; } #endif // LL_X11 } static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty) { - SDL_Cursor *sdlcursor = NULL; - SDL_Surface *bmpsurface; - - // Load cursor pixel data from BMP file - bmpsurface = Load_BMP_Resource(filename); - if (bmpsurface && bmpsurface->w%8==0) - { - SDL_Surface *cursurface; - LL_DEBUGS() << "Loaded cursor file " << filename << " " - << 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)); - 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)) - { - // n.b. we already checked that width is a multiple of 8. - const int bitmap_bytes = (cursurface->w * cursurface->h) / 8; - unsigned char *cursor_data = new unsigned char[bitmap_bytes]; - unsigned char *cursor_mask = new unsigned char[bitmap_bytes]; - memset(cursor_data, 0, bitmap_bytes); - memset(cursor_mask, 0, bitmap_bytes); - int i,j; - // Walk the RGBA cursor pixel data, extracting both data and - // mask to build SDL-friendly cursor bitmaps from. The mask - // is inferred by color-keying against 200,200,200 - 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 srcred = pixelp[0]; - U8 srcgreen = pixelp[1]; - U8 srcblue = pixelp[2]; - BOOL mask_bit = (srcred != 200) - || (srcgreen != 200) - || (srcblue != 200); - BOOL data_bit = mask_bit && (srcgreen <= 80);//not 0x80 - unsigned char bit_offset = (cursurface->w/8) * i - + 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); - delete[] cursor_data; - delete[] cursor_mask; - } else { - LL_WARNS() << "CURSOR BLIT FAILURE, cursurface: " << cursurface << LL_ENDL; - } - SDL_FreeSurface(cursurface); - SDL_FreeSurface(bmpsurface); - } else { - LL_WARNS() << "CURSOR LOAD FAILURE " << filename << LL_ENDL; - } - - return sdlcursor; + SDL_Cursor *sdlcursor = NULL; + SDL_Surface *bmpsurface; + + // Load cursor pixel data from BMP file + bmpsurface = Load_BMP_Resource(filename); + if (bmpsurface && bmpsurface->w%8==0) + { + SDL_Surface *cursurface; + LL_DEBUGS() << "Loaded cursor file " << filename << " " + << 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)); + 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)) + { + // n.b. we already checked that width is a multiple of 8. + const int bitmap_bytes = (cursurface->w * cursurface->h) / 8; + unsigned char *cursor_data = new unsigned char[bitmap_bytes]; + unsigned char *cursor_mask = new unsigned char[bitmap_bytes]; + memset(cursor_data, 0, bitmap_bytes); + memset(cursor_mask, 0, bitmap_bytes); + int i,j; + // Walk the RGBA cursor pixel data, extracting both data and + // mask to build SDL-friendly cursor bitmaps from. The mask + // is inferred by color-keying against 200,200,200 + 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 srcred = pixelp[0]; + U8 srcgreen = pixelp[1]; + U8 srcblue = pixelp[2]; + BOOL mask_bit = (srcred != 200) + || (srcgreen != 200) + || (srcblue != 200); + BOOL data_bit = mask_bit && (srcgreen <= 80);//not 0x80 + unsigned char bit_offset = (cursurface->w/8) * i + + 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); + delete[] cursor_data; + delete[] cursor_mask; + } else { + LL_WARNS() << "CURSOR BLIT FAILURE, cursurface: " << cursurface << LL_ENDL; + } + SDL_FreeSurface(cursurface); + SDL_FreeSurface(bmpsurface); + } else { + LL_WARNS() << "CURSOR LOAD FAILURE " << filename << LL_ENDL; + } + + return sdlcursor; } void LLWindowSDL::updateCursor() { - if (ATIbug) { - // cursor-updating is very flaky when this bug is - // present; do nothing. - return; - } - - if (mCurrentCursor != mNextCursor) - { - if (mNextCursor < UI_CURSOR_COUNT) - { - SDL_Cursor *sdlcursor = mSDLCursors[mNextCursor]; - // Try to default to the arrow for any cursors that - // did not load correctly. - if (!sdlcursor && mSDLCursors[UI_CURSOR_ARROW]) - sdlcursor = mSDLCursors[UI_CURSOR_ARROW]; - if (sdlcursor) - SDL_SetCursor(sdlcursor); - } else { - LL_WARNS() << "Tried to set invalid cursor number " << mNextCursor << LL_ENDL; - } - mCurrentCursor = mNextCursor; - } + if (ATIbug) { + // cursor-updating is very flaky when this bug is + // present; do nothing. + return; + } + + if (mCurrentCursor != mNextCursor) + { + if (mNextCursor < UI_CURSOR_COUNT) + { + SDL_Cursor *sdlcursor = mSDLCursors[mNextCursor]; + // Try to default to the arrow for any cursors that + // did not load correctly. + if (!sdlcursor && mSDLCursors[UI_CURSOR_ARROW]) + sdlcursor = mSDLCursors[UI_CURSOR_ARROW]; + if (sdlcursor) + SDL_SetCursor(sdlcursor); + } else { + LL_WARNS() << "Tried to set invalid cursor number " << mNextCursor << LL_ENDL; + } + mCurrentCursor = mNextCursor; + } } void LLWindowSDL::initCursors() { - int i; - // Blank the cursor pointer array for those we may miss. - for (i=0; i<UI_CURSOR_COUNT; ++i) - { - mSDLCursors[i] = NULL; - } - // Pre-make an SDL cursor for each of the known cursor types. - // We hardcode the hotspots - to avoid that we'd have to write - // a .cur file loader. - // NOTE: SDL doesn't load RLE-compressed BMP files. - mSDLCursors[UI_CURSOR_ARROW] = makeSDLCursorFromBMP("llarrow.BMP",0,0); - mSDLCursors[UI_CURSOR_WAIT] = makeSDLCursorFromBMP("wait.BMP",12,15); - mSDLCursors[UI_CURSOR_HAND] = makeSDLCursorFromBMP("hand.BMP",7,10); - mSDLCursors[UI_CURSOR_IBEAM] = makeSDLCursorFromBMP("ibeam.BMP",15,16); - mSDLCursors[UI_CURSOR_CROSS] = makeSDLCursorFromBMP("cross.BMP",16,14); - mSDLCursors[UI_CURSOR_SIZENWSE] = makeSDLCursorFromBMP("sizenwse.BMP",14,17); - mSDLCursors[UI_CURSOR_SIZENESW] = makeSDLCursorFromBMP("sizenesw.BMP",17,17); - mSDLCursors[UI_CURSOR_SIZEWE] = makeSDLCursorFromBMP("sizewe.BMP",16,14); - mSDLCursors[UI_CURSOR_SIZENS] = makeSDLCursorFromBMP("sizens.BMP",17,16); + int i; + // Blank the cursor pointer array for those we may miss. + for (i=0; i<UI_CURSOR_COUNT; ++i) + { + mSDLCursors[i] = NULL; + } + // Pre-make an SDL cursor for each of the known cursor types. + // We hardcode the hotspots - to avoid that we'd have to write + // a .cur file loader. + // NOTE: SDL doesn't load RLE-compressed BMP files. + mSDLCursors[UI_CURSOR_ARROW] = makeSDLCursorFromBMP("llarrow.BMP",0,0); + mSDLCursors[UI_CURSOR_WAIT] = makeSDLCursorFromBMP("wait.BMP",12,15); + mSDLCursors[UI_CURSOR_HAND] = makeSDLCursorFromBMP("hand.BMP",7,10); + mSDLCursors[UI_CURSOR_IBEAM] = makeSDLCursorFromBMP("ibeam.BMP",15,16); + mSDLCursors[UI_CURSOR_CROSS] = makeSDLCursorFromBMP("cross.BMP",16,14); + mSDLCursors[UI_CURSOR_SIZENWSE] = makeSDLCursorFromBMP("sizenwse.BMP",14,17); + mSDLCursors[UI_CURSOR_SIZENESW] = makeSDLCursorFromBMP("sizenesw.BMP",17,17); + mSDLCursors[UI_CURSOR_SIZEWE] = makeSDLCursorFromBMP("sizewe.BMP",16,14); + mSDLCursors[UI_CURSOR_SIZENS] = makeSDLCursorFromBMP("sizens.BMP",17,16); mSDLCursors[UI_CURSOR_SIZEALL] = makeSDLCursorFromBMP("sizeall.BMP", 17, 17); - mSDLCursors[UI_CURSOR_NO] = makeSDLCursorFromBMP("llno.BMP",8,8); - mSDLCursors[UI_CURSOR_WORKING] = makeSDLCursorFromBMP("working.BMP",12,15); - mSDLCursors[UI_CURSOR_TOOLGRAB] = makeSDLCursorFromBMP("lltoolgrab.BMP",2,13); - mSDLCursors[UI_CURSOR_TOOLLAND] = makeSDLCursorFromBMP("lltoolland.BMP",1,6); - mSDLCursors[UI_CURSOR_TOOLFOCUS] = makeSDLCursorFromBMP("lltoolfocus.BMP",8,5); - mSDLCursors[UI_CURSOR_TOOLCREATE] = makeSDLCursorFromBMP("lltoolcreate.BMP",7,7); - mSDLCursors[UI_CURSOR_ARROWDRAG] = makeSDLCursorFromBMP("arrowdrag.BMP",0,0); - mSDLCursors[UI_CURSOR_ARROWCOPY] = makeSDLCursorFromBMP("arrowcop.BMP",0,0); - mSDLCursors[UI_CURSOR_ARROWDRAGMULTI] = makeSDLCursorFromBMP("llarrowdragmulti.BMP",0,0); - mSDLCursors[UI_CURSOR_ARROWCOPYMULTI] = makeSDLCursorFromBMP("arrowcopmulti.BMP",0,0); - mSDLCursors[UI_CURSOR_NOLOCKED] = makeSDLCursorFromBMP("llnolocked.BMP",8,8); - mSDLCursors[UI_CURSOR_ARROWLOCKED] = makeSDLCursorFromBMP("llarrowlocked.BMP",0,0); - mSDLCursors[UI_CURSOR_GRABLOCKED] = makeSDLCursorFromBMP("llgrablocked.BMP",2,13); - mSDLCursors[UI_CURSOR_TOOLTRANSLATE] = makeSDLCursorFromBMP("lltooltranslate.BMP",0,0); - mSDLCursors[UI_CURSOR_TOOLROTATE] = makeSDLCursorFromBMP("lltoolrotate.BMP",0,0); - mSDLCursors[UI_CURSOR_TOOLSCALE] = makeSDLCursorFromBMP("lltoolscale.BMP",0,0); - mSDLCursors[UI_CURSOR_TOOLCAMERA] = makeSDLCursorFromBMP("lltoolcamera.BMP",7,5); - mSDLCursors[UI_CURSOR_TOOLPAN] = makeSDLCursorFromBMP("lltoolpan.BMP",7,5); - mSDLCursors[UI_CURSOR_TOOLZOOMIN] = makeSDLCursorFromBMP("lltoolzoomin.BMP",7,5); + mSDLCursors[UI_CURSOR_NO] = makeSDLCursorFromBMP("llno.BMP",8,8); + mSDLCursors[UI_CURSOR_WORKING] = makeSDLCursorFromBMP("working.BMP",12,15); + mSDLCursors[UI_CURSOR_TOOLGRAB] = makeSDLCursorFromBMP("lltoolgrab.BMP",2,13); + mSDLCursors[UI_CURSOR_TOOLLAND] = makeSDLCursorFromBMP("lltoolland.BMP",1,6); + mSDLCursors[UI_CURSOR_TOOLFOCUS] = makeSDLCursorFromBMP("lltoolfocus.BMP",8,5); + mSDLCursors[UI_CURSOR_TOOLCREATE] = makeSDLCursorFromBMP("lltoolcreate.BMP",7,7); + mSDLCursors[UI_CURSOR_ARROWDRAG] = makeSDLCursorFromBMP("arrowdrag.BMP",0,0); + mSDLCursors[UI_CURSOR_ARROWCOPY] = makeSDLCursorFromBMP("arrowcop.BMP",0,0); + mSDLCursors[UI_CURSOR_ARROWDRAGMULTI] = makeSDLCursorFromBMP("llarrowdragmulti.BMP",0,0); + mSDLCursors[UI_CURSOR_ARROWCOPYMULTI] = makeSDLCursorFromBMP("arrowcopmulti.BMP",0,0); + mSDLCursors[UI_CURSOR_NOLOCKED] = makeSDLCursorFromBMP("llnolocked.BMP",8,8); + mSDLCursors[UI_CURSOR_ARROWLOCKED] = makeSDLCursorFromBMP("llarrowlocked.BMP",0,0); + mSDLCursors[UI_CURSOR_GRABLOCKED] = makeSDLCursorFromBMP("llgrablocked.BMP",2,13); + mSDLCursors[UI_CURSOR_TOOLTRANSLATE] = makeSDLCursorFromBMP("lltooltranslate.BMP",0,0); + mSDLCursors[UI_CURSOR_TOOLROTATE] = makeSDLCursorFromBMP("lltoolrotate.BMP",0,0); + mSDLCursors[UI_CURSOR_TOOLSCALE] = makeSDLCursorFromBMP("lltoolscale.BMP",0,0); + mSDLCursors[UI_CURSOR_TOOLCAMERA] = makeSDLCursorFromBMP("lltoolcamera.BMP",7,5); + mSDLCursors[UI_CURSOR_TOOLPAN] = makeSDLCursorFromBMP("lltoolpan.BMP",7,5); + mSDLCursors[UI_CURSOR_TOOLZOOMIN] = makeSDLCursorFromBMP("lltoolzoomin.BMP",7,5); mSDLCursors[UI_CURSOR_TOOLZOOMOUT] = makeSDLCursorFromBMP("lltoolzoomout.BMP", 7, 5); - mSDLCursors[UI_CURSOR_TOOLPICKOBJECT3] = makeSDLCursorFromBMP("toolpickobject3.BMP",0,0); - mSDLCursors[UI_CURSOR_TOOLPLAY] = makeSDLCursorFromBMP("toolplay.BMP",0,0); - mSDLCursors[UI_CURSOR_TOOLPAUSE] = makeSDLCursorFromBMP("toolpause.BMP",0,0); - mSDLCursors[UI_CURSOR_TOOLMEDIAOPEN] = makeSDLCursorFromBMP("toolmediaopen.BMP",0,0); - mSDLCursors[UI_CURSOR_PIPETTE] = makeSDLCursorFromBMP("lltoolpipette.BMP",2,28); - mSDLCursors[UI_CURSOR_TOOLSIT] = makeSDLCursorFromBMP("toolsit.BMP",20,15); - mSDLCursors[UI_CURSOR_TOOLBUY] = makeSDLCursorFromBMP("toolbuy.BMP",20,15); - mSDLCursors[UI_CURSOR_TOOLOPEN] = makeSDLCursorFromBMP("toolopen.BMP",20,15); - mSDLCursors[UI_CURSOR_TOOLPATHFINDING] = makeSDLCursorFromBMP("lltoolpathfinding.BMP", 16, 16); - mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_START] = makeSDLCursorFromBMP("lltoolpathfindingpathstart.BMP", 16, 16); - mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD] = makeSDLCursorFromBMP("lltoolpathfindingpathstartadd.BMP", 16, 16); - mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_END] = makeSDLCursorFromBMP("lltoolpathfindingpathend.BMP", 16, 16); - mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD] = makeSDLCursorFromBMP("lltoolpathfindingpathendadd.BMP", 16, 16); - mSDLCursors[UI_CURSOR_TOOLNO] = makeSDLCursorFromBMP("llno.BMP",8,8); - - if (getenv("LL_ATI_MOUSE_CURSOR_BUG") != NULL) { - LL_INFOS() << "Disabling cursor updating due to LL_ATI_MOUSE_CURSOR_BUG" << LL_ENDL; - ATIbug = true; - } + mSDLCursors[UI_CURSOR_TOOLPICKOBJECT3] = makeSDLCursorFromBMP("toolpickobject3.BMP",0,0); + mSDLCursors[UI_CURSOR_TOOLPLAY] = makeSDLCursorFromBMP("toolplay.BMP",0,0); + mSDLCursors[UI_CURSOR_TOOLPAUSE] = makeSDLCursorFromBMP("toolpause.BMP",0,0); + mSDLCursors[UI_CURSOR_TOOLMEDIAOPEN] = makeSDLCursorFromBMP("toolmediaopen.BMP",0,0); + mSDLCursors[UI_CURSOR_PIPETTE] = makeSDLCursorFromBMP("lltoolpipette.BMP",2,28); + mSDLCursors[UI_CURSOR_TOOLSIT] = makeSDLCursorFromBMP("toolsit.BMP",20,15); + mSDLCursors[UI_CURSOR_TOOLBUY] = makeSDLCursorFromBMP("toolbuy.BMP",20,15); + mSDLCursors[UI_CURSOR_TOOLOPEN] = makeSDLCursorFromBMP("toolopen.BMP",20,15); + mSDLCursors[UI_CURSOR_TOOLPATHFINDING] = makeSDLCursorFromBMP("lltoolpathfinding.BMP", 16, 16); + mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_START] = makeSDLCursorFromBMP("lltoolpathfindingpathstart.BMP", 16, 16); + mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD] = makeSDLCursorFromBMP("lltoolpathfindingpathstartadd.BMP", 16, 16); + mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_END] = makeSDLCursorFromBMP("lltoolpathfindingpathend.BMP", 16, 16); + mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD] = makeSDLCursorFromBMP("lltoolpathfindingpathendadd.BMP", 16, 16); + mSDLCursors[UI_CURSOR_TOOLNO] = makeSDLCursorFromBMP("llno.BMP",8,8); + + if (getenv("LL_ATI_MOUSE_CURSOR_BUG") != NULL) { + LL_INFOS() << "Disabling cursor updating due to LL_ATI_MOUSE_CURSOR_BUG" << LL_ENDL; + ATIbug = true; + } } void LLWindowSDL::quitCursors() { - int i; - if (mWindow) - { - for (i=0; i<UI_CURSOR_COUNT; ++i) - { - if (mSDLCursors[i]) - { - SDL_FreeCursor(mSDLCursors[i]); - mSDLCursors[i] = NULL; - } - } - } else { - // SDL doesn't refcount cursors, so if the window has - // already been destroyed then the cursors have gone with it. - LL_INFOS() << "Skipping quitCursors: mWindow already gone." << LL_ENDL; - for (i=0; i<UI_CURSOR_COUNT; ++i) - mSDLCursors[i] = NULL; - } + int i; + if (mWindow) + { + for (i=0; i<UI_CURSOR_COUNT; ++i) + { + if (mSDLCursors[i]) + { + SDL_FreeCursor(mSDLCursors[i]); + mSDLCursors[i] = NULL; + } + } + } else { + // SDL doesn't refcount cursors, so if the window has + // already been destroyed then the cursors have gone with it. + LL_INFOS() << "Skipping quitCursors: mWindow already gone." << LL_ENDL; + for (i=0; i<UI_CURSOR_COUNT; ++i) + mSDLCursors[i] = NULL; + } } void LLWindowSDL::captureMouse() { - // SDL already enforces the semantics that captureMouse is - // used for, i.e. that we continue to get mouse events as long - // as a button is down regardless of whether we left the - // window, and in a less obnoxious way than SDL_WM_GrabInput - // which would confine the cursor to the window too. + // SDL already enforces the semantics that captureMouse is + // used for, i.e. that we continue to get mouse events as long + // as a button is down regardless of whether we left the + // window, and in a less obnoxious way than SDL_WM_GrabInput + // which would confine the cursor to the window too. - LL_DEBUGS() << "LLWindowSDL::captureMouse" << LL_ENDL; + LL_DEBUGS() << "LLWindowSDL::captureMouse" << LL_ENDL; } void LLWindowSDL::releaseMouse() { - // see LWindowSDL::captureMouse() - - LL_DEBUGS() << "LLWindowSDL::releaseMouse" << LL_ENDL; + // see LWindowSDL::captureMouse() + + LL_DEBUGS() << "LLWindowSDL::releaseMouse" << LL_ENDL; } void LLWindowSDL::hideCursor() { - if(!mCursorHidden) - { - // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; - mCursorHidden = TRUE; - mHideCursorPermanent = TRUE; - SDL_ShowCursor(0); - } - else - { - // LL_INFOS() << "hideCursor: already hidden" << LL_ENDL; - } + if(!mCursorHidden) + { + // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; + mCursorHidden = TRUE; + mHideCursorPermanent = TRUE; + SDL_ShowCursor(0); + } + else + { + // LL_INFOS() << "hideCursor: already hidden" << LL_ENDL; + } } void LLWindowSDL::showCursor() { - if(mCursorHidden) - { - // LL_INFOS() << "showCursor: showing" << LL_ENDL; - mCursorHidden = FALSE; - mHideCursorPermanent = FALSE; - SDL_ShowCursor(1); - } - else - { - // LL_INFOS() << "showCursor: already visible" << LL_ENDL; - } + if(mCursorHidden) + { + // LL_INFOS() << "showCursor: showing" << LL_ENDL; + mCursorHidden = FALSE; + mHideCursorPermanent = FALSE; + SDL_ShowCursor(1); + } + else + { + // LL_INFOS() << "showCursor: already visible" << LL_ENDL; + } } void LLWindowSDL::showCursorFromMouseMove() { - if (!mHideCursorPermanent) - { - showCursor(); - } + if (!mHideCursorPermanent) + { + showCursor(); + } } void LLWindowSDL::hideCursorUntilMouseMove() { - if (!mHideCursorPermanent) - { - hideCursor(); - mHideCursorPermanent = FALSE; - } + if (!mHideCursorPermanent) + { + hideCursor(); + mHideCursorPermanent = FALSE; + } } - - // // LLSplashScreenSDL - I don't think we'll bother to implement this; it's // fairly obsolete at this point. @@ -2233,272 +2278,128 @@ void LLSplashScreenSDL::hideImpl() { } +S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type) +{ + 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"} }; + switch (type) + { + default: + case OSMB_OK: + oData.flags = SDL_MESSAGEBOX_WARNING; + oData.buttons = btnOk; + oData.numbuttons = 1; + break; + case OSMB_OKCANCEL: + oData.flags = SDL_MESSAGEBOX_INFORMATION; + oData.buttons = btnOkCancel; + oData.numbuttons = 2; + break; + case OSMB_YESNO: + oData.flags = SDL_MESSAGEBOX_INFORMATION; + oData.buttons = btnYesNo; + oData.numbuttons = 2; + break; + } -#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(); + int btn{0}; + if( 0 == SDL_ShowMessageBox( &oData, &btn ) ) + return btn; + return OSBTN_CANCEL; } -S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type) +BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) { - S32 rtn = OSBTN_CANCEL; - - if(gWindowImplementation != NULL) - gWindowImplementation->beforeDialog(); - - if (LLWindowSDL::ll_try_gtk_init()) - { - 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; - break; - case OSMB_OKCANCEL: - messagetype = GTK_MESSAGE_QUESTION; - buttons = GTK_BUTTONS_OK_CANCEL; - break; - case OSMB_YESNO: - messagetype = GTK_MESSAGE_QUESTION; - buttons = GTK_BUTTONS_YES_NO; - 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; -} - -static void color_changed_callback(GtkWidget *widget, - gpointer user_data) -{ - 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(); - - U32 modifiers = 0; // pretend-native modifiers... oh what a tangled web we weave! - - // we go through so many levels of device abstraction that I can't really guess - // what a plugin under GDK under Qt under SL under SDL under X11 considers - // a 'native' modifier mask. this has been sort of reverse-engineered... they *appear* - // to match GDK consts, but that may be co-incidence. - modifiers |= (mKeyModifiers & KMOD_LSHIFT) ? 0x0001 : 0; - modifiers |= (mKeyModifiers & KMOD_RSHIFT) ? 0x0001 : 0;// munge these into the same shift - modifiers |= (mKeyModifiers & KMOD_CAPS) ? 0x0002 : 0; - modifiers |= (mKeyModifiers & KMOD_LCTRL) ? 0x0004 : 0; - modifiers |= (mKeyModifiers & KMOD_RCTRL) ? 0x0004 : 0;// munge these into the same ctrl - modifiers |= (mKeyModifiers & KMOD_LALT) ? 0x0008 : 0;// untested - modifiers |= (mKeyModifiers & KMOD_RALT) ? 0x0008 : 0;// untested - // *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["modifiers"] = (S32)modifiers; - - return result; -} - - -BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ - BOOL rtn = FALSE; - - beforeDialog(); + LLSD result = LLSD::emptyMap(); - if (ll_try_gtk_init()) - { - GtkWidget *win = NULL; + U32 modifiers = 0; // pretend-native modifiers... oh what a tangled web we weave! - 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; -} + // we go through so many levels of device abstraction that I can't really guess + // what a plugin under GDK under Qt under SL under SDL under X11 considers + // a 'native' modifier mask. this has been sort of reverse-engineered... they *appear* + // to match GDK consts, but that may be co-incidence. + modifiers |= (mKeyModifiers & KMOD_LSHIFT) ? 0x0001 : 0; + modifiers |= (mKeyModifiers & KMOD_RSHIFT) ? 0x0001 : 0;// munge these into the same shift + modifiers |= (mKeyModifiers & KMOD_CAPS) ? 0x0002 : 0; + modifiers |= (mKeyModifiers & KMOD_LCTRL) ? 0x0004 : 0; + modifiers |= (mKeyModifiers & KMOD_RCTRL) ? 0x0004 : 0;// munge these into the same ctrl + modifiers |= (mKeyModifiers & KMOD_LALT) ? 0x0008 : 0;// untested + modifiers |= (mKeyModifiers & KMOD_RALT) ? 0x0008 : 0;// untested + // *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). -BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ - return (FALSE); + result["virtual_key"] = (S32)mKeyVirtualKey; + result["virtual_key_win"] = (S32)LLKeyboardSDL::mapSDL2toWin( mKeyVirtualKey ); + result["modifiers"] = (S32)modifiers; + 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) { - char* const argv[] = {(char*)cmd.c_str(), (char*)arg.c_str(), NULL}; - fflush(NULL); - pid_t pid = fork(); - if (pid == 0) - { // 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); - // end ourself by running the command - execv(cmd.c_str(), argv); /* Flawfinder: ignore */ - // if execv returns at all, there was a problem. - LL_WARNS() << "execv failure when trying to start " << cmd << LL_ENDL; - _exit(1); // _exit because we don't want atexit() clean-up! - } else { - if (pid > 0) - { - // parent - wait for child to die - int childExitStatus; - waitpid(pid, &childExitStatus, 0); - } else { - LL_WARNS() << "fork failure." << LL_ENDL; - } - } + char* const argv[] = {(char*)cmd.c_str(), (char*)arg.c_str(), NULL}; + fflush(NULL); + pid_t pid = fork(); + if (pid == 0) + { // 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); + // <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. + LL_WARNS() << "execv failure when trying to start " << cmd << LL_ENDL; + _exit(1); // _exit because we don't want atexit() clean-up! + } else { + if (pid > 0) + { + // parent - wait for child to die + int childExitStatus; + waitpid(pid, &childExitStatus, 0); + } else { + LL_WARNS() << "fork failure." << LL_ENDL; + } + } } #endif @@ -2506,192 +2407,215 @@ void exec_cmd(const std::string& cmd, const std::string& arg) // Must begin with protocol identifier. void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) { - bool found = false; - S32 i; - for (i = 0; i < gURLProtocolWhitelistCount; i++) - { - if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) - { - found = true; - break; - } - } - - if (!found) - { - LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; - return; - } - - LL_INFOS() << "spawn_web_browser: " << escaped_url << LL_ENDL; - + bool found = false; + S32 i; + for (i = 0; i < gURLProtocolWhitelistCount; i++) + { + if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) + { + found = true; + break; + } + } + + if (!found) + { + LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; + return; + } + + LL_INFOS() << "spawn_web_browser: " << escaped_url << LL_ENDL; + #if LL_LINUX # if LL_X11 - if (mSDL_Display) - { - maybe_lock_display(); - // Just in case - before forking. - XSync(mSDL_Display, False); - maybe_unlock_display(); - } + if (mSDL_Display) + { + maybe_lock_display(); + // Just in case - before forking. + XSync(mSDL_Display, False); + maybe_unlock_display(); + } # endif // LL_X11 - std::string cmd, arg; - cmd = gDirUtilp->getAppRODataDir(); - cmd += gDirUtilp->getDirDelimiter(); - cmd += "etc"; - cmd += gDirUtilp->getDirDelimiter(); - cmd += "launch_url.sh"; - arg = escaped_url; - exec_cmd(cmd, arg); + std::string cmd, arg; + cmd = gDirUtilp->getAppRODataDir(); + cmd += gDirUtilp->getDirDelimiter(); + cmd += "etc"; + cmd += gDirUtilp->getDirDelimiter(); + cmd += "launch_url.sh"; + arg = escaped_url; + exec_cmd(cmd, arg); #endif // LL_LINUX - LL_INFOS() << "spawn_web_browser returning." << LL_ENDL; + 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; + return NULL; } void LLWindowSDL::bringToFront() { - // This is currently used when we are 'launched' to a specific - // map position externally. - LL_INFOS() << "bringToFront" << LL_ENDL; + // This is currently used when we are 'launched' to a specific + // map position externally. + LL_INFOS() << "bringToFront" << LL_ENDL; #if LL_X11 - if (mSDL_Display && !mFullscreen) - { - maybe_lock_display(); - XRaiseWindow(mSDL_Display, mSDL_XWindowID); - XSync(mSDL_Display, False); - maybe_unlock_display(); - } + if (mSDL_Display && !mFullscreen) + { + maybe_lock_display(); + XRaiseWindow(mSDL_Display, mSDL_XWindowID); + XSync(mSDL_Display, False); + maybe_unlock_display(); + } #endif // LL_X11 } //static std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() { - // Use libfontconfig to find us a nice ordered list of fallback fonts - // specific to this system. - std::string final_fallback("/usr/share/fonts/truetype/kochi/kochi-gothic.ttf"); - const int max_font_count_cutoff = 40; // fonts are expensive in the current system, don't enumerate an arbitrary number of them - // Our 'ideal' font properties which define the sorting results. - // slant=0 means Roman, index=0 means the first face in a font file - // (the one we actually use), weight=80 means medium weight, - // spacing=0 means proportional spacing. - std::string sort_order("slant=0:index=0:weight=80:spacing=0"); - // elide_unicode_coverage removes fonts from the list whose unicode - // range is covered by fonts earlier in the list. This usually - // removes ~90% of the fonts as redundant (which is great because - // the font list can be huge), but might unnecessarily reduce the - // renderable range if for some reason our FreeType actually fails - // to use some of the fonts we want it to. - const bool elide_unicode_coverage = true; - std::vector<std::string> rtns; - FcFontSet *fs = NULL; - FcPattern *sortpat = NULL; - - LL_INFOS() << "Getting system font list from FontConfig..." << LL_ENDL; - - // If the user has a system-wide language preference, then favor - // fonts from that language group. This doesn't affect the types - // of languages that can be displayed, but ensures that their - // preferred language is rendered from a single consistent font where - // possible. - FL_Locale *locale = NULL; - FL_Success success = FL_FindLocale(&locale, FL_MESSAGES); - if (success != 0) - { - if (success >= 2 && locale->lang) // confident! - { - LL_INFOS("AppInit") << "Language " << locale->lang << LL_ENDL; - LL_INFOS("AppInit") << "Location " << locale->country << LL_ENDL; - LL_INFOS("AppInit") << "Variant " << locale->variant << LL_ENDL; - - LL_INFOS() << "Preferring fonts of language: " - << locale->lang - << LL_ENDL; - sort_order = "lang=" + std::string(locale->lang) + ":" - + sort_order; - } - } - FL_FreeLocale(&locale); - - if (!FcInit()) - { - LL_WARNS() << "FontConfig failed to initialize." << LL_ENDL; - rtns.push_back(final_fallback); - return rtns; - } - - sortpat = FcNameParse((FcChar8*) sort_order.c_str()); - if (sortpat) - { - // Sort the list of system fonts from most-to-least-desirable. - FcResult result; - fs = FcFontSort(NULL, sortpat, elide_unicode_coverage, - NULL, &result); - FcPatternDestroy(sortpat); - } - - int found_font_count = 0; - if (fs) - { - // Get the full pathnames to the fonts, where available, - // which is what we really want. - found_font_count = fs->nfont; - for (int i=0; i<fs->nfont; ++i) - { - FcChar8 *filename; - if (FcResultMatch == FcPatternGetString(fs->fonts[i], - FC_FILE, 0, - &filename) - && filename) - { - rtns.push_back(std::string((const char*)filename)); - if (rtns.size() >= max_font_count_cutoff) - break; // hit limit - } - } - FcFontSetDestroy (fs); - } - - LL_DEBUGS() << "Using font list: " << LL_ENDL; - for (std::vector<std::string>::iterator it = rtns.begin(); - it != rtns.end(); - ++it) - { - LL_DEBUGS() << " file: " << *it << LL_ENDL; - } - LL_INFOS() << "Using " << rtns.size() << "/" << found_font_count << " system fonts." << LL_ENDL; - - rtns.push_back(final_fallback); - return rtns; -} - -#endif // LL_SDL + // Use libfontconfig to find us a nice ordered list of fallback fonts + // specific to this system. + std::string final_fallback("/usr/share/fonts/truetype/kochi/kochi-gothic.ttf"); + const int max_font_count_cutoff = 40; // fonts are expensive in the current system, don't enumerate an arbitrary number of them + // Our 'ideal' font properties which define the sorting results. + // slant=0 means Roman, index=0 means the first face in a font file + // (the one we actually use), weight=80 means medium weight, + // spacing=0 means proportional spacing. + std::string sort_order("slant=0:index=0:weight=80:spacing=0"); + // elide_unicode_coverage removes fonts from the list whose unicode + // range is covered by fonts earlier in the list. This usually + // removes ~90% of the fonts as redundant (which is great because + // the font list can be huge), but might unnecessarily reduce the + // renderable range if for some reason our FreeType actually fails + // to use some of the fonts we want it to. + const bool elide_unicode_coverage = true; + std::vector<std::string> rtns; + FcFontSet *fs = NULL; + FcPattern *sortpat = NULL; + + LL_INFOS() << "Getting system font list from FontConfig..." << LL_ENDL; + + // If the user has a system-wide language preference, then favor + // fonts from that language group. This doesn't affect the types + // of languages that can be displayed, but ensures that their + // preferred language is rendered from a single consistent font where + // possible. + FL_Locale *locale = NULL; + FL_Success success = FL_FindLocale(&locale, FL_MESSAGES); + if (success != 0) + { + if (success >= 2 && locale->lang) // confident! + { + LL_INFOS("AppInit") << "Language " << locale->lang << LL_ENDL; + LL_INFOS("AppInit") << "Location " << locale->country << LL_ENDL; + LL_INFOS("AppInit") << "Variant " << locale->variant << LL_ENDL; + + LL_INFOS() << "Preferring fonts of language: " + << locale->lang + << LL_ENDL; + sort_order = "lang=" + std::string(locale->lang) + ":" + + sort_order; + } + } + FL_FreeLocale(&locale); + + if (!FcInit()) + { + LL_WARNS() << "FontConfig failed to initialize." << LL_ENDL; + rtns.push_back(final_fallback); + return rtns; + } + + sortpat = FcNameParse((FcChar8*) sort_order.c_str()); + if (sortpat) + { + // Sort the list of system fonts from most-to-least-desirable. + FcResult result; + fs = FcFontSort(NULL, sortpat, elide_unicode_coverage, + NULL, &result); + FcPatternDestroy(sortpat); + } + + int found_font_count = 0; + if (fs) + { + // Get the full pathnames to the fonts, where available, + // which is what we really want. + found_font_count = fs->nfont; + for (int i=0; i<fs->nfont; ++i) + { + FcChar8 *filename; + if (FcResultMatch == FcPatternGetString(fs->fonts[i], + FC_FILE, 0, + &filename) + && filename) + { + rtns.push_back(std::string((const char*)filename)); + if (rtns.size() >= max_font_count_cutoff) + break; // hit limit + } + } + FcFontSetDestroy (fs); + } + + LL_DEBUGS() << "Using font list: " << LL_ENDL; + for (std::vector<std::string>::iterator it = rtns.begin(); + it != rtns.end(); + ++it) + { + LL_DEBUGS() << " file: " << *it << LL_ENDL; + } + LL_INFOS() << "Using " << rtns.size() << "/" << found_font_count << " system fonts." << LL_ENDL; + + rtns.push_back(final_fallback); + return rtns; +} + + +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; +} diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h index 7193e6f45a..e922ce592c 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -1,43 +1,43 @@ -/** +/** * @file llwindowsdl.h * @brief SDL implementation of LLWindow class * * $LicenseInfo:firstyear=2001&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 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,184 +46,290 @@ #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() { }; - - // 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); - - /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); - /*virtual*/ F32 getNativeAspectRatio(); - /*virtual*/ F32 getPixelAspectRatio(); - /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } - - /*virtual*/ void beforeDialog(); - /*virtual*/ void afterDialog(); - - /*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b); - - /*virtual*/ void *getPlatformWindow(); - /*virtual*/ void bringToFront(); - - /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); - - static std::vector<std::string> getDynamicFallbackFontList(); - - // Not great that these are public, but they have to be accessible - // by non-class code and it's better than making them global. + 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 + 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; + + BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) override; + + LLWindowResolution *getSupportedResolutions(S32 &num_resolutions) override; + + F32 getNativeAspectRatio() override; + + F32 getPixelAspectRatio() override; + + 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 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(); + + // Not great that these are public, but they have to be accessible + // by non-class code and it's better than making them global. #if LL_X11 - Window mSDL_XWindowID; - Display *mSDL_Display; + 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 (*Lock_Display)(void); + + void (*Unlock_Display)(void); #if LL_X11 - static Window get_SDL_XWindowID(void); - static Display* get_SDL_Display(void); -#endif // LL_X11 + + static Window get_SDL_XWindowID(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(); + 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; - void initCursors(); - void quitCursors(); - void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); + LLSD getNativeKeyData() override; - // Changes display resolution. Returns true if successful - BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); + void initCursors(); - // Go back to last fullscreen display resolution. - BOOL setFullscreenResolution(); + void quitCursors(); - BOOL shouldPostQuit() { return mPostQuit; } + 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); + + // Go back to last fullscreen display resolution. + BOOL setFullscreenResolution(); + + BOOL shouldPostQuit() { return mPostQuit; } protected: - // - // Platform specific methods - // - - // 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 fixWindowSize(void); - U32 SDLCheckGrabbyKeys(SDLKey keysym, BOOL gain); - BOOL SDLReallyCaptureInput(BOOL capture); - - // - // Platform specific variables - // - U32 mGrabbyKeyFlags; - int mReallyCapturedCount; - SDL_Surface * mWindow; - 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; - - int mSDLFlags; - - SDL_Cursor* mSDLCursors[UI_CURSOR_COUNT]; - int mHaveInputFocus; /* 0=no, 1=yes, else unknown */ - int mIsMinimized; /* 0=no, 1=yes, else unknown */ - - friend class LLWindowManager; + // + // Platform specific methods + // + + // 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 fixWindowSize(void); + + U32 SDLCheckGrabbyKeys(U32 keysym, BOOL gain); + + BOOL SDLReallyCaptureInput(BOOL capture); + + // + // Platform specific variables + // + 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; + + int mSDLFlags; + + 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; + + 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 { public: - LLSplashScreenSDL(); - virtual ~LLSplashScreenSDL(); + 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/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 37c498664a..dbbc973f00 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(&sSymPADSOMemoryPool, 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(), sSymPADSOMemoryPool )) + 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) diff --git a/indra/media_plugins/base/media_plugin_base.h b/indra/media_plugins/base/media_plugin_base.h index 38b8226bb3..2e975a5bf2 100644 --- a/indra/media_plugins/base/media_plugin_base.h +++ b/indra/media_plugins/base/media_plugin_base.h @@ -32,6 +32,34 @@ #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 *sSymPADSOMemoryPool = nullptr; + std::vector<apr_dso_handle_t *> sLoadedLibraries; +}; + +extern SymbolGrabber gSymbolGrabber; +#define LL_GRAB_SYM(REQUIRED, SYMBOL_NAME, RETURN, ...) RETURN (*ll##SYMBOL_NAME)(__VA_ARGS__) = nullptr; size_t gRegistered##SYMBOL_NAME = gSymbolGrabber.registerSymbol( { REQUIRED, #SYMBOL_NAME , (apr_dso_handle_sym_t*)&ll##SYMBOL_NAME} ); + +#endif class MediaPluginBase { @@ -46,7 +74,6 @@ public: static void staticReceiveMessage(const char *message_string, void **user_data); protected: - /** Plugin status. */ typedef enum { diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt index 410778114d..bbd2eb222a 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,8 +24,21 @@ 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() + message( "Building with linux volume catcher" ) + set(LINUX_VOLUME_CATCHER linux_volume_catcher.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) find_library(CORESERVICES_LIBRARY CoreServices) @@ -60,6 +65,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.cpp b/indra/media_plugins/cef/linux_volume_catcher.cpp new file mode 100755 index 0000000000..9e6fe461a6 --- /dev/null +++ b/indra/media_plugins/cef/linux_volume_catcher.cpp @@ -0,0 +1,424 @@ +/** + * @file linux_volume_catcher.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.h" +#include <set> +#include <map> +#include <iostream> +extern "C" { +#include <glib.h> +#include <glib-object.h> + +#include <pulse/introspect.h> +#include <pulse/context.h> +#include <pulse/subscribe.h> +#include <pulse/glib-mainloop.h> // There's no special reason why we want the *glib* PA mainloop, but the generic polling implementation seems broken. + +#include "apr_pools.h" +#include "apr_dso.h" +} + +#include "media_plugin_base.h" + +SymbolGrabber gSymbolGrabber; + +#include "linux_volume_catcher_pa_syms.inc" +#include "linux_volume_catcher_paglib_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); +} + +class VolumeCatcherImpl +{ +public: + VolumeCatcherImpl(); + ~VolumeCatcherImpl(); + + void setVolume(F32 volume); + void pump(void); + + // for internal use - can't be private because used from our C callbacks + + bool loadsyms(std::string pulse_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; +}; + +VolumeCatcherImpl::VolumeCatcherImpl() + : mDesiredVolume(0.0f), + mMainloop(nullptr), + mPAContext(nullptr), + mConnected(false), + mGotSyms(false) +{ + init(); +} + +VolumeCatcherImpl::~VolumeCatcherImpl() +{ + cleanup(); +} + +bool VolumeCatcherImpl::loadsyms(std::string pulse_dso_name) +{ + //return grab_pa_syms({pulse_dso_name}); + return gSymbolGrabber.grabSymbols( { pulse_dso_name }) ; +} + +void VolumeCatcherImpl::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) 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 VolumeCatcherImpl::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 VolumeCatcherImpl::setVolume(F32 volume) +{ + mDesiredVolume = volume; + + if (!mGotSyms) return; + + if (mConnected && mPAContext) + { + update_all_volumes(mDesiredVolume); + } + + pump(); +} + +void VolumeCatcherImpl::pump() +{ + gboolean may_block = FALSE; + g_main_context_iteration(g_main_context_default(), may_block); +} + +void VolumeCatcherImpl::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 VolumeCatcherImpl::update_all_volumes(F32 volume) +{ + for (std::set<U32>::iterator it = mSinkInputIndices.begin(); + it != mSinkInputIndices.end(); ++it) + { + update_index_volume(*it, volume); + } +} + +void VolumeCatcherImpl::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); +} + +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; +} + +void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *sii, int eol, void *userdata) +{ + VolumeCatcherImpl *impl = dynamic_cast<VolumeCatcherImpl*>((VolumeCatcherImpl*)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) +{ + VolumeCatcherImpl *impl = dynamic_cast<VolumeCatcherImpl*>((VolumeCatcherImpl*)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) +{ + VolumeCatcherImpl *impl = dynamic_cast<VolumeCatcherImpl*>((VolumeCatcherImpl*)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:; + } +} + +///////////////////////////////////////////////////// + +VolumeCatcher::VolumeCatcher() +{ + pimpl = new VolumeCatcherImpl(); +} + +VolumeCatcher::~VolumeCatcher() +{ + delete pimpl; + pimpl = nullptr; +} + +void VolumeCatcher::setVolume(F32 volume) +{ + llassert(pimpl); + pimpl->setVolume(volume); +} + +void VolumeCatcher::setPan(F32 pan) +{ + // TODO: implement this (if possible) +} + +void VolumeCatcher::pump() +{ + llassert(pimpl); + pimpl->pump(); +} diff --git a/indra/media_plugins/cef/linux_volume_catcher_pa_syms.inc b/indra/media_plugins/cef/linux_volume_catcher_pa_syms.inc new file mode 100755 index 0000000000..4533362e61 --- /dev/null +++ b/indra/media_plugins/cef/linux_volume_catcher_pa_syms.inc @@ -0,0 +1,21 @@ +// required symbols to grab +LL_GRAB_SYM(true, pa_context_connect, int, pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api) +LL_GRAB_SYM(true, pa_context_disconnect, void, pa_context *c) +LL_GRAB_SYM(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(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(true, pa_context_get_state, pa_context_state_t, pa_context *c) +LL_GRAB_SYM(true, pa_context_new_with_proplist, pa_context*, pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist) +LL_GRAB_SYM(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(true, pa_context_set_state_callback, void, pa_context *c, pa_context_notify_cb_t cb, void *userdata) +LL_GRAB_SYM(true, pa_context_set_subscribe_callback, void, pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) +LL_GRAB_SYM(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(true, pa_context_unref, void, pa_context *c) +LL_GRAB_SYM(true, pa_cvolume_set, pa_cvolume*, pa_cvolume *a, unsigned channels, pa_volume_t v) +LL_GRAB_SYM(true, pa_operation_unref, void, pa_operation *o) +LL_GRAB_SYM(true, pa_proplist_free, void, pa_proplist* p) +LL_GRAB_SYM(true, pa_proplist_gets, const char*, pa_proplist *p, const char *key) +LL_GRAB_SYM(true, pa_proplist_new, pa_proplist*, void) +LL_GRAB_SYM(true, pa_proplist_sets, int, pa_proplist *p, const char *key, const char *value) +LL_GRAB_SYM(true, pa_sw_volume_from_linear, pa_volume_t, double v) + +// optional symbols to grab diff --git a/indra/media_plugins/cef/linux_volume_catcher_paglib_syms.inc b/indra/media_plugins/cef/linux_volume_catcher_paglib_syms.inc new file mode 100755 index 0000000000..5fba60c188 --- /dev/null +++ b/indra/media_plugins/cef/linux_volume_catcher_paglib_syms.inc @@ -0,0 +1,6 @@ +// required symbols to grab +LL_GRAB_SYM(true, pa_glib_mainloop_free, void, pa_glib_mainloop* g) +LL_GRAB_SYM(true, pa_glib_mainloop_get_api, pa_mainloop_api*, pa_glib_mainloop* g) +LL_GRAB_SYM(true, pa_glib_mainloop_new, pa_glib_mainloop *, GMainContext *c) + +// optional symbols to grab diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 43d3a32e64..60d91753d0 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"); @@ -1050,6 +1050,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 +1102,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/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 2e4baaa9eb..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 d1559089c8..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 e7b31bec94..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 932aaffa1b..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 29d65fa4e9..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 352b63583e..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 6bc272c009..6bc272c009 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..e5abf22203 --- /dev/null +++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc @@ -0,0 +1,67 @@ +LL_GRAB_SYM(true, gst_buffer_new, GstBuffer*, void) +LL_GRAB_SYM(true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*) +LL_GRAB_SYM(true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err) +LL_GRAB_SYM(true, gst_message_get_type, GType, void) +LL_GRAB_SYM(true, gst_message_type_get_name, const gchar*, GstMessageType type) +LL_GRAB_SYM(true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GRAB_SYM(true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GRAB_SYM(true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending) +LL_GRAB_SYM(true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state) +LL_GRAB_SYM(true, gst_object_unref, void, gpointer object) +LL_GRAB_SYM(true, gst_object_get_type, GType, void) +LL_GRAB_SYM(true, gst_pipeline_get_type, GType, void) +LL_GRAB_SYM(true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline) +LL_GRAB_SYM(true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data) +LL_GRAB_SYM(true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name) +LL_GRAB_SYM(true, gst_element_get_type, GType, void) +LL_GRAB_SYM(true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template) +LL_GRAB_SYM(true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp) +LL_GRAB_SYM(true, gst_caps_from_string, GstCaps *, const gchar *string) +LL_GRAB_SYM(true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index) +LL_GRAB_SYM(true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type) +LL_GRAB_SYM(true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value) +LL_GRAB_SYM(true, gst_structure_get_value, const GValue *, const GstStructure *structure, const gchar *fieldname) +LL_GRAB_SYM(true, gst_value_get_fraction_numerator, gint, const GValue *value) +LL_GRAB_SYM(true, gst_value_get_fraction_denominator, gint, const GValue *value) +LL_GRAB_SYM(true, gst_structure_get_name, const gchar *, const GstStructure *structure) +LL_GRAB_SYM(true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64) + +LL_GRAB_SYM(false, gst_registry_fork_set_enabled, void, gboolean enabled) +LL_GRAB_SYM(false, gst_segtrap_set_enabled, void, gboolean enabled) +LL_GRAB_SYM(false, gst_message_parse_buffering, void, GstMessage *message, gint *percent) +LL_GRAB_SYM(false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GRAB_SYM(false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur) +LL_GRAB_SYM(false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano) + +LL_GRAB_SYM( true, gst_message_parse_tag, void, GstMessage *, GstTagList **) +LL_GRAB_SYM( true, gst_tag_list_foreach, void, const GstTagList *, GstTagForeachFunc, gpointer) +LL_GRAB_SYM( true, gst_tag_list_get_tag_size, guint, const GstTagList *, const gchar *) +LL_GRAB_SYM( true, gst_tag_list_get_value_index, const GValue *, const GstTagList *, const gchar *, guint) + +LL_GRAB_SYM( true, gst_caps_new_simple, GstCaps*, const char *, const char*, ... ) + +LL_GRAB_SYM( true, gst_sample_get_caps, GstCaps*, GstSample* ) +LL_GRAB_SYM( true, gst_sample_get_buffer, GstBuffer*, GstSample* ) +LL_GRAB_SYM( true, gst_buffer_map, gboolean, GstBuffer*, GstMapInfo*, GstMapFlags ) +LL_GRAB_SYM( true, gst_buffer_unmap, void, GstBuffer*, GstMapInfo* ) + +LL_GRAB_SYM( true, gst_app_sink_set_caps, void, GstAppSink*, GstCaps const* ) +LL_GRAB_SYM( true, gst_app_sink_pull_sample, GstSample*, GstAppSink* ) + +LL_GRAB_SYM( true, g_free, void, gpointer ) +LL_GRAB_SYM( true, g_error_free, void, GError* ) + +LL_GRAB_SYM( true, g_main_context_pending, gboolean, GMainContext* ) +LL_GRAB_SYM( true, g_main_loop_get_context, GMainContext*, GMainLoop* ) +LL_GRAB_SYM( true, g_main_context_iteration, gboolean, GMainContext*, gboolean ) +LL_GRAB_SYM( true, g_main_loop_new, GMainLoop*, GMainContext*, gboolean ) +LL_GRAB_SYM( true, g_main_loop_quit, void, GMainLoop* ) +LL_GRAB_SYM( true, gst_mini_object_unref, void, GstMiniObject* ) +LL_GRAB_SYM( true, g_object_set, void, gpointer, gchar const*, ... ) +LL_GRAB_SYM( true, g_source_remove, gboolean, guint ) +LL_GRAB_SYM( true, g_value_get_string, gchar const*, GValue const* ) + +LL_GRAB_SYM( true, gst_debug_set_active, void, gboolean ) +LL_GRAB_SYM( true, gst_debug_add_log_function, void, GstLogFunction, gpointer, GDestroyNotify ) +LL_GRAB_SYM( true, gst_debug_set_default_threshold, void, GstDebugLevel ) +LL_GRAB_SYM( true, gst_debug_message_get , gchar const*, GstDebugMessage * )
\ No newline at end of file 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..dbc544d96b --- /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 gSymbolGrabber; + +#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( !gSymbolGrabber.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 + + gSymbolGrabber.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 a6ae041935..f2b99a60ac 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1434,7 +1434,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) @@ -2369,4 +2368,3 @@ if (LL_TESTS) endif (LL_TESTS) check_message_template(${VIEWER_BINARY_NAME}) - diff --git a/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl index 1a85d70256..a33c4cc58b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl @@ -27,11 +27,11 @@ 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 acd32a81b3..0f9bd131fd 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -78,7 +78,7 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); float getAmbientClamp(); -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); 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 52e71edcac..35848ff4cd 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl @@ -55,7 +55,7 @@ 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); diff --git a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl index 8430cca325..ab43262c0e 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 ec1e49eeb4..83c3845d18 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl @@ -53,7 +53,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); @@ -276,10 +276,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 906e66ecc8..d19ec89cbc 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl @@ -785,7 +785,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 5e8fe9301a..f4a1df9c2c 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl @@ -70,7 +70,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); diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index eb3ead433b..7d26c81283 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -58,17 +58,6 @@ 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 @@ -98,25 +87,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 +110,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 f23ce13608..c10007f1b5 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 d6a4c41497..547a1c49cd 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -108,7 +108,7 @@ #include "llscenemonitor.h" #include "llavatarrenderinfoaccountant.h" #include "lllocalbitmaps.h" -#include "llperfstats.h" +#include "llperfstats.h" #include "llgltfmateriallist.h" // Linden library includes @@ -263,10 +263,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) @@ -563,7 +559,7 @@ static void settings_to_globals() gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc"); gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates"); LLWorldMapView::setScaleSetting(gSavedSettings.getF32("MapScale")); - + #if LL_DARWIN LLWindowMacOSX::sUseMultGL = gSavedSettings.getBOOL("RenderAppleUseMultGL"); gHiDPISupport = gSavedSettings.getBOOL("RenderHiDPI"); @@ -1129,7 +1125,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) { @@ -1343,7 +1339,7 @@ bool LLAppViewer::frame() } } else - { + { try { ret = doFrame(); @@ -1754,7 +1750,7 @@ bool LLAppViewer::cleanup() LLViewerCamera::deleteSingleton(); LL_INFOS() << "Viewer disconnected" << LL_ENDL; - + if (gKeyboard) { gKeyboard->resetKeys(); @@ -2213,7 +2209,7 @@ bool LLAppViewer::initThreads() } // The only configurable thread count right now is ImageDecode - // The viewer typically starts around 8 threads not including image decode, + // The viewer typically starts around 8 threads not including image decode, // so try to leave at least one core free S32 image_decode_count = llclamp(cores - 9, 1, 8); threadCounts["ImageDecode"] = image_decode_count; @@ -2289,7 +2285,7 @@ void LLAppViewer::initLoggingAndGetLastDuration() if (mSecondInstance) { LLFile::mkdir(gDirUtilp->getDumpLogsDirPath()); - + LLUUID uid; uid.generate(); LLError::logToFile(gDirUtilp->getDumpLogsDirPath(uid.asString() + ".log")); @@ -4210,8 +4206,8 @@ bool LLAppViewer::initCache() const F64 disk_cache_percent = gSavedSettings.getF32("DiskCachePercentOfTotal"); const F64 texture_cache_percent = 100.0 - disk_cache_percent; - // note that the maximum size of this cache is defined as a percentage of the - // total cache size - the 'CacheSize' pref - for all caches. + // note that the maximum size of this cache is defined as a percentage of the + // total cache size - the 'CacheSize' pref - for all caches. const uintmax_t disk_cache_size = uintmax_t(cache_total_size * disk_cache_percent / 100); const bool enable_cache_debug_info = gSavedSettings.getBOOL("EnableDiskCacheDebugInfo"); @@ -4225,7 +4221,7 @@ bool LLAppViewer::initCache() gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion()); //texture cache version was bumped up in Simple Cache Viewer, and at this point old vfs files are not needed - remove_vfs_files = true; + remove_vfs_files = true; } } @@ -4282,7 +4278,7 @@ bool LLAppViewer::initCache() { LLDiskCache::getInstance()->removeOldVFSFiles(); } - + if (mPurgeCache) { LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); @@ -5693,4 +5689,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 9f58f90326..0e7610ebf3 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,22 +156,75 @@ 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) { - // 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); + 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() +{ + 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) - { - LLAppViewer* pApp = LLAppViewer::instance(); - pApp->initCrashReporting(); - } + 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 ) + { + if( nCrashSubmitBehavior == CRASH_BEHAVIOR_ASK ) + gCrashBehavior = "ask"; + else + gCrashBehavior = "send"; + setupBreadpad(); + } #endif return success; @@ -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. + LL_INFOS() << "Was asked to go to slurl: " << slurl << LL_ENDL; - 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); - - lldbus_g_connection_register_g_object(server->connection, VIEWERAPI_PATH, G_OBJECT(server)); - - DBusGProxy *serverproxy = lldbus_g_proxy_new_for_name(server->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); + std::string url = slurl; + LLMediaCtrl* web = NULL; + const bool trusted_browser = false; + LLURLDispatcher::dispatch(url, "", web, trusted_browser); +} - 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_object_unref(serverproxy); - } - else - { - g_warning("Unable to connect to dbus: %s", error->message); - } +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; - if (error) - g_error_free(error); - } + g_variant_get (parameters, "(&s)", &slurl); + dispatchSLURL(slurl); } -gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **success_rtn, GError **error) +GDBusNodeInfo *gBusNodeInfo = nullptr; +static const GDBusInterfaceVTable interface_vtable = + { + DoMethodeCall + }; +static void busAcquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { - bool success = false; + 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); +} - LL_INFOS() << "Was asked to go to slurl: " << slurl << LL_ENDL; +static void nameAcquired(GDBusConnection *connection, const gchar *name, gpointer user_data) +{ +} - 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)) - { - return false; // failed - } + auto *pBus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, nullptr); - bool success = false; - DBusGConnection *bus; - GError *error = NULL; + if( !pBus ) + { + LL_WARNS() << "Getting dbus failed." << LL_ENDL; + return false; + } - g_type_init(); - - bus = lldbus_g_bus_get (DBUS_BUS_SESSION, &error); - if (bus) - { - gboolean rtn = FALSE; - DBusGProxy *remote_object = - lldbus_g_proxy_new_for_name(bus, VIEWERAPI_SERVICE, VIEWERAPI_PATH, VIEWERAPI_INTERFACE); + auto pProxy = g_dbus_proxy_new_sync(pBus, G_DBUS_PROXY_FLAGS_NONE, nullptr, + VIEWERAPI_SERVICE, VIEWERAPI_PATH, + VIEWERAPI_INTERFACE, nullptr, nullptr); - 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; - } + if( !pProxy ) + { + LL_WARNS() << "Cannot create new dbus proxy." << LL_ENDL; + g_object_unref( pBus ); + return false; + } - g_object_unref(G_OBJECT(remote_object)); - } - else - { - LL_WARNS() << "Couldn't connect to session bus: " << error->message << LL_ENDL; - } + auto *pArgs = g_variant_new( "(s)", url.c_str() ); + if( !pArgs ) + { + LL_WARNS() << "Cannot create new variant." << LL_ENDL; + g_object_unref( pBus ); + return false; + } - if (error) - g_error_free(error); - - return success; + auto pRes = g_dbus_proxy_call_sync(pProxy, + "GoSLURL", + pArgs, + G_DBUS_CALL_FLAGS_NONE, + -1, nullptr, nullptr); + + + + 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 0289c43043..abe62c9289 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 5d5fcaa3d6..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 6ac30bd9b8..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 3eee25b53d..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/llchathistory.cpp b/indra/newview/llchathistory.cpp index b9bf432581..eddae953a7 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -1190,7 +1190,7 @@ LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename); if (header) header->setup(chat, style_params, args); - return header; + return header; } void LLChatHistory::onClickMoreText() diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp index 97b16a5e93..e027ddaeb0 100644 --- a/indra/newview/llconversationloglist.cpp +++ b/indra/newview/llconversationloglist.cpp @@ -93,9 +93,10 @@ 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); - LLMenuGL::showPopup(this, context_menu, x, y); + if (context_menu && size()) + context_menu->updateParent(LLMenuGL::sMenuContainer); + + LLMenuGL::showPopup(this, context_menu, x, y); } return handled; diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index 01790ad19e..d1c251bfc1 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldirpicker.cpp * @brief OS-specific file picker * * $LicenseInfo:firstyear=2001&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$ */ @@ -41,6 +41,10 @@ # include "llfilepicker.h" #endif +#ifdef LL_FLTK + #include "FL/Fl.H" + #include "FL/Fl_Native_File_Chooser.H" +#endif // // Globals // @@ -55,7 +59,7 @@ LLDirPicker LLDirPicker::sInstance; // Implementation // -// utility function to check if access to local file system via file browser +// utility function to check if access to local file system via file browser // is enabled and if not, tidy up and indicate we're not allowed to do this. bool LLDirPicker::check_local_file_access_enabled() { @@ -107,7 +111,7 @@ BOOL LLDirPicker::getDir(std::string* filename, bool blocking) BOOL success = FALSE; - + if (blocking) { // Modal, so pause agent @@ -178,7 +182,7 @@ void LLDirPicker::reset() BOOL LLDirPicker::getDir(std::string* filename, bool blocking) { LLFilePicker::ELoadFilter filter=LLFilePicker::FFLOAD_DIRECTORY; - + return mFilePicker->getOpenFile(filter, true); } @@ -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,38 +231,43 @@ 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 -LLDirPicker::LLDirPicker() +LLDirPicker::LLDirPicker() { reset(); } @@ -289,7 +306,7 @@ void LLDirPickerThread::getFile() #endif } -//virtual +//virtual void LLDirPickerThread::run() { #if LL_WINDOWS @@ -303,7 +320,7 @@ void LLDirPickerThread::run() if (picker.getDir(&mProposedName, blocking)) { mResponses.push_back(picker.getDirName()); - } + } { LLMutexLock lock(sMutex); diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h index 52febe4523..a1571bcb16 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 c1776705f9..698ba0c01e 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llface.cpp * @brief LLFace class implementation * * $LicenseInfo:firstyear=2001&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$ */ @@ -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"); @@ -87,7 +81,7 @@ The resulting texture coordinate <u,v> is: */ void planarProjection(LLVector2 &tc, const LLVector4a& normal, const LLVector4a ¢er, const LLVector4a& vec) -{ +{ LLVector4a binormal; F32 d = normal[0]; @@ -146,7 +140,7 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) //special value to indicate uninitialized position mIndicesIndex = 0xFFFFFFFF; - + for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) { mIndexInTex[i] = 0; @@ -188,7 +182,7 @@ void LLFace::destroy() mTexture[i] = NULL; } } - + if (isState(LLFace::PARTICLE)) { clearState(LLFace::PARTICLE); @@ -215,7 +209,7 @@ void LLFace::destroy() } } } - + setDrawInfo(NULL); mDrawablep = NULL; @@ -262,11 +256,11 @@ void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep) } mDrawPoolp = new_pool; } - + setTexture(texturep) ; } -void LLFace::setTexture(U32 ch, LLViewerTexture* tex) +void LLFace::setTexture(U32 ch, LLViewerTexture* tex) { llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); @@ -278,8 +272,8 @@ void LLFace::setTexture(U32 ch, LLViewerTexture* tex) if(mTexture[ch].notNull()) { mTexture[ch]->removeFace(ch, this) ; - } - + } + if(tex) { tex->addFace(ch, this) ; @@ -288,7 +282,7 @@ void LLFace::setTexture(U32 ch, LLViewerTexture* tex) mTexture[ch] = tex ; } -void LLFace::setTexture(LLViewerTexture* tex) +void LLFace::setTexture(LLViewerTexture* tex) { setDiffuseMap(tex); } @@ -362,7 +356,7 @@ void LLFace::switchTexture(U32 ch, LLViewerTexture* new_texture) getViewerObject()->changeTEImage(mTEOffset, new_texture) ; } - setTexture(ch, new_texture) ; + setTexture(ch, new_texture) ; dirtyTexture(); } @@ -396,7 +390,7 @@ void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align) //allocate vertices in blocks of 4 for alignment num_vertices = (num_vertices + 0x3) & ~0x3; } - + if (mGeomCount != num_vertices || mIndicesCount != num_indices) { @@ -408,11 +402,11 @@ void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align) llassert(verify()); } -void LLFace::setGeomIndex(U16 idx) -{ +void LLFace::setGeomIndex(U16 idx) +{ if (mGeomIndex != idx) { - mGeomIndex = idx; + mGeomIndex = idx; mVertexBuffer = NULL; } } @@ -437,15 +431,15 @@ void LLFace::setTextureIndex(U8 index) } } -void LLFace::setIndicesIndex(S32 idx) -{ +void LLFace::setIndicesIndex(S32 idx) +{ if (mIndicesIndex != idx) { - mIndicesIndex = idx; + mIndicesIndex = idx; mVertexBuffer = NULL; } } - + //============================================================================ U16 LLFace::getGeometryAvatar( @@ -484,7 +478,7 @@ U16 LLFace::getGeometry(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &no mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount); } - + return mGeomIndex; } @@ -511,7 +505,7 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) mDrawablep->getSpatialGroup()->rebuildGeom(); mDrawablep->getSpatialGroup()->rebuildMesh(); - + if(mVertexBuffer.isNull()) { return; @@ -520,7 +514,7 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) if (mGeomCount > 0 && mIndicesCount > 0) { gGL.getTexUnit(0)->bind(imagep); - + gGL.pushMatrix(); if (mDrawablep->isActive()) { @@ -532,7 +526,7 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) } gGL.diffuseColor4fv(color.mV); - + if (mDrawablep->isState(LLDrawable::RIGGED)) { #if 0 // TODO -- there is no way this won't destroy our GL machine as implemented, rewrite it to not rely on software skinning @@ -730,7 +724,7 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of F32 t = tex_coord.mV[1]; // Texture transforms are done about the center of the face. - s -= 0.5; + s -= 0.5; t -= 0.5; // Handle rotation @@ -743,7 +737,7 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of t *= magT; // Then offset - s += offS + 0.5f; + s += offS + 0.5f; t += offT + 0.5f; tex_coord.mV[0] = s; @@ -751,17 +745,17 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of } // Transform the texture coordinates for this face. -static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVector4Logical& mask, const LLVector4a& rot0, const LLVector4a& rot1, const LLVector4a& offset, const LLVector4a& scale) +static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVector4Logical& mask, const LLVector4a& rot0, const LLVector4a& rot1, const LLVector4a& offset, const LLVector4a& scale) { //tex coord is two coords, <s0, t0, s1, t1> LLVector4a st; // Texture transforms are done about the center of the face. st.setAdd(tex_coord, trans); - + // Handle rotation LLVector4a rot_st; - + // <s0 * cosAng, s0*-sinAng, s1*cosAng, s1*-sinAng> LLVector4a s0; s0.splat(st, 0); @@ -770,9 +764,9 @@ static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVect LLVector4a ss; ss.setSelectWithMask(mask, s1, s0); - LLVector4a a; + LLVector4a a; a.setMul(rot0, ss); - + // <t0*sinAng, t0*cosAng, t1*sinAng, t1*cosAng> LLVector4a t0; t0.splat(st, 1); @@ -783,7 +777,7 @@ static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVect LLVector4a b; b.setMul(rot1, tt); - + st.setAdd(a,b); // Then scale @@ -803,7 +797,7 @@ bool less_than_max_mag(const LLVector4a& vec) val.setAbs(vec); S32 lt = val.lessThan(MAX_MAG).getGatheredBits() & 0x7; - + return lt == 0x7; } @@ -822,31 +816,30 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, } const LLVolumeFace &face = volume.getVolumeFace(f); - - LL_DEBUGS("RiggedBox") << "updating extents for face " << f - << " starting extents " << mExtents[0] << ", " << mExtents[1] - << " starting vf extents " << face.mExtents[0] << ", " << face.mExtents[1] + + LL_DEBUGS("RiggedBox") << "updating extents for face " << f + << " starting extents " << mExtents[0] << ", " << mExtents[1] + << " starting vf extents " << face.mExtents[0] << ", " << face.mExtents[1] << " num verts " << face.mNumVertices << LL_ENDL; // MAINT-8264 - stray vertices, especially in low LODs, cause bounding box errors. - if (face.mNumVertices < 3) + if (face.mNumVertices < 3) { - LL_DEBUGS("RiggedBox") << "skipping face " << f << ", bad num vertices " + LL_DEBUGS("RiggedBox") << "skipping face " << f << ", bad num vertices " << face.mNumVertices << " " << face.mNumIndices << " " << face.mWeights << LL_ENDL; return FALSE; } - + //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])); matMulBoundBox(mat_vert, face.mExtents, mExtents); - LL_DEBUGS("RiggedBox") << "updated extents for face " << f + LL_DEBUGS("RiggedBox") << "updated extents for face " << f << " bbox gave extents " << mExtents[0] << ", " << mExtents[1] << LL_ENDL; if (!mDrawablep->isActive()) @@ -855,11 +848,11 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, offset.load3(mDrawablep->getRegion()->getOriginAgent().mV); mExtents[0].add(offset); mExtents[1].add(offset); - LL_DEBUGS("RiggedBox") << "updating extents for face " << f + LL_DEBUGS("RiggedBox") << "updating extents for face " << f << " not active, added offset " << offset << LL_ENDL; } - LL_DEBUGS("RiggedBox") << "updated extents for face " << f + LL_DEBUGS("RiggedBox") << "updated extents for face " << f << " to " << mExtents[0] << ", " << mExtents[1] << LL_ENDL; LLVector4a t; t.setAdd(mExtents[0],mExtents[1]); @@ -886,7 +879,7 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, const LLVector4a& position, const LLVector4a& normal) { LLVector2 tc = surface_coord; - + const LLTextureEntry *tep = getTextureEntry(); if (tep == NULL) @@ -901,28 +894,28 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, const LLVector4a& po if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) { LLVector4a& center = *(mDrawablep->getVOVolume()->getVolume()->getVolumeFace(mTEOffset).mCenter); - + LLVector4a volume_position; LLVector3 v_position(position.getF32ptr()); volume_position.load3(mDrawablep->getVOVolume()->agentPositionToVolume(v_position).mV); - + if (!mDrawablep->getVOVolume()->isVolumeGlobal()) { LLVector4a scale; scale.load3(mVObjp->getScale().mV); volume_position.mul(scale); } - + LLVector4a volume_normal; LLVector3 v_normal(normal.getF32ptr()); volume_normal.load3(mDrawablep->getVOVolume()->agentDirectionToVolume(v_normal).mV); volume_normal.normalize3fast(); - + if (texgen == LLTextureEntry::TEX_GEN_PLANAR) { planarProjection(tc, volume_normal, center, volume_position); - } + } } if (mTextureMatrix) // if we have a texture matrix, use it @@ -931,14 +924,14 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, const LLVector4a& po tc3 = tc3 * *mTextureMatrix; tc = LLVector2(tc3); } - + else // otherwise use the texture entry parameters { xform(tc, cos(tep->getRotation()), sin(tep->getRotation()), tep->mOffsetS, tep->mOffsetT, tep->mScaleS, tep->mScaleT); } - + return tc; } @@ -979,7 +972,7 @@ void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_po } // Returns the necessary texture transform to align this face's TE to align_to's TE -bool LLFace::calcAlignedPlanarTE(const LLFace* align_to, LLVector2* res_st_offset, +bool LLFace::calcAlignedPlanarTE(const LLFace* align_to, LLVector2* res_st_offset, LLVector2* res_st_scale, F32* res_st_rot, LLRender::eTexIndex map) const { if (!align_to) @@ -1102,13 +1095,13 @@ bool LLFace::canRenderAsMask() return false; } - + LLMaterial* mat = te->getMaterialParams(); if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) { return false; } - + if ((te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha (te->getGlow() == 0.f) && // glowing masks are hard to implement - don't mask getTexture()->getIsAlphaMask()) // texture actually qualifies for masking (lazily recalculated but expensive) @@ -1172,7 +1165,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, const LLVolumeFace &vf = volume.getVolumeFace(face_index); S32 num_vertices = (S32)vf.mNumVertices; S32 num_indices = (S32) vf.mNumIndices; - + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE)) { updateRebuildFlags(); @@ -1218,7 +1211,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLStrider<LLVector4> wght; BOOL full_rebuild = force_rebuild || mDrawablep->isState(LLDrawable::REBUILD_VOLUME); - + BOOL global_volume = mDrawablep->getVOVolume()->isVolumeGlobal(); LLVector3 scale; if (global_volume) @@ -1229,7 +1222,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, { scale = mVObjp->getScale(); } - + bool rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION); bool rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR); bool rebuild_emissive = rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE); @@ -1245,7 +1238,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, BOOL is_global = is_static; LLVector3 center_sum(0.f, 0.f, 0.f); - + if (is_global) { setState(GLOBAL); @@ -1264,13 +1257,13 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_color) { //decide if shiny goes in alpha channel of color - if (tep && + if (tep && !isInAlphaPool()) // <--- alpha channel MUST contain transparency, not shiny { LLMaterial* mat = tep->getMaterialParams().get(); - + bool shiny_in_alpha = false; - + //store shiny in alpha if we don't have a specular map if (!mat || mat->getSpecularID().isNull()) { @@ -1286,7 +1279,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, 0.5f, 0.75f }; - + llassert(tep->getShiny() <= 3); color.mV[3] = U8 (SHININESS_TO_ALPHA[tep->getShiny()] * 255); } @@ -1304,7 +1297,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, __m128i offset = _mm_set1_epi16(index_offset); S32 end = num_indices/8; - + for (S32 i = 0; i < end; i++) { __m128i res = _mm_add_epi16(src[i], offset); @@ -1321,7 +1314,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } } } - + LLMaterial* mat = tep->getMaterialParams().get(); LLGLTFMaterial* gltf_mat = tep->getGLTFRenderMaterial(); @@ -1391,7 +1384,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } } } - + const LLMeshSkinInfo* skin = nullptr; LLMatrix4a mat_vert; LLMatrix4a mat_normal; @@ -1439,7 +1432,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_tcoord) { LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tcoord"); - + //bump setup LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f ); LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f); @@ -1450,11 +1443,11 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, { bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); } - + if (bump_code) { mVObjp->getVolume()->genTangents(face_index); - F32 offset_multiple; + F32 offset_multiple; switch( bump_code ) { case BE_NO_BUMP: @@ -1489,7 +1482,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, tep->getScale( &s_scale, &t_scale ); } // Use the nudged south when coming from above sun angle, such - // that emboss mapping always shows up on the upward faces of cubes when + // that emboss mapping always shows up on the upward faces of cubes when // it's noon (since a lot of builders build with the sun forced to noon). LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; LLVector3 moon_ray = gSky.mVOSkyp->getMoon().getDirection(); @@ -1506,10 +1499,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } U8 tex_mode = 0; - + bool tex_anim = false; - LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; + LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; tex_mode = vobj->mTexAnimMode; if (vobj->mTextureAnimp) @@ -1550,7 +1543,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, do_bump = mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1) || mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD2); } - + // For GLTF materials: Transforms will be applied later bool do_tex_mat = tex_mode && mTextureMatrix && !gltf_mat; @@ -1598,7 +1591,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, U32 count = num_vertices/2 + num_vertices%2; for (S32 i = 0; i < count; i++) - { + { LLVector4a res = *src++; xform4a(res, trans, mask, rot0, rot1, offset, scale); res.store4a(dst); @@ -1609,14 +1602,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, else { //do tex mat, no texgen, no bump for (S32 i = 0; i < num_vertices; i++) - { + { LLVector2 tc(vf.mTexCoords[i]); - + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); tmp = tmp * *mTextureMatrix; tc.mV[0] = tmp.mV[0]; tc.mV[1] = tmp.mV[1]; - *tex_coords0++ = tc; + *tex_coords0++ = tc; } } } @@ -1626,50 +1619,50 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (do_tex_mat) { for (S32 i = 0; i < num_vertices; i++) - { + { LLVector2 tc(vf.mTexCoords[i]); LLVector4a& norm = vf.mNormals[i]; LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; + LLVector4a vec = vf.mPositions[i]; vec.mul(scalea); planarProjection(tc, norm, center, vec); - + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); tmp = tmp * *mTextureMatrix; tc.mV[0] = tmp.mV[0]; tc.mV[1] = tmp.mV[1]; - - *tex_coords0++ = tc; + + *tex_coords0++ = tc; } } else if (xforms != XFORM_NONE) { for (S32 i = 0; i < num_vertices; i++) - { + { LLVector2 tc(vf.mTexCoords[i]); LLVector4a& norm = vf.mNormals[i]; LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; + LLVector4a vec = vf.mPositions[i]; vec.mul(scalea); planarProjection(tc, norm, center, vec); - + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); - *tex_coords0++ = tc; + *tex_coords0++ = tc; } } else { for (S32 i = 0; i < num_vertices; i++) - { + { LLVector2 tc(vf.mTexCoords[i]); LLVector4a& norm = vf.mNormals[i]; LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; + LLVector4a vec = vf.mPositions[i]; vec.mul(scalea); planarProjection(tc, norm, center, vec); - *tex_coords0++ = tc; + *tex_coords0++ = tc; } } } @@ -1679,7 +1672,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen default"); std::vector<LLVector2> bump_tc; - + if (mat && !mat->getNormalID().isNull()) { //writing out normal and specular texture coordinates, not bump offsets do_bump = false; @@ -1692,9 +1685,9 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, S32 xform_channel = XFORM_NONE; switch (ch) { - case 0: + case 0: xform_channel = XFORM_BLINNPHONG_COLOR; - mVertexBuffer->getTexCoord0Strider(dst, mGeomIndex, mGeomCount); + mVertexBuffer->getTexCoord0Strider(dst, mGeomIndex, mGeomCount); break; case 1: xform_channel = XFORM_BLINNPHONG_NORMAL; @@ -1739,26 +1732,26 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, break; } const bool do_xform = (xforms & xform_channel) != XFORM_NONE; - + for (S32 i = 0; i < num_vertices; i++) - { + { LLVector2 tc(vf.mTexCoords[i]); - + LLVector4a& norm = vf.mNormals[i]; - + LLVector4a& center = *(vf.mCenter); - + if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) { LLVector4a vec = vf.mPositions[i]; - + vec.mul(scalea); if (texgen == LLTextureEntry::TEX_GEN_PLANAR) { planarProjection(tc, norm, center, vec); - } + } } if (tex_mode && mTextureMatrix) @@ -1784,7 +1777,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if ((!mat && !gltf_mat) && do_bump) { mVertexBuffer->getTexCoord1Strider(tex_coords1, mGeomIndex, mGeomCount); - + mVObjp->getVolume()->genTangents(face_index); for (S32 i = 0; i < num_vertices; i++) @@ -1801,7 +1794,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, tangent_to_object.rotate(binormal_dir, t); LLVector4a binormal; mat_normal.rotate(t, binormal); - + //VECTORIZE THIS if (mDrawablep->isActive()) { @@ -1815,7 +1808,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLVector2 tc = bump_tc[i]; tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() ); - + *tex_coords1++ = tc; } } @@ -1825,23 +1818,23 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_pos) { LLVector4a* src = vf.mPositions; - + //_mm_prefetch((char*)src, _MM_HINT_T0); LLVector4a* end = src+num_vertices; //LLVector4a* end_64 = end-4; llassert(num_vertices > 0); - + mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount); - - + + F32* dst = (F32*) vert.get(); F32* end_f32 = dst+mGeomCount*4; //_mm_prefetch((char*)dst, _MM_HINT_NTA); //_mm_prefetch((char*)src, _MM_HINT_NTA); - + //_mm_prefetch((char*)dst, _MM_HINT_NTA); @@ -1854,26 +1847,26 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, F32 val = 0.f; S32* vp = (S32*) &val; *vp = index; - + llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); LLVector4Logical mask; mask.clear(); mask.setElement<3>(); - + texIdx.set(0,0,0,val); LLVector4a tmp; - + while (src < end) - { + { mat_vert.affineTransform(*src++, res0); tmp.setSelectWithMask(mask, texIdx, res0); tmp.store4a((F32*) dst); dst += 4; } - + while (dst < end_f32) { res0.store4a((F32*) dst); @@ -1889,24 +1882,24 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, F32* normals = (F32*) norm.get(); LLVector4a* src = vf.mNormals; LLVector4a* end = src+num_vertices; - + while (src < end) - { + { LLVector4a normal; mat_normal.rotate(*src++, normal); normal.store4a(normals); normals += 4; } } - + if (rebuild_tangent) { LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tangent"); mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount); F32* tangents = (F32*) tangent.get(); - + mVObjp->getVolume()->genTangents(face_index); - + LLVector4Logical mask; mask.clear(); mask.setElement<3>(); @@ -1920,12 +1913,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mat_normal.rotate(*src, tangent_out); tangent_out.setSelectWithMask(mask, *src, tangent_out); tangent_out.store4a(tangents); - + src++; tangents += 4; } } - + if (rebuild_weights && vf.mWeights) { LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - weight"); @@ -1943,7 +1936,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, U32 vec[4]; vec[0] = vec[1] = vec[2] = vec[3] = color.asRGBA(); - + src.loadua((F32*) vec); F32* dst = (F32*) colors.get(); @@ -1954,7 +1947,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } for (S32 i = 0; i < num_vecs; i++) - { + { src.store4a(dst); dst += 4; } @@ -1970,14 +1963,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLVector4a src; - + LLColor4U glow4u = LLColor4U(0,0,0,glow); U32 glow32 = glow4u.asRGBA(); U32 vec[4]; vec[0] = vec[1] = vec[2] = vec[3] = glow32; - + src.loadua((F32*) vec); F32* dst = (F32*) emissive.get(); @@ -1988,7 +1981,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } for (S32 i = 0; i < num_vecs; i++) - { + { src.store4a(dst); dst += 4; } @@ -2001,7 +1994,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mTexExtents[1].setVec(1,1); xform(mTexExtents[0], cos_ang, sin_ang, os, ot, ms, mt); xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt); - + F32 es = vf.mTexCoordExtents[1].mV[0] - vf.mTexCoordExtents[0].mV[0] ; F32 et = vf.mTexCoordExtents[1].mV[1] - vf.mTexCoordExtents[0].mV[1] ; mTexExtents[0][0] *= es ; @@ -2024,13 +2017,13 @@ void LLFace::renderIndexed() } //check if the face has a media -BOOL LLFace::hasMedia() const +BOOL LLFace::hasMedia() const { if(mHasMedia) { return TRUE ; } - if(mTexture[LLRender::DIFFUSE_MAP].notNull()) + if(mTexture[LLRender::DIFFUSE_MAP].notNull()) { return mTexture[LLRender::DIFFUSE_MAP]->hasParcelMedia() ; //if has a parcel media } @@ -2051,7 +2044,7 @@ F32 LLFace::getTextureVirtualSize() { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; F32 radius; - F32 cos_angle_to_view_dir; + F32 cos_angle_to_view_dir; BOOL in_frustum = calcPixelArea(cos_angle_to_view_dir, radius); if (mPixelArea < F_ALMOST_ZERO || !in_frustum) @@ -2086,9 +2079,9 @@ F32 LLFace::getTextureVirtualSize() if(face_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping. { if(mImportanceToCamera > LEAST_IMPORTANCE_FOR_LARGE_IMAGE && mTexture[LLRender::DIFFUSE_MAP].notNull() && mTexture[LLRender::DIFFUSE_MAP]->isLargeImage()) - { + { face_area *= adjustPartialOverlapPixelArea(cos_angle_to_view_dir, radius ); - } + } } setVirtualSize(face_area) ; @@ -2136,7 +2129,7 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) LLVector4a t; t.load3(camera->getOrigin().mV); lookAt.setSub(center, t); - + F32 dist = lookAt.getLength3().getF32(); dist = llmax(dist-size.getLength3().getF32(), 0.001f); //ramp down distance for nearby objects @@ -2147,7 +2140,7 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) dist *= 16.f; } - lookAt.normalize3fast() ; + lookAt.normalize3fast() ; //get area of circle around node F32 app_angle = atanf((F32) sqrt(size_squared) / dist); @@ -2157,10 +2150,10 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) x_axis.load3(camera->getXAxis().mV); cos_angle_to_view_dir = lookAt.dot3(x_axis).getF32(); - //if has media, check if the face is out of the view frustum. + //if has media, check if the face is out of the view frustum. if(hasMedia()) { - if(!camera->AABBInFrustum(center, size)) + if(!camera->AABBInFrustum(center, size)) { mImportanceToCamera = 0.f ; return false ; @@ -2170,7 +2163,7 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) cos_angle_to_view_dir = 1.0f ; } else - { + { LLVector4a d; d.setSub(lookAt, x_axis); @@ -2187,7 +2180,7 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) mImportanceToCamera = 1.0f ; } else - { + { mImportanceToCamera = LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist) ; } @@ -2208,10 +2201,10 @@ F32 LLFace::adjustPartialOverlapPixelArea(F32 cos_angle_to_view_dir, F32 radius //F32 radius_square = radius * radius ; //F32 d_square = d * d ; //F32 screen_radius_square = screen_radius * screen_radius ; - //face_area = + //face_area = // radius_square * acosf((d_square + radius_square - screen_radius_square)/(2 * d * radius)) + // screen_radius_square * acosf((d_square + screen_radius_square - radius_square)/(2 * d * screen_radius)) - - // 0.5f * sqrtf((-d + radius + screen_radius) * (d + radius - screen_radius) * (d - radius + screen_radius) * (d + radius + screen_radius)) ; + // 0.5f * sqrtf((-d + radius + screen_radius) * (d + radius - screen_radius) * (d - radius + screen_radius) * (d + radius + screen_radius)) ; //---------------------------------------------- //the above calculation is too expensive @@ -2229,13 +2222,13 @@ const F32 FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[FACE_IMPORTANCE_LEVEL][2] = // const F32 FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[FACE_IMPORTANCE_LEVEL][2] = //{cos(angle), importance_weight} {{0.985f /*cos(10 degrees)*/, 1.0f}, {0.94f /*cos(20 degrees)*/, 0.8f}, {0.866f /*cos(30 degrees)*/, 0.64f}, {0.0f, 0.36f}} ; -//static +//static F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist) { F32 importance = 0.f ; - - if(cos_angle_to_view_dir > LLViewerCamera::getInstance()->getCosHalfFov() && - dist < FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[FACE_IMPORTANCE_LEVEL - 1][0]) + + if(cos_angle_to_view_dir > LLViewerCamera::getInstance()->getCosHalfFov() && + dist < FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[FACE_IMPORTANCE_LEVEL - 1][0]) { LLViewerCamera* camera = LLViewerCamera::getInstance(); F32 camera_moving_speed = camera->getAverageSpeed() ; @@ -2246,12 +2239,12 @@ F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist) //if camera moves or rotates too fast, ignore the importance factor return 0.f ; } - + S32 i = 0 ; for(i = 0; i < FACE_IMPORTANCE_LEVEL && dist > FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][0]; ++i); i = llmin(i, FACE_IMPORTANCE_LEVEL - 1) ; F32 dist_factor = FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][1] ; - + for(i = 0; i < FACE_IMPORTANCE_LEVEL && cos_angle_to_view_dir < FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[i][0] ; ++i) ; i = llmin(i, FACE_IMPORTANCE_LEVEL - 1) ; importance = dist_factor * FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[i][1] ; @@ -2260,7 +2253,7 @@ F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist) return importance ; } -//static +//static F32 LLFace::adjustPixelArea(F32 importance, F32 pixel_area) { if(pixel_area > LLViewerTexture::sMaxSmallImageSize) @@ -2275,7 +2268,7 @@ F32 LLFace::adjustPixelArea(F32 importance, F32 pixel_area) if(importance < LEAST_IMPORTANCE_FOR_LARGE_IMAGE)//if the face is not important, do not load hi-res. { pixel_area = LLViewerTexture::sMinLargeImageSize ; - } + } } } @@ -2290,7 +2283,7 @@ BOOL LLFace::verify(const U32* indices_array) const { //no vertex buffer, face is implicitly valid return TRUE; } - + // First, check whether the face data fits within the pool's range. if ((mGeomIndex + mGeomCount) > mVertexBuffer->getNumVerts()) { @@ -2299,18 +2292,18 @@ BOOL LLFace::verify(const U32* indices_array) const } S32 indices_count = (S32)getIndicesCount(); - + if (!indices_count) { return TRUE; } - + if (indices_count > LL_MAX_INDICES_COUNT) { ok = FALSE; LL_INFOS() << "Face has bogus indices count" << LL_ENDL; } - + if (mIndicesIndex + mIndicesCount > mVertexBuffer->getNumIndices()) { ok = FALSE; @@ -2369,7 +2362,7 @@ S32 LLFace::getColors(LLStrider<LLColor4U> &colors) { return -1; } - + // llassert(mGeomIndex >= 0); mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount); return mGeomIndex; diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 4ad136e13a..3704a5253c 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfilepicker.cpp * @brief OS-specific file picker * * $LicenseInfo:firstyear=2001&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$ */ @@ -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 @@ -112,7 +117,7 @@ LLFilePicker::~LLFilePicker() // nothing } -// utility function to check if access to local file system via file browser +// utility function to check if access to local file system via file browser // is enabled and if not, tidy up and indicate we're not allowed to do this. bool LLFilePicker::check_local_file_access_enabled() { @@ -267,7 +272,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) mOFN.nFilterIndex = 1; setupFilter(filter); - + if (blocking) { // Modal, so pause agent @@ -275,7 +280,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) } reset(); - + // NOTA BENE: hitting the file dialog triggers a window focus event, destroying the selection manager!! success = GetOpenFileName(&mOFN); if (success) @@ -290,7 +295,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) // Account for the fact that the app has been stalled. LLFrameTimer::updateFrameTime(); } - + return success; } @@ -476,7 +481,7 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, L"Targa Images (*.tga)\0*.tga\0" \ L"\0"; break; - + case FFSAVE_JPEG: if (filename.empty()) { @@ -569,7 +574,7 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, return FALSE; } - + mOFN.nMaxFile = SINGLE_FILENAME_BUFFER_SIZE; mOFN.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; @@ -663,6 +668,7 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF allowedv->push_back("gltf"); allowedv->push_back("glb"); break; + case FFLOAD_MODEL: case FFLOAD_COLLADA: allowedv->push_back("dae"); break; @@ -695,11 +701,11 @@ bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) { return false; } - + gViewerWindow->getWindow()->beforeDialog(); - + std::unique_ptr<std::vector<std::string>> allowed_types = navOpenFilterProc(filter); - + std::unique_ptr<std::vector<std::string>> filev = doLoadDialog(allowed_types.get(), mPickOptions); @@ -711,7 +717,7 @@ bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) mFiles.insert(mFiles.end(), filev->begin(), filev->end()); return true; } - + return false; } @@ -724,14 +730,14 @@ bool LLFilePicker::doNavChooseDialogModeless(ELoadFilter filter, { return false; } - + std::unique_ptr<std::vector<std::string>> allowed_types=navOpenFilterProc(filter); - + doLoadDialogModeless(allowed_types.get(), mPickOptions, callback, userdata); - + return true; } @@ -785,13 +791,13 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, creator = "\?\?\?\?"; extension = "glb"; break; - + case LLFilePicker::FFSAVE_XML: type = "\?\?\?\?"; creator = "\?\?\?\?"; extension = "xml"; break; - + case LLFilePicker::FFSAVE_RAW: type = "\?\?\?\?"; creator = "\?\?\?\?"; @@ -803,13 +809,13 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, creator = "prvw"; extension = "j2c"; break; - + case LLFilePicker::FFSAVE_SCRIPT: type = "LSL "; creator = "\?\?\?\?"; extension = "lsl"; break; - + case LLFilePicker::FFSAVE_ALL: default: type = "\?\?\?\?"; @@ -823,16 +829,16 @@ bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filena { // Setup the type, creator, and extension std::string extension, type, creator; - + set_nav_save_data(filter, extension, type, creator); - + std::string namestring = filename; if (namestring.empty()) namestring="Untitled"; - + gViewerWindow->getWindow()->beforeDialog(); // Run the dialog - std::unique_ptr<std::string> filev = doSaveDialog(&namestring, + std::unique_ptr<std::string> filev = doSaveDialog(&namestring, &type, &creator, &extension, @@ -845,7 +851,7 @@ bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filena mFiles.push_back(*filev); return true; } - + return false; } @@ -856,9 +862,9 @@ bool LLFilePicker::doNavSaveDialogModeless(ESaveFilter filter, { // Setup the type, creator, and extension std::string extension, type, creator; - + set_nav_save_data(filter, extension, type, creator); - + std::string namestring = filename; if (namestring.empty()) namestring="Untitled"; @@ -887,11 +893,11 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) } reset(); - + mPickOptions &= ~F_MULTIPLE; mPickOptions |= F_FILE; - - if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. + + if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. { mPickOptions |= ( F_NAV_SUPPORT | F_DIRECTORY ); @@ -902,7 +908,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) { mPickOptions |= F_NAV_SUPPORT; } - + if (blocking) // always true for linux/mac { // Modal, so pause agent @@ -911,7 +917,7 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) success = doNavChooseDialog(filter); - + if (success) { if (!getFileCount()) @@ -943,10 +949,10 @@ BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, } reset(); - + mPickOptions &= ~F_MULTIPLE; mPickOptions |= F_FILE; - + if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. { @@ -972,11 +978,11 @@ BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking) { return FALSE; } - + BOOL success = FALSE; reset(); - + mPickOptions |= F_FILE; mPickOptions |= F_MULTIPLE; @@ -1022,7 +1028,7 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, } reset(); - + mPickOptions |= F_FILE; mPickOptions |= F_MULTIPLE; @@ -1044,7 +1050,7 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, } reset(); - + mPickOptions &= ~F_MULTIPLE; if (blocking) @@ -1078,7 +1084,7 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, { if( mLocked ) return false; - + // if local file browsing is turned off, return without opening dialog if ( check_local_file_access_enabled() == false ) { @@ -1086,7 +1092,7 @@ BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, } reset(); - + mPickOptions &= ~F_MULTIPLE; return doNavSaveDialogModeless(filter, filename, callback, userdata); @@ -1095,488 +1101,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); - } +#if LL_FLTK - 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); */ - - 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) +BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, + const std::string& filename, + void (*callback)(bool, std::string&, void*), + void *userdata) { - 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; + LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; + return FALSE; } -static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker) +BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, + void (*callback)(bool, std::vector<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::getMultipleOpenFilesModeless(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) -{ - return add_simple_pattern_filter_to_gtkchooser(picker, "*.xml", - LLTrans::getString("xml_files") + " (*.xml)"); -} -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) + 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 suggest_name = "untitled"; - std::string suggest_ext = ""; - std::string caption = LLTrans::getString("save_file_verb") + " "; - switch (filter) + 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 ) - { - return FALSE; - } - - gViewerWindow->getWindow()->beforeDialog(); - - reset(); - - GtkWindow* picker = buildFilePicker(false, false, "openfile"); - - if (picker) + else if( res == -1 ) { - 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(); + LL_WARNS() << "FLTK failed: " << flDlg.errmsg() << LL_ENDL; } - - 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. @@ -1590,7 +1336,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, } reset(); - + LL_INFOS() << "getSaveFile suggested filename is [" << filename << "]" << LL_ENDL; if (!filename.empty()) @@ -1620,7 +1366,7 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) } reset(); - + // HACK: Static filenames for 'open' until we implement filepicker std::string filename = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + "upload"; switch (filter) @@ -1664,13 +1410,13 @@ BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, return FALSE; } -#endif // LL_GTK +#endif // LL_FLTK #else // not implemented BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename ) { - reset(); + reset(); return FALSE; } diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 38daff9937..5ac473755e 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -1,25 +1,25 @@ -/** +/** * @file llfilepicker.h * @brief OS-specific file picker * * $LicenseInfo:firstyear=2001&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$ */ @@ -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; } @@ -143,7 +132,7 @@ public: S32 getFileCount() const { return (S32)mFiles.size(); } // see lldir.h : getBaseFileName and getDirName to extract base or directory names - + // clear any lists of buffers or whatever, and make sure the file // picker isn't locked. void reset(); @@ -156,10 +145,10 @@ private: FILENAME_BUFFER_SIZE = 65000 }; - // utility function to check if access to local file system via file browser + // utility function to check if access to local file system via file browser // is enabled and if not, tidy up and indicate we're not allowed to do this. bool check_local_file_access_enabled(); - + #if LL_WINDOWS OPENFILENAMEW mOFN; // for open and save dialogs WCHAR mFilesW[FILENAME_BUFFER_SIZE]; @@ -170,7 +159,7 @@ private: #if LL_DARWIN S32 mPickOptions; std::vector<std::string> mFileVector; - + bool doNavChooseDialog(ELoadFilter filter); bool doNavChooseDialogModeless(ELoadFilter filter, void (*callback)(bool, std::vector<std::string>&, void*), @@ -183,14 +172,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; @@ -198,12 +185,6 @@ private: bool mLocked; 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. diff --git a/indra/newview/llfloatercreatelandmark.cpp b/indra/newview/llfloatercreatelandmark.cpp index b82d8a29ba..351f4a844c 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 d84f5ae1fc..f91c302df7 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 1578caa39c..6d80a18599 100644 --- a/indra/newview/llfloateremojipicker.cpp +++ b/indra/newview/llfloateremojipicker.cpp @@ -424,6 +424,7 @@ void LLFloaterEmojiPicker::fillGroups() LLButton::Params params; params.font = LLFontGL::getFontEmoji(); + params.name = "all_categories"; LLRect rect; rect.mTop = mGroups->getRect().getHeight(); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index a3e173398f..54615f1d7d 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)); @@ -529,6 +531,7 @@ LLFloaterPreference::~LLFloaterPreference() { LLConversationLog::instance().removeObserver(this); mComplexityChangedSignal.disconnect(); + mImpostorsChangedSignal.disconnect(); } void LLFloaterPreference::draw() @@ -1283,6 +1286,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)); @@ -1561,6 +1567,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 04ac87364d..936808d58e 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 a91f0ec060..d59113144e 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 2c92f3dbf1..80e35368eb 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 187ac9d323..403e9fadf0 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -3858,15 +3858,14 @@ void LLPanelRegionEnvironment::onChkAllowOverride(bool value) mAllowOverrideRestore = mAllowOverride; mAllowOverride = value; - std::string notification("EstateParcelEnvironmentOverride"); if (LLPanelEstateInfo::isLindenEstate()) notification = "ChangeLindenEstate"; - LLSD args; - args["ESTATENAME"] = LLEstateInfoModel::instance().getName(); - LLNotification::Params params(notification); - params.substitutions(args); + LLSD args; + args["ESTATENAME"] = LLEstateInfoModel::instance().getName(); + LLNotification::Params params(notification); + params.substitutions(args); params.functor.function([this](const LLSD& notification, const LLSD& response) { confirmUpdateEstateEnvironment(notification, response); }); if (!value || LLPanelEstateInfo::isLindenEstate()) diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp index 6a2daeeb90..1f6ad85be7 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 ddb69cdfb3..42cf9036ce 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -852,7 +852,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")); @@ -5121,7 +5121,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(), @@ -5129,11 +5129,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 6f06f3b36d..ac73e0d639 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -379,7 +379,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/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 332c6d3085..24d07fc390 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -627,13 +627,13 @@ bool LLInventoryFilter::checkAgainstSearchVisibility(const LLFolderViewModelItem if (listener->isItemInOutfits() && ((mFilterOps.mSearchVisibility & VISIBILITY_OUTFITS) == 0)) return FALSE; - if (listener->isItemInTrash() && ((mFilterOps.mSearchVisibility & VISIBILITY_TRASH) == 0)) - return FALSE; + if (listener->isItemInTrash() && ((mFilterOps.mSearchVisibility & VISIBILITY_TRASH) == 0)) + return FALSE; - if (!listener->isAgentInventory() && ((mFilterOps.mSearchVisibility & VISIBILITY_LIBRARY) == 0)) - return FALSE; + if (!listener->isAgentInventory() && ((mFilterOps.mSearchVisibility & VISIBILITY_LIBRARY) == 0)) + return FALSE; - return TRUE; + return TRUE; } const std::string& LLInventoryFilter::getFilterSubString(BOOL trim) const diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 5f4b816b99..bfa87a9834 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -564,7 +564,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 205e5f3489..d964b4af21 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2050,8 +2050,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; } + mParentChildCategoryTree.erase(id); delete cat_list; - mParentChildCategoryTree.erase(id); } addChangedMask(LLInventoryObserver::REMOVE, id); @@ -5046,4 +5046,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 722447b5d7..7335d1e4fe 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 ab04a8589a..ae2236da3f 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(); + removeItemID(idp); view_item->destroyView(); - removeItemID(idp); } LLInventoryObject const* objectp = mInventory->getObject(item_id); diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp index feb691520f..98c1019f03 100644 --- a/indra/newview/llmanip.cpp +++ b/indra/newview/llmanip.cpp @@ -568,9 +568,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/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp index d3b981e205..b0953f929c 100644 --- a/indra/newview/llmediadataclient.cpp +++ b/indra/newview/llmediadataclient.cpp @@ -204,7 +204,7 @@ bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object) if (std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred) != mUnQueuedRequests.end()) return true; - return false; + return false; } void LLMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object) @@ -829,7 +829,7 @@ bool LLObjectMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &ob if (std::find_if(mRoundRobinQueue.begin(), mRoundRobinQueue.end(), PredicateMatchRequest(object->getID())) != mRoundRobinQueue.end()) return true; - return false; + return false; } void LLObjectMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object) diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index a3eab3c26d..0cfa5f3402 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 { @@ -1185,7 +1180,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()) { @@ -1206,6 +1201,8 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) void LLModelPreview::resetPreviewTarget() { + LLMutexLock lock(this); + if (mModelLoader) { mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; @@ -1251,7 +1248,7 @@ void LLModelPreview::generateNormals() (*it)->generateNormals(angle_cutoff); } - mVertexBuffer[5].clear(); + mVertexBuffer[LLModel::NUM_LODS].clear(); } bool perform_copy = mModelFacesCopy[which_lod].empty(); @@ -2093,7 +2090,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; @@ -2397,12 +2394,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; + } } } @@ -2731,10 +2732,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 { @@ -2971,8 +2972,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(); @@ -2993,7 +2995,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]; @@ -3130,12 +3134,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(); @@ -3144,7 +3148,7 @@ BOOL LLModelPreview::render() LLGLDisable no_blend(GL_BLEND); LLGLEnable cull(GL_CULL_FACE); LLGLDepthTest depth(GL_FALSE); // SL-12781 disable z-buffer to render background color - + { gUIProgram.bind(); @@ -3212,15 +3216,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) @@ -3243,11 +3247,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 @@ -3290,7 +3295,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 @@ -3310,7 +3315,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; @@ -3320,7 +3325,7 @@ BOOL LLModelPreview::render() refresh(); } - gObjectPreviewProgram.bind(skin_weight); + gObjectPreviewProgram.bind(show_skin_weight); gGL.loadIdentity(); gPipeline.enableLightsPreview(); @@ -3329,7 +3334,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 @@ -3345,9 +3350,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); } @@ -3362,7 +3367,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 { @@ -3373,15 +3378,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) { @@ -3403,11 +3408,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) @@ -3431,10 +3432,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); @@ -3447,7 +3454,7 @@ BOOL LLModelPreview::render() gGL.popMatrix(); } - if (physics) + if (show_physics) { glClear(GL_DEPTH_BUFFER_BIT); @@ -3513,12 +3520,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]); } @@ -3533,7 +3540,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(); } @@ -3548,14 +3555,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); @@ -3615,10 +3625,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(); @@ -3682,7 +3693,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) { @@ -3725,16 +3736,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) @@ -3758,10 +3768,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); @@ -3776,7 +3790,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 1a6c5db535..c6245bcd8d 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -913,18 +913,10 @@ void LLOutfitListBase::onIdleRefreshList() ++items_iter) { LLViewerInventoryCategory *cat = gInventory.getCategory(*items_iter); - if (!cat) + if (cat) { - LLInventoryObject* obj = gInventory.getObject(*items_iter); - if (!obj || (obj->getType() != LLAssetType::AT_CATEGORY)) - { - break; - } - cat = (LLViewerInventoryCategory*)obj; + updateChangedCategoryName(cat, cat->getName()); } - std::string name = cat->getName(); - - updateChangedCategoryName(cat, name); } sortOutfits(); 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 a527ebe47f..a72d7f2773 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -5229,7 +5229,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) @@ -5495,4 +5495,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 a64b85815f..2c466d4698 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -395,7 +395,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) {} @@ -428,7 +428,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) {} @@ -621,4 +621,3 @@ public: }; #endif - diff --git a/indra/newview/llphysicsshapebuilderutil.cpp b/indra/newview/llphysicsshapebuilderutil.cpp index 9603ee6329..a79cc984c1 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 b3b100296f..24e68fcf77 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 bd34e40642..9f7be28277 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 5d46c695b7..b5ccb3591f 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -405,13 +405,19 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w F32* tc = (F32*) tex_coordsp.get(); F32* vw = (F32*) vertex_weightsp.get(); - F32* cw = (F32*) clothing_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); - LLVector4a::memcpyNonAliased16(cw, (F32*) mMesh->getClothingWeights(), num_verts*4*sizeof(F32)); + //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)); } const U32 idx_count = mMesh->getNumFaces()*3; diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 02108e861a..18cfa37fe1 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1723,7 +1723,13 @@ 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"); + std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.log"); + std::string user_data_path_cef_old = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.old"); + if (gDirUtilp->fileExists(user_data_path_cef_log)) + { + LLFile::remove(user_data_path_cef_old, ENOENT); + LLFile::rename(user_data_path_cef_log, user_data_path_cef_old); + } // See if the plugin executable exists llstat s; @@ -1733,9 +1739,7 @@ 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 { @@ -1789,9 +1793,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/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 6ac94fe4c4..9d4022fda1 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewerstats.cpp * @brief LLViewerStats class implementation * * $LicenseInfo:firstyear=2002&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$ */ @@ -36,10 +36,10 @@ #include "llappviewer.h" -#include "pipeline.h" -#include "lltexturefetch.h" -#include "llviewerobjectlist.h" -#include "llviewertexturelist.h" +#include "pipeline.h" +#include "lltexturefetch.h" +#include "llviewerobjectlist.h" +#include "llviewertexturelist.h" #include "lltexlayer.h" #include "lltexlayerparams.h" #include "llsurface.h" @@ -142,13 +142,13 @@ LLTrace::CountStatHandle<> FPS("FPS", "Frames rendered"), TEX_REBAKES("texrebakes", "Number of times avatar textures have been forced to rebake"), NUM_NEW_OBJECTS("numnewobjectsstat", "Number of objects in scene that were not previously in cache"); -LLTrace::CountStatHandle<LLUnit<F64, LLUnits::Kilotriangles> > +LLTrace::CountStatHandle<LLUnit<F64, LLUnits::Kilotriangles> > TRIANGLES_DRAWN("trianglesdrawnstat"); LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Kilotriangles> > TRIANGLES_DRAWN_PER_FRAME("trianglesdrawnperframestat"); -LLTrace::CountStatHandle<F64Kilobytes > +LLTrace::CountStatHandle<F64Kilobytes > ACTIVE_MESSAGE_DATA_RECEIVED("activemessagedatareceived", "Message system data received on all active regions"), LAYERS_NETWORK_DATA_RECEIVED("layersdatareceived", "Network data received for layer data (terrain)"), OBJECT_NETWORK_DATA_RECEIVED("objectdatareceived", "Network data received for objects"), @@ -157,7 +157,7 @@ LLTrace::CountStatHandle<F64Kilobytes > MESSAGE_SYSTEM_DATA_IN("messagedatain", "Incoming message system network data"), MESSAGE_SYSTEM_DATA_OUT("messagedataout", "Outgoing message system network data"); -LLTrace::CountStatHandle<F64Seconds > +LLTrace::CountStatHandle<F64Seconds > SIM_20_FPS_TIME("sim20fpstime", "Seconds with sim FPS below 20"), SIM_PHYSICS_20_FPS_TIME("simphysics20fpstime", "Seconds with physics FPS below 20"), LOSS_5_PERCENT_TIME("loss5percenttime", "Seconds with packet loss > 5%"); @@ -181,7 +181,7 @@ SimMeasurement<> SIM_TIME_DILATION("simtimedilation", "Simulator time scale", SIM_PHYSICS_PINNED_TASKS("physicspinnedtasks", "", LL_SIM_STAT_PHYSICS_PINNED_TASKS), SIM_PHYSICS_LOD_TASKS("physicslodtasks", "", LL_SIM_STAT_PHYSICS_LOD_TASKS); -SimMeasurement<LLUnit<F64, LLUnits::Percent> > +SimMeasurement<LLUnit<F64, LLUnits::Percent> > SIM_PERCENTAGE_SCRIPTS_RUN("simpctscriptsrun", "", LL_SIM_STAT_PCTSCRIPTSRUN), SIM_SKIPPED_CHARACTERS_PERCENTAGE("simsimpctsteppedcharacters", "", LL_SIM_STAT_PCTSTEPPEDCHARACTERS); @@ -198,17 +198,17 @@ LLTrace::SampleStatHandle<> FPS_SAMPLE("fpssample"), WINDOW_WIDTH("windowwidth", "Window width"), WINDOW_HEIGHT("windowheight", "Window height"); -LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > +LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > PACKETS_LOST_PERCENT("packetslostpercentstat"); -static LLTrace::SampleStatHandle<bool> +static LLTrace::SampleStatHandle<bool> CHAT_BUBBLES("chatbubbles", "Chat Bubbles Enabled"); LLTrace::SampleStatHandle<F64Megabytes > FORMATTED_MEM("formattedmemstat"); LLTrace::SampleStatHandle<F64Kilobytes > DELTA_BANDWIDTH("deltabandwidth", "Increase/Decrease in bandwidth based on packet loss"), MAX_BANDWIDTH("maxbandwidth", "Max bandwidth setting"); - + SimMeasurement<F64Milliseconds > SIM_FRAME_TIME("simframemsec", "", LL_SIM_STAT_FRAMEMS), SIM_NET_TIME("simnetmsec", "", LL_SIM_STAT_NETMS), SIM_OTHER_TIME("simsimothermsec", "", LL_SIM_STAT_SIMOTHERMS), @@ -223,7 +223,7 @@ SimMeasurement<F64Milliseconds > SIM_FRAME_TIME("simframemsec", "", LL_SIM_STAT_ SIM_SPARE_TIME("simsparemsec", "", LL_SIM_STAT_SIMSPARETIME), SIM_SLEEP_TIME("simsleepmsec", "", LL_SIM_STAT_SIMSLEEPTIME), SIM_PUMP_IO_TIME("simpumpiomsec", "", LL_SIM_STAT_IOPUMPTIME); - + SimMeasurement<F64Kilobytes > SIM_UNACKED_BYTES("simtotalunackedbytes", "", LL_SIM_STAT_TOTAL_UNACKED_BYTES); SimMeasurement<F64Megabytes > SIM_PHYSICS_MEM("physicsmemoryallocated", "", LL_SIM_STAT_SIMPHYSICSMEMORY); @@ -235,7 +235,7 @@ LLTrace::SampleStatHandle<F64Milliseconds > FRAMETIME_JITTER("frametimejitter", LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP("agentpositionsnap", "agent position corrections"); LLTrace::EventStatHandle<> LOADING_WEARABLES_LONG_DELAY("loadingwearableslongdelay", "Wearables took too long to load"); - + LLTrace::EventStatHandle<F64Milliseconds > REGION_CROSSING_TIME("regioncrossingtime", "CROSSING_AVG"), FRAME_STACKTIME("framestacktime", "FRAME_SECS"), UPDATE_STACKTIME("updatestacktime", "UPDATE_SECS"), @@ -243,7 +243,7 @@ LLTrace::EventStatHandle<F64Milliseconds > REGION_CROSSING_TIME("regioncrossingt IMAGE_STACKTIME("imagestacktime", "IMAGE_SECS"), REBUILD_STACKTIME("rebuildstacktime", "REBUILD_SECS"), RENDER_STACKTIME("renderstacktime", "RENDER_SECS"); - + LLTrace::EventStatHandle<F64Seconds > AVATAR_EDIT_TIME("avataredittime", "Seconds in Edit Appearance"), TOOLBOX_TIME("toolboxtime", "Seconds using Toolbox"), MOUSELOOK_TIME("mouselooktime", "Seconds in Mouselook"), @@ -263,7 +263,7 @@ LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > SWAP_FRAME_PCT("swap_ LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > IDLE_FRAME_PCT("idle_frame_pct"); } -LLViewerStats::LLViewerStats() +LLViewerStats::LLViewerStats() : mLastTimeDiff(0.0) { getRecording().start(); @@ -283,20 +283,20 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff) { add(LLStatViewer::LOSS_5_PERCENT_TIME, time_diff); } - + F32 sim_fps = getRecording().getLastValue(LLStatViewer::SIM_FPS); if (0.f < sim_fps && sim_fps < 20.f) { add(LLStatViewer::SIM_20_FPS_TIME, time_diff); } - + F32 sim_physics_fps = getRecording().getLastValue(LLStatViewer::SIM_PHYSICS_FPS); if (0.f < sim_physics_fps && sim_physics_fps < 20.f) { add(LLStatViewer::SIM_PHYSICS_20_FPS_TIME, time_diff); } - + if (time_diff >= (F64Seconds)0.5) { record(LLStatViewer::FPS_2_TIME, time_diff); @@ -320,7 +320,7 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff) // old stats that were never really used F64Seconds jit = (F64Seconds) std::fabs((mLastTimeDiff - time_diff)); sample(LLStatViewer::FRAMETIME_JITTER, jit); - + F32Seconds average_frametime = gRenderStartTime.getElapsedTimeF32() / (F32)gFrameCount; sample(LLStatViewer::FRAMETIME_SLEW, F64Milliseconds (average_frametime - time_diff)); @@ -329,39 +329,39 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff) sample(LLStatViewer::DELTA_BANDWIDTH, F64Bits(delta_bandwidth)); sample(LLStatViewer::MAX_BANDWIDTH, F64Bits(max_bandwidth)); } - + mLastTimeDiff = time_diff; } void LLViewerStats::addToMessage(LLSD &body) { LLSD &misc = body["misc"]; - + misc["Version"] = TRUE; //TODO RN: get last value, not mean misc["Vertex Buffers Enabled"] = getRecording().getMean(LLStatViewer::ENABLE_VBO); - + body["AgentPositionSnaps"] = getRecording().getSum(LLStatViewer::AGENT_POSITION_SNAP).value(); //mAgentPositionSnaps.asLLSD(); - LL_INFOS() << "STAT: AgentPositionSnaps: Mean = " << getRecording().getMean(LLStatViewer::AGENT_POSITION_SNAP).value() << "; StdDev = " << getRecording().getStandardDeviation(LLStatViewer::AGENT_POSITION_SNAP).value() + LL_INFOS() << "STAT: AgentPositionSnaps: Mean = " << getRecording().getMean(LLStatViewer::AGENT_POSITION_SNAP).value() << "; StdDev = " << getRecording().getStandardDeviation(LLStatViewer::AGENT_POSITION_SNAP).value() << "; Count = " << getRecording().getSampleCount(LLStatViewer::AGENT_POSITION_SNAP) << LL_ENDL; } // *NOTE:Mani The following methods used to exist in viewer.cpp // Moving them here, but not merging them into LLViewerStats yet. -U32 gTotalLandIn = 0, +U32 gTotalLandIn = 0, gTotalLandOut = 0, - gTotalWaterIn = 0, + gTotalWaterIn = 0, gTotalWaterOut = 0; -F32 gAveLandCompression = 0.f, +F32 gAveLandCompression = 0.f, gAveWaterCompression = 0.f, gBestLandCompression = 1.f, gBestWaterCompression = 1.f, - gWorstLandCompression = 0.f, + gWorstLandCompression = 0.f, gWorstWaterCompression = 0.f; -U32Bytes gTotalWorldData, - gTotalObjectData, +U32Bytes gTotalWorldData, + gTotalObjectData, gTotalTextureData; U32 gSimPingCount = 0; U32Bits gObjectData; @@ -442,7 +442,7 @@ void update_statistics() world->updateNetStats(); world->requestCacheMisses(); } - + // Reset all of these values. gVLManager.resetBitCounts(); gObjectData = (U32Bytes)0; @@ -476,7 +476,7 @@ void update_statistics() // auto tot_avatar_render_time_raw = tot_avatar_time_raw - tot_av_idle_time_raw; // the time spent this frame on the "display()" call. Treated as "tot time rendering" auto tot_render_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_DISPLAY); - // sleep time is basically forced sleep when window out of focus + // sleep time is basically forced sleep when window out of focus auto tot_sleep_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_SLEEP); // time spent on UI auto tot_ui_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_UI); @@ -572,11 +572,11 @@ void send_viewer_stats(bool include_preferences) LL_WARNS() << "Could not get ViewerStats capability" << LL_ENDL; return; } - + LLViewerStats::instance().getRecording().pause(); LLSD &agent = body["agent"]; - + time_t ltime; time(<ime); F32 run_time = F32(LLFrameTimer::getElapsedSeconds()); @@ -602,7 +602,7 @@ void send_viewer_stats(bool include_preferences) agent["version"] = LLVersionInfo::instance().getChannelAndVersion(); std::string language = LLUI::getLanguage(); agent["language"] = language; - + agent["sim_fps"] = ((F32) gFrameCount - gSimFrames) / (F32) (gRenderStartTime.getElapsedTimeF32() - gSimLastTime); @@ -617,7 +617,7 @@ void send_viewer_stats(bool include_preferences) agent["translation"] = LLTranslate::instance().asLLSD(); LLSD &system = body["system"]; - + system["ram"] = (S32) gSysMemory.getPhysicalMemoryKB().value(); system["os"] = LLOSInfo::instance().getOSStringSimple(); system["cpu"] = gSysCPU.getCPUString(); @@ -668,7 +668,7 @@ void send_viewer_stats(bool include_preferences) { shader_level = 2; } - + system["shader_level"] = shader_level; @@ -687,9 +687,9 @@ void send_viewer_stats(bool include_preferences) in["compressed_packets"] = (S32) gMessageSystem->mCompressedPacketsIn; in["savings"] = (gMessageSystem->mUncompressedBytesIn - gMessageSystem->mCompressedBytesIn) / 1024.0; - + LLSD &out = body["stats"]["net"]["out"]; - + out["kbytes"] = gMessageSystem->mTotalBytesOut / 1024.0; out["packets"] = (S32) gMessageSystem->mPacketsOut; out["compressed_packets"] = (S32) gMessageSystem->mCompressedPacketsOut; @@ -712,7 +712,7 @@ void send_viewer_stats(bool include_preferences) gInventory.mValidationInfo->asLLSD(validation_info); body["ui"] = LLUIUsage::instance().asLLSD(); - + body["stats"]["voice"] = LLVoiceVivoxStats::getInstance()->read(); // Misc stats, two strings and two ints @@ -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 6372679a07..aa55c9791e 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -154,26 +154,26 @@ void LLViewerStatsRecorder::recordCacheFullUpdate(LLViewerRegion::eCacheUpdateRe void LLViewerStatsRecorder::writeToLog( F32 interval ) { if (!mEnableStatsLogging || !mEnableStatsRecording) - { - return; - } + { + return; + } - size_t data_size = 0; - F64 delta_time = LLFrameTimer::getTotalSeconds() - mLastSnapshotTime; + size_t data_size = 0; + F64 delta_time = LLFrameTimer::getTotalSeconds() - mLastSnapshotTime; if (delta_time < interval) return; - if (mSkipSaveIfZeros) - { + if (mSkipSaveIfZeros) + { S32 total_events = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheUpdateDupes + mObjectCacheUpdateChanges + mObjectCacheUpdateAdds + mObjectCacheUpdateReplacements + mObjectUpdateFailures; - if (total_events == 0) - { + if (total_events == 0) + { LL_DEBUGS("ILXZeroData") << "ILX: not saving zero data" << LL_ENDL; return; } - } + } mLastSnapshotTime = LLFrameTimer::getTotalSeconds(); LL_DEBUGS("ILX") << "ILX: " @@ -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 310c9ee297..b43c2fa540 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); } @@ -6013,7 +6014,7 @@ LLVivoxVoiceClient::sessionState::~sessionState() if (mMyIterator != mSession.end()) mSession.erase(mMyIterator); - removeAllParticipants(); + removeAllParticipants(); } bool LLVivoxVoiceClient::sessionState::isCallBackPossible() diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index e3f2afadc5..0d0ed3f184 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5775,8 +5775,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 a77c31eee3..62e04b45b8 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_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 bc237322af..d993b1f990 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 53f703e56d..6954e68483 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -4014,16 +4014,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 2088a443fd..8a8384bc2d 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_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 4de4dc8fc5..103dff3621 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'])): @@ -582,7 +584,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") @@ -709,7 +711,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): @@ -768,7 +770,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" @@ -777,7 +779,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: @@ -908,7 +910,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]) @@ -933,7 +935,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") @@ -1202,6 +1204,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") @@ -1220,49 +1225,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 @@ -1277,93 +1356,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") @@ -1384,17 +1449,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__": |