From 57d423745fd1d3d0ea6a0c69b869a20c27e27fc5 Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn Date: Fri, 5 Apr 2024 19:25:02 +0200 Subject: Linux viewer (ReleaseOS) resurrection (#1099) Co-authored-by: AiraYumi --- .github/workflows/build_linux.yaml | 47 + .gitignore | 1 - autobuild.xml | 195 +- indra/cmake/00-Common.cmake | 38 +- indra/cmake/Audio.cmake | 2 +- indra/cmake/Boost.cmake | 6 +- indra/cmake/CMakeLists.txt | 1 - indra/cmake/ConfigurePkgConfig.cmake | 74 - indra/cmake/Copy3rdPartyLibs.cmake | 10 - indra/cmake/FreeType.cmake | 13 +- indra/cmake/GLIB.cmake | 22 + indra/cmake/GStreamer10Plugin.cmake | 27 + indra/cmake/ICU4C.cmake | 2 +- indra/cmake/JsonCpp.cmake | 2 +- indra/cmake/LLAddBuildTest.cmake | 7 + indra/cmake/LLWindow.cmake | 14 +- indra/cmake/Meshoptimizer.cmake | 2 +- indra/cmake/UI.cmake | 45 +- indra/cmake/Variables.cmake | 2 - indra/cmake/ViewerMiscLibs.cmake | 9 +- indra/llcommon/llprocessor.cpp | 2 +- indra/llcommon/llsdutil.cpp | 1 + indra/llcommon/llsys.cpp | 133 +- indra/llcorehttp/CMakeLists.txt | 2 - indra/llimage/llimageworker.cpp | 2 +- indra/llmath/llcalcparser.h | 6 +- indra/llmessage/CMakeLists.txt | 3 - indra/llmessage/llnamevalue.cpp | 4 + indra/llprimitive/llprimtexturelist.cpp | 9 +- indra/llrender/llfontfreetype.cpp | 36 +- indra/llrender/llfontfreetypesvg.cpp | 4 + indra/llrender/llfontfreetypesvg.h | 6 +- indra/llrender/llgl.cpp | 111 +- indra/llrender/llglheaders.h | 16 + indra/llrender/llglslshader.cpp | 2 +- indra/llwindow/CMakeLists.txt | 8 +- indra/llwindow/llkeyboard.cpp | 40 +- indra/llwindow/llkeyboard.h | 36 +- indra/llwindow/llkeyboardheadless.cpp | 4 - indra/llwindow/llkeyboardheadless.h | 9 +- indra/llwindow/llkeyboardsdl.cpp | 837 +++-- indra/llwindow/llkeyboardsdl.h | 50 +- indra/llwindow/llwindowsdl.cpp | 3866 ++++++++++---------- indra/llwindow/llwindowsdl.h | 433 ++- indra/media_plugins/CMakeLists.txt | 2 +- indra/media_plugins/gstreamer10/CMakeLists.txt | 46 + .../gstreamer10/llmediaimplgstreamer.h | 53 + .../gstreamer10/llmediaimplgstreamer_syms.cpp | 197 + .../gstreamer10/llmediaimplgstreamer_syms.h | 68 + .../gstreamer10/llmediaimplgstreamer_syms_raw.inc | 68 + .../gstreamer10/media_plugin_gstreamer10.cpp | 982 +++++ indra/newview/CMakeLists.txt | 1 - indra/newview/llappviewerlinux.cpp | 359 +- indra/newview/llappviewerlinux.h | 28 - indra/newview/llappviewerlinux_api.h | 143 - indra/newview/llappviewerlinux_api.xml | 14 - indra/newview/llappviewerlinux_api_dbus.cpp | 126 - indra/newview/llappviewerlinux_api_dbus.h | 44 - .../newview/llappviewerlinux_api_dbus_syms_raw.inc | 9 - indra/newview/llchathistory.cpp | 2 +- indra/newview/llconversationloglist.cpp | 7 +- indra/newview/lldirpicker.cpp | 36 + indra/newview/lldirpicker.h | 2 + indra/newview/llface.cpp | 1 - indra/newview/llfasttimerview.cpp | 14 +- indra/newview/llfilepicker.h | 14 + indra/newview/llfloaterregioninfo.cpp | 9 +- indra/newview/llhttpretrypolicy.cpp | 5 +- indra/newview/llinventoryfilter.cpp | 10 +- indra/newview/llinventorygallerymenu.cpp | 2 +- indra/newview/llmanip.cpp | 3 - indra/newview/llmediadataclient.cpp | 4 +- indra/newview/llpanelface.cpp | 3 +- indra/newview/llpanelface.h | 5 +- indra/newview/lltoastalertpanel.h | 10 +- indra/newview/llviewerstats.cpp | 7 + indra/newview/llviewerstatsrecorder.cpp | 22 +- indra/newview/llvoicevivox.cpp | 2 +- indra/newview/llvovolume.cpp | 3 +- indra/newview/llxmlrpctransaction.cpp | 2 +- indra/newview/viewer_manifest.py | 206 +- 81 files changed, 5144 insertions(+), 3504 deletions(-) create mode 100644 .github/workflows/build_linux.yaml delete mode 100644 indra/cmake/ConfigurePkgConfig.cmake create mode 100644 indra/cmake/GLIB.cmake create mode 100644 indra/cmake/GStreamer10Plugin.cmake create mode 100644 indra/media_plugins/gstreamer10/CMakeLists.txt create mode 100644 indra/media_plugins/gstreamer10/llmediaimplgstreamer.h create mode 100644 indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.cpp create mode 100644 indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.h create mode 100644 indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc create mode 100644 indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp delete mode 100644 indra/newview/llappviewerlinux_api.h delete mode 100644 indra/newview/llappviewerlinux_api.xml delete mode 100644 indra/newview/llappviewerlinux_api_dbus.cpp delete mode 100644 indra/newview/llappviewerlinux_api_dbus.h delete mode 100644 indra/newview/llappviewerlinux_api_dbus_syms_raw.inc diff --git a/.github/workflows/build_linux.yaml b/.github/workflows/build_linux.yaml new file mode 100644 index 0000000000..005284e984 --- /dev/null +++ b/.github/workflows/build_linux.yaml @@ -0,0 +1,47 @@ +name: Linux build example +on: + workflow_dispatch: + push: +jobs: + build: + runs-on: ubuntu-22.04 + env: + AUTOBUILD_ADDRSIZE: 64 + AUTOBUILD_VARIABLES_FILE: ${{ github.workspace }}/.build-variables/variables + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Setup python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Checkout build variables + uses: actions/checkout@v4 + with: + repository: secondlife/build-variables + ref: viewer + path: .build-variables + + - name: Checkout master-message-template + uses: actions/checkout@v4 + with: + repository: secondlife/master-message-template + path: .master-message-template + + - name: Install autobuild and python dependencies + run: pip3 install autobuild llsd + + - name: Install Linux dependencies + if: runner.os == 'linux' + run: sudo apt update && sudo apt install -y libfltk1.3-dev libunwind-dev libgl1-mesa-dev libglu1-mesa-dev libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxext-dev libxrender-dev libxfixes-dev libxxf86vm-dev libxss-dev libdbus-1-dev libudev-dev libssl-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libfreetype6-dev ninja-build libxft-dev + + - name: Build + id: build + shell: bash + run: | + autobuild configure -c ReleaseOS -A64 + cd build-linux-x86_64 && ninja -k0 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 612421f8c9..5bb0e953f7 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -7,7 +7,7 @@ autobuild installables - SDL + SDL2 platforms @@ -29,13 +29,13 @@ license lgpl license_file - LICENSES/SDL.txt + LICENSES/SDL2.txt copyright - Copyright (C) 1997-2012 Sam Lantinga + Copyright (C) 1997-2022 Sam Lantinga (slouken@libsdl.org) version - 1.2.15 + 2.28.0 name - SDL + SDL2 description 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. @@ -93,7 +93,7 @@ copyright Copyright © 2012 The Apache Software Foundation, Licensed under the Apache License, Version 2.0. version - 1.7.2-e935465 + 1.7.2-c5f3347 name apr_suite description @@ -375,7 +375,7 @@ copyright Copyright (c) 1996 - 2014, Daniel Stenberg, (daniel@haxx.se). version - 7.54.1-5a4a82d + 7.54.1-513145c name curl description @@ -543,6 +543,20 @@ name windows64 + linux64 + + archive + + hash_algorithm + sha1 + hash + 5b957aa7f353b10ae17b7119e5b3668f48a35325 + url + https://github.com/secondlife/3p-emoji-shortcodes/releases/download/v6.1.0.5413f58/emoji_shortcodes-6.1.0.5413f58-linux64-5413f58.tar.zst + + name + linux64 + version 6.1.0.579438 @@ -615,14 +629,14 @@ archive - creds - github hash fb6797ff93b6e881b060d2a8b396d8d7477834ee hash_algorithm sha1 url https://api.github.com/repos/secondlife/3p-fmodstudio/releases/assets/108908444 + creds + github name darwin64 @@ -631,14 +645,14 @@ archive - creds - github hash a378bd1604aa97ca763140911f9f4e463ced85c0 hash_algorithm sha1 url https://api.github.com/repos/secondlife/3p-fmodstudio/releases/assets/108908446 + creds + github name linux64 @@ -647,14 +661,14 @@ archive - creds - github hash 72304491d86bd797b840999b255358f195b06609 hash_algorithm sha1 url https://api.github.com/repos/secondlife/3p-fmodstudio/releases/assets/108908456 + creds + github name windows64 @@ -706,11 +720,11 @@ archive hash - 061e1bd8eef85a5d15fafc9d46fc562a621207da + 07a38133c008ce6f728d652d00a756bea3a70288 hash_algorithm sha1 url - https://github.com/secondlife/3p-freetype/releases/download/v2.12.1.d315c1b/freetype-2.12.1.8443253711-linux64-8443253711.tar.zst + https://github.com/secondlife/3p-freetype/releases/download/v2.12.1-r1/freetype-2.12.1.8503093630-linux64-8503093630.tar.zst name linux64 @@ -885,34 +899,6 @@ name gstreamer - gtk-atk-pango-glib - - platforms - - linux64 - - archive - - hash - de7bba8fd2275a11b077b124413065d0 - url - 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 - - name - linux64 - - - license - lgpl - license_file - LICENSES/gtk-atk-pango-glib.txt - copyright - Copyright (various, see sources) - version - 0.1 - name - gtk-atk-pango-glib - havok-source platforms @@ -921,14 +907,14 @@ archive - creds - github hash a193ff65d6db48626d65d96c6124c6efca85e8ec hash_algorithm sha1 url https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/108912596 + creds + github name darwin64 @@ -949,14 +935,14 @@ archive - creds - github hash ebfb82b6143874e7938b9d1e8a70d0a2e28aa818 hash_algorithm sha1 url https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/108912599 + creds + github name windows64 @@ -1005,33 +991,33 @@ name darwin64 - linux64 + windows64 archive hash - 99e96926b7cf668d8e8195a021d6eacb09de32a0 + b7db881dac80302e4d9010af34c0bf6ca9897df9 hash_algorithm sha1 url - https://github.com/secondlife/3p-icu4c/releases/download/v4.8.1-7d08d82/icu4c-4.8.1-linux64-7d08d82.tar.zst + https://github.com/secondlife/3p-icu4c/releases/download/v4.8.1-7d08d82/icu4c-4.8.1-windows64-7d08d82.tar.zst name - linux64 + windows64 - windows64 + linux64 archive hash - b7db881dac80302e4d9010af34c0bf6ca9897df9 + bdd74e2a02c7b78fded9222140d197da4af9904e hash_algorithm sha1 url - https://github.com/secondlife/3p-icu4c/releases/download/v4.8.1-7d08d82/icu4c-4.8.1-windows64-7d08d82.tar.zst + https://github.com/secondlife/3p-icu4c/releases/download/v4.8.1-8bff176/icu4c-4.8.1-linux64-8512575562.tar.zst name - windows64 + linux64 version @@ -1176,11 +1162,11 @@ archive hash - 97e268754808cb2fbd682c4d3beafd2c598e1ba7 + 66dce1d0c2fc19dff13db279d973773fc7e2aa13 hash_algorithm sha1 url - https://github.com/secondlife/3p-jsoncpp/releases/download/v0.5.0.bc46e62/jsoncpp-0.5.0.bc46e62-linux64-bc46e62.tar.zst + https://github.com/secondlife/3p-jsoncpp/releases/download/v0.5.0-cc63e92/jsoncpp-0.5.0.cc63e92-linux64-cc63e92.tar.zst name linux64 @@ -1207,7 +1193,7 @@ copyright Copyright (c) 2007-2010 Baptiste Lepilleur version - 0.5.0.bc46e62 + 0.5.0.1db375e name jsoncpp description @@ -1221,14 +1207,14 @@ archive - creds - github hash bcc7e2c34896fc9cbc41828dee8a4ddf54f10453 hash_algorithm sha1 url https://api.github.com/repos/secondlife/3p-kdu/releases/assets/108298968 + creds + github name darwin64 @@ -1237,14 +1223,14 @@ archive - creds - github hash 9de772df2ed12e9c742df6c90670c7cbbb9c93a6 hash_algorithm sha1 url https://api.github.com/repos/secondlife/3p-kdu/releases/assets/108298969 + creds + github name linux64 @@ -1253,14 +1239,14 @@ archive - creds - github hash 92533ff0f8c1881ad85e75800f9072c413ccf7b7 hash_algorithm sha1 url https://api.github.com/repos/secondlife/3p-kdu/releases/assets/108298970 + creds + github name windows64 @@ -1529,7 +1515,7 @@ copyright Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved. version - 2.9.4.7476681 + 2.9.4.2db4418 name libxml2 description @@ -2138,9 +2124,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 45ebd074053dc9cae8c5c74b52085d4b + 90052be851c4fcecc35d8424b4f31352de14ab2f + hash_algorithm + sha1 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/465/990/ogg_vorbis-1.2.2-1.3.2.500397-linux64-500397.tar.bz2 + 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 name linux64 @@ -2167,7 +2155,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors copyright Copyright (c) 2002, Xiph.org Foundation version - 1.3.3-1.3.6.e4101b6 + 1.3.3-1.3.6.881f65e name ogg_vorbis description @@ -2175,6 +2163,23 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors open-libndofdev + platforms + + linux64 + + archive + + hash + 2d20683554f0b00234bbb84d0ce7ac1be1ad70aa + hash_algorithm + sha1 + url + https://github.com/secondlife/3p-open-libndofdev/releases/download/v1.14-r1/open_libndofdev-0.14.8503290964-linux64-8503290964.tar.zst + + name + linux64 + + license BSD license_file @@ -2182,7 +2187,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors copyright Copyright (c) 2008, Jan Ciger (jan.ciger (at) gmail.com) version - 0.3 + 0.14.8503290964 name open-libndofdev description @@ -2422,7 +2427,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors copyright Copyright (c) 1997-2014 University of Cambridge; Copyright(c) 2009-2014 Zoltan Herczeg; Copyright (c) 2007-2012, Google Inc. version - 8.35.979fd86 + 8.35.3c0eb51 name pcre description @@ -2436,14 +2441,14 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive - creds - github hash cc7c5bf53f83cff81d874ad66394df0991bd432c hash_algorithm sha1 url https://api.github.com/repos/secondlife/3p-slvoice/releases/assets/108299352 + creds + github name darwin64 @@ -2464,14 +2469,14 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive - creds - github hash 0c205371bb1731a9812b00556037729fdc057cbc hash_algorithm sha1 url https://api.github.com/repos/secondlife/3p-slvoice/releases/assets/108299356 + creds + github name windows64 @@ -2744,16 +2749,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors viewer-fonts - copyright - 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 - description - Viewer fonts - license - Various open source - license_file - LICENSES/fonts.txt - name - viewer-fonts platforms darwin64 @@ -2780,9 +2775,33 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors name windows64 + common + + archive + + hash + c25de57e57856a826b2c146ac951ae0b53250666 + hash_algorithm + sha1 + url + https://github.com/secondlife/3p-viewer-fonts/releases/download/v1.0.0-r1/viewer_fonts-1.0.0.8512067490-common-8512067490.tar.zst + + name + common + + license + Various open source + license_file + LICENSES/fonts.txt + copyright + 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 version - 1.579464 + 1.0.0.8512067490 + name + viewer-fonts + description + Viewer fonts viewer-manager @@ -3312,11 +3331,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors -G Ninja -DLL_TESTS=Off - + arguments ../indra - + build @@ -3337,7 +3356,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors -G Ninja -DLL_TESTS=Off - + build diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 24534c98d9..486071a2df 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -87,7 +87,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) @@ -107,7 +107,15 @@ endif (WINDOWS) if (LINUX) - set(CMAKE_SKIP_RPATH TRUE) + 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() # EXTERNAL_TOS # force this platform to accept TOS via external browser @@ -134,21 +142,28 @@ if (LINUX) -pthread -Wno-parentheses -Wno-deprecated + -Wno-c++20-compat + -Wno-pessimizing-move + -Wno-stringop-overflow + -Wno-stringop-truncation -fvisibility=hidden ) - - if (ADDRESS_SIZE EQUAL 32) - add_compile_options(-march=pentium4) - endif (ADDRESS_SIZE EQUAL 32) + add_link_options( + -Wl,--no-keep-memory + -Wl,--build-id + ) # 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}") -endif (LINUX) + # 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 + if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -lstdc++ -lm") + endif() +endif (LINUX) if (DARWIN) # Warnings should be fatal -- thanks, Nicky Perian, for spotting reversed default @@ -182,9 +197,10 @@ if (LINUX OR DARWIN) list(APPEND GCC_WARNINGS -Wno-reorder -Wno-non-virtual-dtor ) + if(LINUX) + list(APPEND GCC_WARNINGS -Wno-maybe-uninitialized -Wno-misleading-indentation -Wno-stringop-truncation -Wno-unused-value ) + endif() + add_compile_options(${GCC_WARNINGS}) add_compile_options(-m${ADDRESS_SIZE}) endif (LINUX OR DARWIN) - - - 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/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 48930c1c19..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 a9714696b4..8382ceef1e 100644 --- a/indra/cmake/ICU4C.cmake +++ b/indra/cmake/ICU4C.cmake @@ -13,7 +13,7 @@ if (WINDOWS) elseif(DARWIN) target_link_libraries( ll::icu4c INTERFACE icuuc) elseif(LINUX) - target_link_libraries( ll::icu4c INTERFACE icuuc) + 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/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/UI.cmake b/indra/cmake/UI.cmake index 8b70192efc..0eb9af6dcf 100644 --- a/indra/cmake/UI.cmake +++ b/indra/cmake/UI.cmake @@ -1,35 +1,43 @@ # -*- 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 ) + target_compile_definitions(ll::uilibraries INTERFACE LL_X11=1 ) if( USE_CONAN ) - target_link_libraries( ll::uilibraries INTERFACE CONAN_PKG::gtk ) return() endif() - use_prebuilt_binary(gtk-atk-pango-glib) - + + find_package(FLTK REQUIRED ) + find_library(ND_FLTK_STATIC_LIBRARY libfltk.a PATH_SUFFIXES fltk ) + + if( NOT ND_FLTK_STATIC_LIBRARY ) + message(FATAL_ERROR "libfltk.a not found") + else() + message("libfltk.a found ${ND_FLTK_STATIC_LIBRARY}") + endif() + + target_include_directories( ll::uilibraries SYSTEM INTERFACE ${FLTK_INCLUDE_DIR}) + target_compile_definitions( ll::uilibraries INTERFACE LL_FLTK=1 ) 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 + ${ND_FLTK_STATIC_LIBRARY} + 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 +59,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 3e5a37b277..2cb11994fc 100644 --- a/indra/cmake/ViewerMiscLibs.cmake +++ b/indra/cmake/ViewerMiscLibs.cmake @@ -2,15 +2,10 @@ include(Prebuilt) if (LINUX) - #use_prebuilt_binary(libuuid) add_library( ll::fontconfig INTERFACE IMPORTED ) - if( NOT USE_CONAN ) - find_package(Fontconfig REQUIRED) - target_link_libraries( ll::fontconfig INTERFACE Fontconfig::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/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 7bca86119c..ce3b1160c0 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -867,7 +867,7 @@ private: LLPI_SET_INFO_INT(eModel, "model"); - S32 family = 0; + 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 c3e7c544ec..7438524272 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -36,6 +36,7 @@ # include // for htonl #elif LL_LINUX # include +#pragma GCC diagnostic ignored "-Wstringop-truncation" // It's actually okay what happens here #elif LL_DARWIN # include #endif diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 938685bae6..988c74229c 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$ */ @@ -97,7 +97,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 @@ -187,7 +187,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. @@ -267,12 +267,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)) @@ -283,7 +283,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()); } @@ -292,12 +292,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); @@ -312,9 +312,9 @@ LLOSInfo::LLOSInfo() : { mOSString = mOSStringSimple; } - + #elif LL_LINUX - + struct utsname un; if(uname(&un) != -1) { @@ -354,7 +354,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 @@ -368,7 +368,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; } @@ -384,7 +384,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; } @@ -410,7 +410,7 @@ LLOSInfo::LLOSInfo() : } #else - + struct utsname un; if(uname(&un) != -1) { @@ -510,57 +510,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 @@ -578,7 +567,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 } @@ -1003,11 +992,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; @@ -1027,16 +1016,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); } } @@ -1048,7 +1037,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; @@ -1063,8 +1052,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 // @@ -1350,8 +1339,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 c1ee052997..369d55defe 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -161,7 +161,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/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 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..15de4046ac 100644 --- a/indra/llmessage/llnamevalue.cpp +++ b/indra/llmessage/llnamevalue.cpp @@ -35,6 +35,10 @@ #include "llstring.h" #include "llstringtable.h" +#if LL_LINUX +#pragma GCC diagnostic ignored "-Wstringop-truncation" // It's actually okay what happens here +#endif + // Anonymous enumeration to provide constants in this file. // *NOTE: These values may be used in sscanf statements below as their // value-1, so search for '2047' if you cange NV_BUFFER_LEN or '63' if 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 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(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 #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 9d3abf32bb..0850fe3e05 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 @@ -148,7 +148,7 @@ void APIENTRY gl_debug_callback(GLenum source, glGetBufferParameteriv(GL_UNIFORM_BUFFER, GL_BUFFER_SIZE, &ubo_size); glGetBufferParameteriv(GL_UNIFORM_BUFFER, GL_BUFFER_IMMUTABLE_STORAGE, &ubo_immutable); } - + if (severity == GL_DEBUG_SEVERITY_HIGH) { LL_ERRS() << "Halting on GL Error" << LL_ENDL; @@ -166,7 +166,7 @@ void ll_init_fail_log(std::string filename) void ll_fail(std::string msg) { - + if (gDebugSession) { std::vector lines; @@ -176,7 +176,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; @@ -199,8 +199,6 @@ LLMatrix4 gGLObliqueProjectionInverse; std::list LLGLUpdate::sGLQ; -#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS - #if LL_WINDOWS // WGL_ARB_create_context PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; @@ -220,8 +218,6 @@ PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC wglBlitContextFramebufferAMD = n PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr; PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = nullptr; -#endif - // GL_VERSION_1_2 //PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements = nullptr; //PFNGLTEXIMAGE3DPROC glTexImage3D = nullptr; @@ -991,7 +987,7 @@ LLGLManager::LLGLManager() : mDriverVersionRelease(0), mGLVersion(1.0f), mGLSLVersionMajor(0), - mGLSLVersionMinor(0), + mGLSLVersionMinor(0), mVRAM(0), mGLMaxVertexRange(0), mGLMaxIndexRange(0) @@ -1018,7 +1014,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) @@ -1071,7 +1067,7 @@ bool LLGLManager::initGL() str << ext << " "; LL_DEBUGS("GLExtensions") << ext << LL_ENDL; } - + { PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0; wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); @@ -1086,7 +1082,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)); @@ -1095,9 +1091,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); @@ -1127,7 +1123,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 @@ -1157,7 +1153,7 @@ bool LLGLManager::initGL() { mGLVendorShort = "MISC"; } - + // This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture. initExtensions(); @@ -1281,12 +1277,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; } @@ -1369,6 +1365,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{""}; @@ -1386,9 +1385,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; @@ -1399,10 +1398,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"); @@ -1420,8 +1418,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 @@ -2237,7 +2233,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 } @@ -2260,7 +2256,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)) @@ -2268,7 +2264,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 { @@ -2282,7 +2278,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; @@ -2339,7 +2335,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 } @@ -2348,7 +2344,7 @@ void assert_glerror() do_assert_glerror(); } } - + void clear_glerror() { @@ -2369,11 +2365,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); @@ -2392,7 +2388,7 @@ void LLGLState::resetTextureStates() { gGL.flush(); GLint maxTextureUnits; - + glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextureUnits); for (S32 j = maxTextureUnits-1; j >=0; j--) { @@ -2402,7 +2398,7 @@ void LLGLState::resetTextureStates() } } -void LLGLState::dumpStates() +void LLGLState::dumpStates() { LL_INFOS("RenderState") << "GL States:" << LL_ENDL; for (boost::unordered_map::iterator iter = sStateMap.begin(); @@ -2425,15 +2421,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::iterator iter = sStateMap.begin(); iter != sStateMap.end(); ++iter) { @@ -2487,7 +2483,7 @@ void LLGLState::setEnabled(S32 enabled) mIsEnabled = enabled; } -LLGLState::~LLGLState() +LLGLState::~LLGLState() { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; if (mState) @@ -2536,7 +2532,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: // .[.] [] const char* version = (const char*) glGetString(GL_VERSION); @@ -2549,6 +2545,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); @@ -2619,13 +2616,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: // .[.] [] const char* version = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION); major = 0; minor = 0; - + if( !version ) { return; @@ -2694,7 +2691,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; @@ -2725,7 +2722,7 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G : mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled) { stop_glerror(); - + checkState(); if (!depth_enabled) @@ -2848,7 +2845,7 @@ LLGLSquashToFarClip::~LLGLSquashToFarClip() } - + LLGLSyncFence::LLGLSyncFence() { mSync = 0; @@ -2898,7 +2895,7 @@ void LLGLSyncFence::wait() LLGLSPipelineSkyBox::LLGLSPipelineSkyBox() : mCullFace(GL_CULL_FACE) , mSquashClip() -{ +{ } LLGLSPipelineSkyBox::~LLGLSPipelineSkyBox() @@ -2913,20 +2910,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 c1238ac6b9..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 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 LLKeyboard::sKeysToNames; std::map 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::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::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 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 mTranslateKeyMap; // Map of translations from OS keys to Linden KEYs - std::map mInvTranslateKeyMap; // Map of translations from Linden KEYs to OS keys + std::map mTranslateKeyMap; // Map of translations from OS keys to Linden KEYs + std::map 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 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::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... + + // 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] = ' '; // 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] = '='; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_COMMA] = ','; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_MINUS] = '-'; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_PERIOD] = '.'; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_BACKQUOTE] = '`'; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_SLASH] = KEY_DIVIDE; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_SEMICOLON] = ';'; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_LEFTBRACKET] = '['; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_BACKSLASH] = '\\'; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_RIGHTBRACKET] = ']'; // Those are handled by SDL2 via text input, do not map them + mTranslateKeyMap[SDLK_QUOTE] = '\''; // 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 ) +{ + // 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 mTranslateNumpadMap; // special map for translating OS keys to numpad keys - std::map mInvTranslateNumpadMap; // inverse of the above + std::map mTranslateNumpadMap; // special map for translating OS keys to numpad keys + std::map 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 -#endif // LL_GTK +#ifdef LL_GLIB +#include +#endif extern "C" { # include "fontconfig/fontconfig.h" @@ -57,6 +52,7 @@ extern "C" { # include # include # include +# include #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 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 > 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> 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() <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 ); + + 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; - } - - return FALSE; + 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_WarpMouseInWindow(mWindow, screen_pos.mX, screen_pos.mY); - // 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; + //LL_INFOS() << llformat("llcw %d,%d -> scr %d,%d", position.mX, position.mY, screen_pos.mX, screen_pos.mY) << LL_ENDL; - return result; + 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); - - - 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. - // 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; + + LL_INFOS() << "X11 hint for urgency, " << urgent << LL_ENDL; - maybe_lock_display(); - wm_hints = XGetWMHints(mSDL_Display, mSDL_XWindowID); - if (!wm_hints) - wm_hints = XAllocWMHints(); + maybe_lock_display(); + wm_hints = XGetWMHints(mSDL_Display, mSDL_XWindowID); + if (!wm_hints) + wm_hints = XAllocWMHints(); - if (urgent) - wm_hints->flags |= XUrgencyHint; - else - wm_hints->flags &= ~XUrgencyHint; + 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(); - } + 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; -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 -} + F32 remaining_time = mFlashTimer.getRemainingTimeF32(); + if (remaining_time < seconds) + remaining_time = seconds; + mFlashTimer.reset(); + mFlashTimer.setTimerExpirySec(remaining_time); -#else + x11_set_urgent(TRUE); + mFlashing = TRUE; +#endif // LL_X11 + } +} 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; + + // Use display no from mWindow/mSurface here? + int max = SDL_GetNumDisplayModes(0); + max = llclamp( max, 0, MAX_NUM_RESOLUTIONS ); - SDL_Rect **modes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN); - if ( (modes != NULL) && (modes != ((SDL_Rect **) -1)) ) + for( int i =0; i < max; ++i ) { - int count = 0; - while (*modes && count= 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 ); + + // 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*/ ) // 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! + // I think is is not + // SDL_SetWindowSize(mWindow, width, height); + // + + mCallbacks->handleResize(this, width, height); + } + else if( event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED ) // 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 ) // 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); + } + 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; + 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; ih; ++i) { - for (j=0; jw; ++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; ih; ++i) { + for (j=0; jw; ++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; ibeforeDialog(); - - 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; + LLSD result = LLSD::emptyMap(); - beforeDialog(); + U32 modifiers = 0; // pretend-native modifiers... oh what a tangled web we weave! - if (ll_try_gtk_init()) - { - GtkWidget *win = NULL; + // 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). - win = gtk_color_selection_dialog_new(NULL); - -# if LL_X11 - // Get GTK to tell the window manager to associate this - // dialog with our non-GTK SDL window, which should try - // to keep it on top etc. - if (mSDL_XWindowID != None) - { - gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(mSDL_XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); - } -# endif //LL_X11 - - GtkColorSelection *colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG(win)->colorsel); - - GdkColor color, orig_color; - orig_color.pixel = 0; - orig_color.red = guint16(65535 * *r); - orig_color.green= guint16(65535 * *g); - orig_color.blue = guint16(65535 * *b); - color = orig_color; - - gtk_color_selection_set_previous_color (colorsel, &color); - gtk_color_selection_set_current_color (colorsel, &color); - gtk_color_selection_set_has_palette (colorsel, TRUE); - gtk_color_selection_set_has_opacity_control(colorsel, FALSE); - - gint response = GTK_RESPONSE_NONE; - g_signal_connect (win, - "response", - G_CALLBACK (response_callback), - &response); - - g_signal_connect (G_OBJECT (colorsel), "color_changed", - G_CALLBACK (color_changed_callback), - &color); - - gtk_window_set_modal(GTK_WINDOW(win), TRUE); - gtk_widget_show_all(win); - // hide the help button - we don't service it. - gtk_widget_hide(GTK_COLOR_SELECTION_DIALOG(win)->help_button); - gtk_main(); - - if (response == GTK_RESPONSE_OK && - (orig_color.red != color.red - || orig_color.green != color.green - || orig_color.blue != color.blue) ) - { - *r = color.red / 65535.0f; - *g = color.green / 65535.0f; - *b = color.blue / 65535.0f; - rtn = TRUE; - } - } - - afterDialog(); - - return rtn; -} -#else -S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type) -{ - LL_INFOS() << "MSGBOX: " << caption << ": " << text << LL_ENDL; - return 0; -} - -BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ - return (FALSE); + result["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); + // 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 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 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; infont; ++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::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 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; infont; ++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::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..74b9ff026c 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,295 @@ #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 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 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); + + 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); + // Lazily initialize and check the runtime GTK version for goodness. + static bool ll_try_gtk_init(void); #endif // LL_GTK #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..fe8fee5e7e 100644 --- a/indra/media_plugins/CMakeLists.txt +++ b/indra/media_plugins/CMakeLists.txt @@ -3,7 +3,7 @@ add_subdirectory(base) if (LINUX) - #add_subdirectory(gstreamer010) + add_subdirectory(gstreamer10) add_subdirectory(example) endif (LINUX) diff --git a/indra/media_plugins/gstreamer10/CMakeLists.txt b/indra/media_plugins/gstreamer10/CMakeLists.txt new file mode 100644 index 0000000000..ffa3c30519 --- /dev/null +++ b/indra/media_plugins/gstreamer10/CMakeLists.txt @@ -0,0 +1,46 @@ +# -*- 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 + +if(NOT WINDOWS) # not windows therefore gcc LINUX and DARWIN +add_definitions(-fPIC) +endif() + +set(media_plugin_gstreamer10_SOURCE_FILES + media_plugin_gstreamer10.cpp + llmediaimplgstreamer_syms.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/gstreamer10/llmediaimplgstreamer.h b/indra/media_plugins/gstreamer10/llmediaimplgstreamer.h new file mode 100644 index 0000000000..6bc272c009 --- /dev/null +++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer.h @@ -0,0 +1,53 @@ +/** + * @file llmediaimplgstreamer.h + * @author Tofu Linden + * @brief implementation that supports media playback via GStreamer. + * + * @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 + */ + +// header guard +#ifndef llmediaimplgstreamer_h +#define llmediaimplgstreamer_h + +#if LL_GSTREAMER010_ENABLED + +extern "C" { +#include +#include + +#include "apr_pools.h" +#include "apr_dso.h" +} + + +extern "C" { +gboolean llmediaimplgstreamer_bus_callback (GstBus *bus, + GstMessage *message, + gpointer data); +} + +#endif // LL_GSTREAMER010_ENABLED + +#endif // llmediaimplgstreamer_h diff --git a/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.cpp b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.cpp new file mode 100644 index 0000000000..e5e5c1c9a3 --- /dev/null +++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.cpp @@ -0,0 +1,197 @@ +/** + * @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 + */ + +#include +#include +#include + +#ifdef LL_WINDOWS +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0502 +#include +#endif + +#include "linden_common.h" + +extern "C" { +#include +#include +} + +#include "apr_pools.h" +#include "apr_dso.h" + +#ifdef LL_WINDOWS + +#ifndef _M_AMD64 +#define GSTREAMER_REG_KEY "Software\\GStreamer1.0\\x86" +#define GSTREAMER_DIR_SUFFIX "1.0\\x86\\bin\\" +#else +#define GSTREAMER_REG_KEY "Software\\GStreamer1.0\\x86_64" +#define GSTREAMER_DIR_SUFFIX "1.0\\x86_64\\bin\\" +#endif + +bool openRegKey( HKEY &aKey ) +{ + // Try native (32 bit view/64 bit view) of registry first. + if( ERROR_SUCCESS == ::RegOpenKeyExA( HKEY_LOCAL_MACHINE, GSTREAMER_REG_KEY, 0, KEY_QUERY_VALUE, &aKey ) ) + return true; + + // If native view fails, use 32 bit view or registry. + if( ERROR_SUCCESS == ::RegOpenKeyExA( HKEY_LOCAL_MACHINE, GSTREAMER_REG_KEY, 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &aKey ) ) + return true; + + return false; +} + +std::string getGStreamerDir() +{ + std::string ret; + HKEY hKey; + + if( openRegKey( hKey ) ) + { + DWORD dwLen(0); + ::RegQueryValueExA( hKey, "InstallDir", nullptr, nullptr, nullptr, &dwLen ); + + if( dwLen > 0 ) + { + std::vector< char > vctBuffer; + vctBuffer.resize( dwLen ); + ::RegQueryValueExA( hKey, "InstallDir", nullptr, nullptr, reinterpret_cast< LPBYTE>(&vctBuffer[ 0 ]), &dwLen ); + ret = &vctBuffer[0]; + + if( ret[ dwLen-1 ] != '\\' ) + ret += "\\"; + ret += GSTREAMER_DIR_SUFFIX; + + SetDllDirectoryA( ret.c_str() ); + } + ::RegCloseKey( hKey ); + } + return ret; +} +#else +std::string getGStreamerDir() { return ""; } +#endif + +#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL; +#include "llmediaimplgstreamer_syms_raw.inc" +#undef LL_GST_SYM + +struct Symloader +{ + bool mRequired; + char const *mName; + apr_dso_handle_sym_t *mPPFunc; +}; + +#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) { REQ, #GSTSYM , (apr_dso_handle_sym_t*)&ll##GSTSYM}, +Symloader sSyms[] = { +#include "llmediaimplgstreamer_syms_raw.inc" +{ false, 0, 0 } }; +#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; + +std::vector< apr_dso_handle_t* > sLoadedLibraries; + +bool grab_gst_syms( std::vector< std::string > const &aDSONames ) +{ + if (sSymsGrabbed) + return true; + + //attempt to load the shared libraries + apr_pool_create(&sSymGSTDSOMemoryPool, NULL); + + for( std::vector< std::string >::const_iterator itr = aDSONames.begin(); itr != aDSONames.end(); ++itr ) + { + apr_dso_handle_t *pDSO(NULL); + std::string strDSO = getGStreamerDir() + *itr; + if( APR_SUCCESS == apr_dso_load( &pDSO, strDSO.c_str(), sSymGSTDSOMemoryPool )) + sLoadedLibraries.push_back( pDSO ); + + for( int i = 0; sSyms[ i ].mName; ++i ) + { + if( !*sSyms[ i ].mPPFunc ) + { + apr_dso_sym( sSyms[ i ].mPPFunc, pDSO, sSyms[ i ].mName ); + } + } + } + + std::stringstream strm; + bool sym_error = false; + for( int i = 0; sSyms[ i ].mName; ++i ) + { + if( sSyms[ i ].mRequired && ! *sSyms[ i ].mPPFunc ) + { + sym_error = true; + strm << sSyms[ i ].mName << std::endl; + } + } + + sSymsGrabbed = !sym_error; + return sSymsGrabbed; +} + + +void ungrab_gst_syms() +{ + // should be safe to call regardless of whether we've + // actually grabbed syms. + + for( std::vector< apr_dso_handle_t* >::iterator itr = sLoadedLibraries.begin(); itr != sLoadedLibraries.end(); ++itr ) + apr_dso_unload( *itr ); + + sLoadedLibraries.clear(); + + if ( sSymGSTDSOMemoryPool ) + { + apr_pool_destroy(sSymGSTDSOMemoryPool); + sSymGSTDSOMemoryPool = NULL; + } + + for( int i = 0; sSyms[ i ].mName; ++i ) + *sSyms[ i ].mPPFunc = NULL; + + sSymsGrabbed = false; +} + diff --git a/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.h b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.h new file mode 100644 index 0000000000..0874644ee6 --- /dev/null +++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.h @@ -0,0 +1,68 @@ +/** + * @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" +#include +extern "C" { +#include +} + +bool grab_gst_syms( std::vector< std::string > const&); +void ungrab_gst_syms(); + +#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) extern RTN (*ll##GSTSYM)(__VA_ARGS__); +#include "llmediaimplgstreamer_syms_raw.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))) 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..155eeb6809 --- /dev/null +++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc @@ -0,0 +1,68 @@ +LL_GST_SYM(true, gst_buffer_new, GstBuffer*, void) +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_caps_from_string, GstCaps *, const gchar *string) +LL_GST_SYM(true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index) +LL_GST_SYM(true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type) +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, const 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, const gchar *, const GstStructure *structure) +LL_GST_SYM(true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64) + +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) + +LL_GST_SYM( true, gst_message_parse_tag, void, GstMessage *, GstTagList **) +LL_GST_SYM( true, gst_tag_list_foreach, void, const GstTagList *, GstTagForeachFunc, gpointer) +LL_GST_SYM( true, gst_tag_list_get_tag_size, guint, const GstTagList *, const gchar *) +LL_GST_SYM( true, gst_tag_list_get_value_index, const GValue *, const GstTagList *, const gchar *, guint) + +LL_GST_SYM( true, gst_caps_new_simple, GstCaps*, const char *, const char*, ... ) + +LL_GST_SYM( true, gst_sample_get_caps, GstCaps*, GstSample* ) +LL_GST_SYM( true, gst_sample_get_buffer, GstBuffer*, GstSample* ) +LL_GST_SYM( true, gst_buffer_map, gboolean, GstBuffer*, GstMapInfo*, GstMapFlags ) +LL_GST_SYM( true, gst_buffer_unmap, void, GstBuffer*, GstMapInfo* ) + +LL_GST_SYM( true, gst_app_sink_set_caps, void, GstAppSink*, GstCaps const* ) +LL_GST_SYM( true, gst_app_sink_pull_sample, GstSample*, GstAppSink* ) + +LL_GST_SYM( true, g_free, void, gpointer ) +LL_GST_SYM( true, g_error_free, void, GError* ) + +LL_GST_SYM( true, g_main_context_pending, gboolean, GMainContext* ) +LL_GST_SYM( true, g_main_loop_get_context, GMainContext*, GMainLoop* ) +LL_GST_SYM( true, g_main_context_iteration, gboolean, GMainContext*, gboolean ) +LL_GST_SYM( true, g_main_loop_new, GMainLoop*, GMainContext*, gboolean ) +LL_GST_SYM( true, g_main_loop_quit, void, GMainLoop* ) +LL_GST_SYM( true, gst_mini_object_unref, void, GstMiniObject* ) +LL_GST_SYM( true, g_object_set, void, gpointer, gchar const*, ... ) +LL_GST_SYM( true, g_source_remove, gboolean, guint ) +LL_GST_SYM( true, g_value_get_string, gchar const*, GValue const* ) + + +LL_GST_SYM( true, gst_debug_set_active, void, gboolean ) +LL_GST_SYM( true, gst_debug_add_log_function, void, GstLogFunction, gpointer, GDestroyNotify ) +LL_GST_SYM( true, gst_debug_set_default_threshold, void, GstDebugLevel ) +LL_GST_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..07bfb67283 --- /dev/null +++ b/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp @@ -0,0 +1,982 @@ +/** + * @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 +#include + +} + +#include "llmediaimplgstreamer.h" +#include "llmediaimplgstreamer_syms.h" + +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 ( NULL ) + , mPlaybin ( NULL ) + , mAppSink ( NULL ) + , 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 = NULL; + gchar *debug = NULL; + + 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 = NULL; + gchar *debug = NULL; + + llgst_message_parse_info (message, &err, &debug); + if (err) + llg_error_free (err); + llg_free (debug); + } + break; + } + case GST_MESSAGE_WARNING: + { + GError *err = NULL; + gchar *debug = NULL; + + 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 (NULL == mPump || NULL == mPlaybin) + { + setStatus(STATUS_ERROR); + return false; // error + } + + llg_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL); + + // 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 (NULL == mPump || NULL == 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, NULL); + 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 (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", ""); + 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, + NULL ); + + 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, NULL); + + 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 = NULL; + } + + if (mPump) + { + llg_main_loop_quit(mPump); + mPump = NULL; + } + + mAppSink = NULL; + + 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 ) +#ifndef LL_LINUX // Docu says we need G_GNUC_NO_INSTRUMENT, but GCC says 'error' + G_GNUC_NO_INSTRUMENT +#endif +{ +#ifdef LL_LINUX + std::cerr << file << ":" << line << "(" << function << "): " << llgst_debug_message_get( message ) << std::endl; +#endif +} + +//static +bool MediaPluginGStreamer10::startup() +{ + // first - check if GStreamer is explicitly disabled + if (NULL != getenv("LL_DISABLE_GSTREAMER")) + return false; + + // only do global GStreamer initialization once. + if (!mDoneInit) + { + ll_init_apr(); + + // Get symbols! + std::vector< std::string > vctDSONames; +#if LL_DARWIN +#elif LL_WINDOWS + vctDSONames.push_back( "libgstreamer-1.0-0.dll" ); + vctDSONames.push_back( "libgstapp-1.0-0.dll" ); + vctDSONames.push_back( "libglib-2.0-0.dll" ); + vctDSONames.push_back( "libgobject-2.0-0.dll" ); +#else // linux or other ELFy unixoid + 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" ); +#endif + if( !grab_gst_syms( vctDSONames ) ) + { + return false; + } + + if (llgst_segtrap_set_enabled) + { + llgst_segtrap_set_enabled(FALSE); + } +#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); + +// _putenv_s( "GST_PLUGIN_PATH", "E:\\gstreamer\\1.0\\x86\\lib\\gstreamer-1.0" ); + + llgst_debug_set_default_threshold( GST_LEVEL_WARNING ); + llgst_debug_add_log_function( LogFunction, NULL, NULL ); + llgst_debug_set_active( false ); + + // 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) + { + llg_error_free(err); + } + return false; + } + + mDoneInit = true; + } + + return true; +} + +//static +bool MediaPluginGStreamer10::closedown() +{ + if (!mDoneInit) + return false; // error + + ungrab_gst_syms(); + + 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 = NULL; + 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/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 355f35c558..f359bebb17 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1432,7 +1432,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) 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 -#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 +#include + +#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 = "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ""; + +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" ); // 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 -} - -#if LL_DBUS_ENABLED -extern "C" { -# include -# include -} -#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 - -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 -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 @@ - - - - - - - - - - - - - - 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 - -#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 -} - -#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..e541d2ab00 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -41,6 +41,10 @@ # include "llfilepicker.h" #endif +#ifdef LL_FLTK + #include "FL/Fl.H" + #include "FL/Fl_Native_File_Chooser.H" +#endif // // Globals // @@ -193,20 +197,28 @@ LLDirPicker::LLDirPicker() : mFileName(NULL), mLocked(false) { +#ifndef LL_FLTK mFilePicker = new LLFilePicker(); +#endif reset(); } LLDirPicker::~LLDirPicker() { +#ifndef LL_FLTK delete mFilePicker; +#endif } void LLDirPicker::reset() { +#ifndef LL_FLTK if (mFilePicker) mFilePicker->reset(); +#else + mDir = ""; +#endif } BOOL LLDirPicker::getDir(std::string* filename, bool blocking) @@ -219,6 +231,7 @@ BOOL LLDirPicker::getDir(std::string* filename, bool blocking) return FALSE; } +#ifndef LL_FLTK #if !LL_MESA_HEADLESS if (mFilePicker) @@ -237,15 +250,38 @@ BOOL LLDirPicker::getDir(std::string* filename, bool blocking) #endif // !LL_MESA_HEADLESS return FALSE; +#else + 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 ) + { + char const *pDir = flDlg.filename(0); + if( pDir ) + mDir = pDir; + } + else if( res == -1 ) + { + LL_WARNS() << "FLTK failed: " << flDlg.errmsg() << LL_ENDL; + } + return !mDir.empty(); +#endif } std::string LLDirPicker::getDirName() { +#ifndef LL_FLTK if (mFilePicker) { return mFilePicker->getFirstFile(); } return ""; +#else + return mDir; +#endif } #else // not implemented diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h index 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..b6405df1ff 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -839,7 +839,6 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, //VECTORIZE THIS LLMatrix4a mat_vert; mat_vert.loadu(mat_vert_in); - LLVector4a new_extents[2]; llassert(less_than_max_mag(face.mExtents[0])); llassert(less_than_max_mag(face.mExtents[1])); diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 5b8ca6c49c..a7998f6e9e 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -947,7 +947,7 @@ void LLFastTimerView::printLineStats() { std::string legend_stat; bool first = true; - for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); it != LLTrace::end_block_timer_tree_df(); ++it) { @@ -969,7 +969,7 @@ void LLFastTimerView::printLineStats() std::string timer_stat; first = true; - for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); it != LLTrace::end_block_timer_tree_df(); ++it) { @@ -1046,7 +1046,7 @@ void LLFastTimerView::drawLineGraph() F32Seconds cur_max(0); U32 cur_max_calls = 0; - for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); it != LLTrace::end_block_timer_tree_df(); ++it) { @@ -1195,8 +1195,8 @@ void LLFastTimerView::drawLegend() S32 scroll_offset = 0; // element's y offset from top of the inner scroll's rect ft_display_idx.clear(); std::map display_line; - for (block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); - it != block_timer_tree_df_iterator_t(); + for (LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + it != LLTrace::end_block_timer_tree_df(); ++it) { BlockTimerStatHandle* idp = (*it); @@ -1311,8 +1311,8 @@ void LLFastTimerView::generateUniqueColors() F32 hue = 0.f; - for (block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); - it != block_timer_tree_df_iterator_t(); + for (LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); + it != LLTrace::end_block_timer_tree_df(); ++it) { BlockTimerStatHandle* idp = (*it); diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 38daff9937..5686627776 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -33,6 +33,12 @@ #ifndef LL_LLFILEPICKER_H #define LL_LLFILEPICKER_H +#if LL_FLTK + #if LL_GTK + #undef LL_GTK + #endif +#endif + #include "stdtypes.h" #if LL_DARWIN @@ -58,6 +64,7 @@ extern "C" { // mostly for Linux, possible on others #if LL_GTK # include "gtk/gtk.h" +#error "Direct use of GTK is deprecated" #endif // LL_GTK } @@ -192,6 +199,13 @@ private: // we also remember the extension of the last added file. std::string mCurrentExtension; #endif +#if LL_FLTK + enum EType + { + eSaveFile, eOpenFile, eOpenMultiple + }; + bool openFileDialog( int32_t filter, bool blocking, EType aType ); +#endif std::vector mFiles; S32 mCurrentFile; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index d4eb40ff92..fdfc5b08cb 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -3850,15 +3850,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/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 7b4283e94d..6091488c53 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -621,13 +621,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/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/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 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 { 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 { GetTEVal(DataType default_value) : _default(default_value) {} @@ -621,4 +621,3 @@ public: }; #endif - 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 mButtonData; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 6ac94fe4c4..c1f4f858c1 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -67,6 +67,11 @@ #include "lluiusage.h" #include "lltranslate.h" +#if LL_LINUX +#pragma GCC diagnostic ignored "-Wunused-value" // Happens due to LL_DEBUGS("LogViewerStatsPacket"); Does that even do anything? +#endif + + // "Minimal Vulkan" to get max API Version // Calls @@ -827,6 +832,8 @@ void send_viewer_stats(bool include_preferences) LL_INFOS("LogViewerStatsPacket") << "Sending viewer statistics: " << body << LL_ENDL; + + // 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 bda8c35702..b422de8f9c 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -5995,7 +5995,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 716a65dbcf..e5067132fd 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5765,8 +5765,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 ba7e8d7298..c3835bd60e 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/viewer_manifest.py b/indra/newview/viewer_manifest.py index c7f32d0da9..3de57c6bf4 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1202,6 +1202,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,44 +1223,121 @@ 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(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(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)") + """ + Once we got CEF enable this + 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" ) + with self.prefix(src=os.path.join(pkgdir, 'lib', 'release', 'swiftshader'), dst=os.path.join("bin", "swiftshader") ): + self.path( "*.so" ) + with self.prefix(src=os.path.join(pkgdir, 'lib', 'release', 'swiftshader'), dst=os.path.join("lib", "swiftshader") ): + self.path( "*.so" ) + + 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="bin"): + 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'), 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('bin', '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): @@ -1294,76 +1374,53 @@ class LinuxManifest(ViewerManifest): self.run_command(["mv", tempname, 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 +1441,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__": -- cgit v1.2.3