diff --git a/doc/contributions.txt b/doc/contributions.txt index 258e139bc..53ab212d8 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -74,6 +74,7 @@ Aleric Inglewood VWR-24312 VWR-24320 VWR-24333 + VWR-24334 SNOW-47 SNOW-84 SNOW-86 @@ -112,7 +113,9 @@ Aleric Inglewood IMP-664 IMP-670 IMP-701 + IMP-702 IMP-734 + IMP-735 Alissa Sabre VWR-81 VWR-83 diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 33637ab1e..c0e8dc408 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -44,6 +44,7 @@ endif(NOT STANDALONE) add_custom_target(prepare DEPENDS ${prepare_depends}) add_subdirectory(cmake) +add_subdirectory(${LIBS_OPEN_PREFIX}cwdebug) add_subdirectory(${LIBS_OPEN_PREFIX}llaudio) add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter) add_subdirectory(${LIBS_OPEN_PREFIX}llcommon) @@ -75,8 +76,8 @@ if (VIEWER) add_subdirectory(${LIBS_OPEN_PREFIX}llplugin) add_subdirectory(${LIBS_OPEN_PREFIX}llui) - # viewer media plugins - add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins) + # viewer plugins directory + add_subdirectory(${LIBS_OPEN_PREFIX}plugins) # llplugin testbed code (is this the right way to include it?) #if (NOT LINUX) @@ -105,6 +106,7 @@ if (VIEWER) add_dependencies(viewer solaris-crash-logger) endif (LINUX) + add_subdirectory(${VIEWER_PREFIX}newview/statemachine) add_subdirectory(${VIEWER_PREFIX}newview) add_dependencies(viewer secondlife-bin) endif (VIEWER) diff --git a/indra/cmake/AIStateMachine.cmake b/indra/cmake/AIStateMachine.cmake new file mode 100644 index 000000000..c1bda40c4 --- /dev/null +++ b/indra/cmake/AIStateMachine.cmake @@ -0,0 +1,4 @@ +# -*- cmake -*- + +set(AISTATEMACHINE_INCLUDE_DIRS statemachine) +set(AISTATEMACHINE_LIBRARIES statemachine) diff --git a/indra/cmake/BasicPluginBase.cmake b/indra/cmake/BasicPluginBase.cmake new file mode 100644 index 000000000..a4f339272 --- /dev/null +++ b/indra/cmake/BasicPluginBase.cmake @@ -0,0 +1,8 @@ +# -*- cmake -*- + + +set(BASIC_PLUGIN_BASE_INCLUDE_DIRS + ${LIBS_OPEN_DIR}/plugins/base_basic/ + ) + +set(BASIC_PLUGIN_BASE_LIBRARIES basic_plugin_base) diff --git a/indra/cmake/Cwdebug.cmake b/indra/cmake/Cwdebug.cmake new file mode 100644 index 000000000..9568a625f --- /dev/null +++ b/indra/cmake/Cwdebug.cmake @@ -0,0 +1 @@ +set(CWDEBUG_LIBRARIES cwdebug) diff --git a/indra/cmake/FindMyZLIB.cmake b/indra/cmake/FindMyZLIB.cmake deleted file mode 100644 index 6d630f1ba..000000000 --- a/indra/cmake/FindMyZLIB.cmake +++ /dev/null @@ -1,46 +0,0 @@ -# -*- cmake -*- - -# - Find zlib -# Find the ZLIB includes and library -# This module defines -# ZLIB_INCLUDE_DIRS, where to find zlib.h, etc. -# ZLIB_LIBRARIES, the libraries needed to use zlib. -# ZLIB_FOUND, If false, do not try to use zlib. -# -# This FindZLIB is about 43 times as fast the one provided with cmake (2.8.x), -# because it doesn't look up the version of zlib, resulting in a dramatic -# speed up for configure (from 4 minutes 22 seconds to 6 seconds). -# -# Note: Since this file is only used for standalone, the windows -# specific parts were left out. - -FIND_PATH(ZLIB_INCLUDE_DIR zlib.h - NO_SYSTEM_ENVIRONMENT_PATH - ) - -FIND_LIBRARY(ZLIB_LIBRARY z) - -if (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR) - SET(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR}) - SET(ZLIB_LIBRARIES ${ZLIB_LIBRARY}) - SET(ZLIB_FOUND "YES") -else (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR) - SET(ZLIB_FOUND "NO") -endif (ZLIB_LIBRARY AND ZLIB_INCLUDE_DIR) - -if (ZLIB_FOUND) - if (NOT ZLIB_FIND_QUIETLY) - message(STATUS "Found ZLIB: ${ZLIB_LIBRARIES}") - SET(ZLIB_FIND_QUIETLY TRUE) - endif (NOT ZLIB_FIND_QUIETLY) -else (ZLIB_FOUND) - if (ZLIB_FIND_REQUIRED) - message(FATAL_ERROR "Could not find ZLIB library") - endif (ZLIB_FIND_REQUIRED) -endif (ZLIB_FOUND) - -mark_as_advanced( - ZLIB_LIBRARY - ZLIB_INCLUDE_DIR - ) - diff --git a/indra/cmake/GStreamer010Plugin.cmake b/indra/cmake/GStreamer010Plugin.cmake index 2b45a1abc..90ed35c81 100644 --- a/indra/cmake/GStreamer010Plugin.cmake +++ b/indra/cmake/GStreamer010Plugin.cmake @@ -6,11 +6,13 @@ if (STANDALONE) pkg_check_modules(GSTREAMER010 REQUIRED gstreamer-0.10) pkg_check_modules(GSTREAMER010_PLUGINS_BASE REQUIRED gstreamer-plugins-base-0.10) -elseif (LINUX) + +else (STANDALONE) + + # Possibly libxml and glib should have their own .cmake file instead... use_prebuilt_binary(glib) # gstreamer needs glib - use_prebuilt_binary(gstreamer) - # possible libxml should have its own .cmake file instead use_prebuilt_binary(libxml) + use_prebuilt_binary(gstreamer) set(GSTREAMER010_FOUND ON FORCE BOOL) set(GSTREAMER010_PLUGINS_BASE_FOUND ON FORCE BOOL) set(GSTREAMER010_INCLUDE_DIRS @@ -18,23 +20,47 @@ elseif (LINUX) ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0 ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/libxml2 ) + +endif (STANDALONE) + +if (WINDOWS) # We don't need to explicitly link against gstreamer itself, because # LLMediaImplGStreamer probes for the system's copy at runtime. - set(GSTREAMER010_LIBRARIES - gobject-2.0 - gmodule-2.0 - dl - gthread-2.0 - rt - glib-2.0 - ) -endif (STANDALONE) + set(GSTREAMER010_LIBRARIES + libgstvideo + libgstaudio + libgstbase-0.10 + libgstreamer-0.10 + gobject-2.0 + gmodule-2.0 + gthread-2.0 + glib-2.0 + ) +else (WINDOWS) + # We don't need to explicitly link against gstreamer itself, because + # LLMediaImplGStreamer probes for the system's copy at runtime. + set(GSTREAMER010_LIBRARIES + gstvideo-0.10 + gstaudio-0.10 + gstbase-0.10 + gstreamer-0.10 + gobject-2.0 + gmodule-2.0 + dl + gthread-2.0 + rt + glib-2.0 + ) + + +endif (WINDOWS) + if (GSTREAMER010_FOUND AND GSTREAMER010_PLUGINS_BASE_FOUND) set(GSTREAMER010 ON CACHE BOOL "Build with GStreamer-0.10 streaming media support.") + add_definitions(-DLL_GSTREAMER010_ENABLED=1) endif (GSTREAMER010_FOUND AND GSTREAMER010_PLUGINS_BASE_FOUND) -if (GSTREAMER010) - add_definitions(-DLL_GSTREAMER010_ENABLED=1) -endif (GSTREAMER010) + + diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index f9b1ef96f..74f2e0cb1 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -3,6 +3,7 @@ INCLUDE(APR) INCLUDE(LLMath) INCLUDE(Tut) +INCLUDE(Cwdebug) MACRO(ADD_BUILD_TEST_NO_COMMON name parent) # MESSAGE("${CMAKE_CURRENT_SOURCE_DIR}/tests/${name}_test.cpp") diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index 2862ba7f0..efb3d004c 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -6,6 +6,7 @@ include(EXPAT) include(ZLIB) set(LLCOMMON_INCLUDE_DIRS + ${LIBS_OPEN_DIR}/cwdebug ${LIBS_OPEN_DIR}/llcommon ${APR_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} diff --git a/indra/cmake/MediaPluginBase.cmake b/indra/cmake/MediaPluginBase.cmake index 2be035b64..7e2d30dfa 100644 --- a/indra/cmake/MediaPluginBase.cmake +++ b/indra/cmake/MediaPluginBase.cmake @@ -1,8 +1,6 @@ # -*- cmake -*- +include(BasicPluginBase) -set(MEDIA_PLUGIN_BASE_INCLUDE_DIRS - ${LIBS_OPEN_DIR}/media_plugins/base/ - ) - -set(MEDIA_PLUGIN_BASE_LIBRARIES media_plugin_base) +set(MEDIA_PLUGIN_BASE_INCLUDE_DIRS ${LIBS_OPEN_DIR}/plugins/base_media ${BASIC_PLUGIN_BASE_INCLUDE_DIRS}) +set(MEDIA_PLUGIN_BASE_LIBRARIES media_plugin_base ${BASIC_PLUGIN_BASE_LIBRARIES}) diff --git a/indra/cwdebug/CMakeLists.txt b/indra/cwdebug/CMakeLists.txt new file mode 100644 index 000000000..b291957e7 --- /dev/null +++ b/indra/cwdebug/CMakeLists.txt @@ -0,0 +1,33 @@ +# -*- cmake -*- + +project(cwdebug) + +include(00-Common) +include(LLCommon) +include(LLMath) +include(LLMessage) +include(LLVFS) + +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) + +set(cwdebug_SOURCE_FILES + debug.cc + ) + +set(cwdebug_HEADER_FILES + CMakeLists.txt + + cwdebug.h + sys.h + debug.h + debug_ostream_operators.h + ) + +set_source_files_properties(${cwdebug_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +add_definitions(-fPIC) + +list(APPEND cwdebug_SOURCE_FILES ${cwdebug_HEADER_FILES}) + +add_library (cwdebug ${cwdebug_SOURCE_FILES}) diff --git a/indra/cwdebug/cwdebug.h b/indra/cwdebug/cwdebug.h new file mode 100644 index 000000000..37415df3f --- /dev/null +++ b/indra/cwdebug/cwdebug.h @@ -0,0 +1,9 @@ +// We support compiling C++ source files that are not +// thread-safe, but in that case we assume that they +// will not be linked with libcwd_r. +#if !defined(_REENTRANT) || !defined(__linux__) +#undef CWDEBUG +#endif + +#include "sys.h" +#include "debug.h" diff --git a/indra/cwdebug/debug.cc b/indra/cwdebug/debug.cc new file mode 100644 index 000000000..48392beae --- /dev/null +++ b/indra/cwdebug/debug.cc @@ -0,0 +1,413 @@ +// slviewer -- Second Life Viewer Source Code +// +//! @file debug.cc +//! @brief This file contains the definitions of debug related objects and functions. +// +// Copyright (C) 2008, by +// +// Carlo Wood, Run on IRC +// RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt +// Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef USE_PCH +#include "sys.h" // Needed for platform-specific code +#endif + +#ifdef CWDEBUG + +#ifndef USE_PCH +#include // Needed for std::isprint +#include // Needed for setfill and setw +#include +#include +#include +#include +#include "debug.h" +#ifdef USE_LIBCW +#include // memleak_filter +#endif +#include +#include +#endif // USE_PCH + +#define BACKTRACE_AQUIRE_LOCK libcwd::_private_::mutex_tct::lock() +#define BACKTRACE_RELEASE_LOCK libcwd::_private_::mutex_tct::unlock() + +namespace debug { + +#if CWDEBUG_LOCATION +void BackTrace::dump_backtrace(void) const +{ + for (int frame = 0; frame < frames(); ++frame) + { + libcwd::location_ct loc((char*)buffer()[frame] + libcwd::builtin_return_address_offset); + Dout(dc::notice|continued_cf, '#' << std::left << std::setw(3) << frame << + std::left << std::setw(16) << buffer()[frame] << ' ' << loc << "\n in "); + char const* mangled_function_name = loc.mangled_function_name(); + if (mangled_function_name != libcwd::unknown_function_c) + { + std::string demangled_function_name; + libcwd::demangle_symbol(mangled_function_name, demangled_function_name); + Dout(dc::finish, demangled_function_name); + } + else + Dout(dc::finish, mangled_function_name); + } +} +#endif // CWDEBUG_LOCATION + +#if CWDEBUG_ALLOC && CWDEBUG_LOCATION +typedef std::map, libcwd::_private_::internal_allocator> backtrace_map_t; +backtrace_map_t* backtrace_map; +static int total_calls = 0; +static int number_of_stack_traces = 0; + +void my_backtrace_hook(void** buffer, int frames LIBCWD_COMMA_TSD_PARAM) +{ + ++total_calls; + + backtrace_map_t::iterator iter; + + set_alloc_checking_off(__libcwd_tsd); + { + BackTrace backtrace(buffer, frames); + std::pair res = backtrace_map->insert(backtrace_map_t::value_type(backtrace, 0)); + if (res.second) + ++number_of_stack_traces; + ++res.first->second; + iter = res.first; + } + set_alloc_checking_on(__libcwd_tsd); +#if 0 + // Dump the stack trace. + iter->first.dump_backtrace(); +#endif +} + +void start_recording_backtraces(void) +{ + BACKTRACE_AQUIRE_LOCK; + libcwd::backtrace_hook = my_backtrace_hook; + BACKTRACE_RELEASE_LOCK; + //Debug(dc::malloc.on()); + LIBCWD_TSD_DECLARATION; + set_alloc_checking_off(__libcwd_tsd); + backtrace_map = new backtrace_map_t; + set_alloc_checking_on(__libcwd_tsd); +} + +struct Compare { + bool operator()(backtrace_map_t::const_iterator const& iter1, backtrace_map_t::const_iterator const& iter2) + { + return iter1->second > iter2->second; + } +}; + +void stop_recording_backtraces(void) +{ + //Debug(dc::malloc.off()); + BACKTRACE_AQUIRE_LOCK; + libcwd::backtrace_hook = NULL; + + if (!backtrace_map) + { + Dout(dc::notice, "Not recording; call cwdebug_start() first."); + return; + } + + Dout(dc::notice, "Total number of calls: " << total_calls); + Dout(dc::notice, "Number of different stack traces: " << number_of_stack_traces); + Dout(dc::notice, "First 10 stack traces:"); + std::list entries; + for (backtrace_map_t::const_iterator iter = backtrace_map->begin(); iter != backtrace_map->end(); ++iter) + entries.push_back(iter); + entries.sort(Compare()); + int count = 0; + for (std::list::iterator iter = entries.begin(); iter != entries.end(); ++iter, ++count) + { + Dout(dc::notice, "Used: " << (*iter)->second); + // Dump the stack trace. + (*iter)->first.dump_backtrace(); + if (count == 10) + break; + } + + // Clear all data. + LIBCWD_TSD_DECLARATION; + set_alloc_checking_off(__libcwd_tsd); + delete backtrace_map; + set_alloc_checking_on(__libcwd_tsd); + backtrace_map = NULL; + total_calls = 0; + number_of_stack_traces = 0; + + BACKTRACE_RELEASE_LOCK; +} +#endif // CWDEBUG_ALLOC && CWDEBUG_LOCATION + + namespace channels { // namespace DEBUGCHANNELS + namespace dc { + +#ifndef DOXYGEN +#define DDCN(x) (x) +#endif + // Add new debug channels here. + + channel_ct viewer DDCN("VIEWER"); //!< This debug channel is used for the normal debugging out of the viewer. + channel_ct primbackup DDCN("PRIMBACKUP"); //!< This debug channel is used for output related to primbackup. + channel_ct gtk DDCN("GTK"); //!< This debug channel is used for output related to gtk. + channel_ct sdl DDCN("SDL"); //!< This debug channel is used for output related to sdl locking. + channel_ct backtrace DDCN("BACKTRACE"); //!< This debug channel is used for backtraces. + channel_ct statemachine DDCN("STATEMACHINE"); //!< This debug channel is used class AIStateMachine. + + } // namespace dc + } // namespace DEBUGCHANNELS + + // Anonymous namespace, this map and its initialization functions are private to this file + // for Thead-safeness reasons. + namespace { + + /*! @brief The type of rcfile_dc_states. + * @internal + */ + typedef std::map rcfile_dc_states_type; + + /*! @brief Map containing the default debug channel states used at the start of each new thread. + * @internal + * + * The first thread calls main, which calls debug::init which will initialize this + * map with all debug channel labels and whether or not they were turned on in the + * rcfile or not. + */ + rcfile_dc_states_type rcfile_dc_states; + + /*! @brief Set the default state of debug channel \a dc_label. + * @internal + * + * This function is called once for each debug channel. + */ + void set_state(char const* dc_label, bool is_on) + { + std::pair res = + rcfile_dc_states.insert(rcfile_dc_states_type::value_type(std::string(dc_label), is_on)); + if (!res.second) + Dout(dc::warning, "Calling set_state() more than once for the same label!"); + return; + } + + /*! @brief Save debug channel states. + * @internal + * + * One time initialization function of rcfile_dc_state. + * This must be called from debug::init after reading the rcfile. + */ + void save_dc_states(void) + { + // We may only call this function once: it reflects the states as stored + // in the rcfile and that won't change. Therefore it is not needed to + // lock `rcfile_dc_states', it is only written to by the first thread + // (once, via main -> init) when there are no other threads yet. + static bool second_time = false; + if (second_time) + { + Dout(dc::warning, "Calling save_dc_states() more than once!"); + return; + } + second_time = true; + ForAllDebugChannels( set_state(debugChannel.get_label(), debugChannel.is_on()) ); + } + + } // anonymous namespace + + /*! @brief Returns the the original state of a debug channel. + * @internal + * + * For a given \a dc_label, which must be the exact name (channel_ct::get_label) of an + * existing debug channel, this function returns \c true when the corresponding debug channel was + * on at the startup of the application, directly after reading the libcwd runtime + * configuration file (.libcwdrc). + * + * If the label/channel did not exist at the start of the application, it will return \c false + * (note that libcwd disallows adding debug channels to modules - so this would probably + * a bug). + */ + bool is_on_in_rcfile(char const* dc_label) + { + rcfile_dc_states_type::const_iterator iter = rcfile_dc_states.find(std::string(dc_label)); + if (iter == rcfile_dc_states.end()) + { + Dout(dc::warning, "is_on_in_rcfile(\"" << dc_label << "\"): \"" << dc_label << "\" is an unknown label!"); + return false; + } + return iter->second; + } + +#if LIBCWD_THREAD_SAFE + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + // I can cause I'm the maintainer of libcwd ;). + libcwd::_private_::pthread_lock_interface_ct cout_mutex(&mutex); + libcwd::_private_::lock_interface_base_ct* cout_mutex_ptr(&cout_mutex); +#endif + + /*! @brief Initialize debugging code from new threads. + * + * This function needs to be called at the start of each new thread, + * because a new thread starts in a completely reset state. + * + * The function turns on all debug channels that were turned on + * after reading the rcfile at the start of the application. + * Furthermore it initializes the debug ostream, its mutex and the + * margin of the default debug object (Dout). + */ + void init_thread(void) + { + // Turn on all debug channels that are turned on as per rcfile configuration. + ForAllDebugChannels( + if (!debugChannel.is_on() && is_on_in_rcfile(debugChannel.get_label())) + debugChannel.on(); + ); + + // Turn on debug output. + Debug( libcw_do.on() ); + static std::ofstream debug_file; + static bool debug_out_opened = false; + if (!debug_out_opened) + { + debug_out_opened = true; // Thread-safe, cause the main thread calls this first while it's still alone. + std::ostringstream os; + os << "debug.out." << getpid(); + debug_file.open(os.str().c_str()); + } + static debug::TeeStream debug_stream(std::cout, debug_file); +#if LIBCWD_THREAD_SAFE + Debug( libcw_do.set_ostream(&debug_stream, cout_mutex_ptr) ); +#else + Debug( libcw_do.set_ostream(&debug_stream) ); +#endif + + static bool first_thread = true; + if (!first_thread) // So far, the application has only one thread. So don't add a thread id. + { + // Set the thread id in the margin. + char margin[18]; + sprintf(margin, "0x%-14lx ", pthread_self()); + Debug( libcw_do.margin().assign(margin, 17) ); + } + first_thread = false; + } + + /*! @brief Initialize debugging code from main. + * + * This function initializes the debug code. + */ + void init(void) + { +#if CWDEBUG_ALLOC && defined(USE_LIBCW) + // Tell the memory leak detector which parts of the code are + // expected to leak so that we won't get an alarm for those. + { + std::vector > hide_list; + hide_list.push_back(std::pair("libdl.so.2", "_dlerror_run")); + hide_list.push_back(std::pair("libstdc++.so.6", "__cxa_get_globals")); + // The following is actually necessary because of a bug in glibc + // (see http://sources.redhat.com/bugzilla/show_bug.cgi?id=311). + hide_list.push_back(std::pair("libc.so.6", "dl_open_worker")); + memleak_filter().hide_functions_matching(hide_list); + } + { + std::vector hide_list; + // Also because of http://sources.redhat.com/bugzilla/show_bug.cgi?id=311 + hide_list.push_back(std::string("ld-linux.so.2")); + memleak_filter().hide_objectfiles_matching(hide_list); + } + memleak_filter().set_flags(libcwd::show_objectfile|libcwd::show_function); +#endif + + // The following call allocated the filebuf's of cin, cout, cerr, wcin, wcout and wcerr. + // Because this causes a memory leak being reported, make them invisible. + Debug(set_invisible_on()); + + // You want this, unless you mix streams output with C output. + // Read http://gcc.gnu.org/onlinedocs/libstdc++/27_io/howto.html#8 for an explanation. + //std::ios::sync_with_stdio(false); + + // Cancel previous call to set_invisible_on. + Debug(set_invisible_off()); + + // This will warn you when you are using header files that do not belong to the + // shared libcwd object that you linked with. + Debug( check_configuration() ); + + Debug( + libcw_do.on(); // Show which rcfile we are reading! + ForAllDebugChannels( + while (debugChannel.is_on()) + debugChannel.off() // Print as little as possible though. + ); + read_rcfile(); // Put 'silent = on' in the rcfile to suppress most of the output here. + libcw_do.off() + ); + save_dc_states(); + + init_thread(); + } + +#if CWDEBUG_LOCATION + /*! @brief Return call location. + * + * @param return_addr The return address of the call. + */ + std::string call_location(void const* return_addr) + { + libcwd::location_ct loc((char*)return_addr + libcwd::builtin_return_address_offset); + std::ostringstream convert; + convert << loc; + return convert.str(); + } + + std::vector __attribute__ ((visibility("default"))) backtraces; + pthread_mutex_t __attribute__ ((visibility("default"))) backtrace_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +} // namespace debug + +#if CWDEBUG_ALLOC +// These can be called from gdb. +void cwdebug_start() +{ + debug::start_recording_backtraces(); +} + +void cwdebug_stop() +{ + debug::stop_recording_backtraces(); +} +#endif + +#if CWDEBUG_LOCATION +void cwdebug_backtrace(int n) +{ + if (0 < n && n <= debug::backtraces.size()) + { + Dout(dc::backtrace, "Backtrace #" << n << ":"); + debug::backtraces[n - 1].dump_backtrace(); + } + else + std::cout << "No such backtrace nr. Max is " << debug::backtraces.size() << std::endl; +} +#endif + +#endif // CWDEBUG diff --git a/indra/cwdebug/debug.h b/indra/cwdebug/debug.h new file mode 100644 index 000000000..e91eab92e --- /dev/null +++ b/indra/cwdebug/debug.h @@ -0,0 +1,257 @@ +// slviewer -- Second Life Viewer Source Code +// +//! @file debug.h +//! @brief This file contains the declaration of debug related macros, objects and functions. +// +// Copyright (C) 2008, by +// +// Carlo Wood, Run on IRC +// RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt +// Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef DEBUG_H +#define DEBUG_H + +#ifndef CWDEBUG + +#ifndef DOXYGEN // No need to document this. See http://libcwd.sourceforge.net/ for more info. + +#include +#include // std::exit, EXIT_FAILURE + +#define AllocTag1(p) +#define AllocTag2(p, desc) +#define AllocTag_dynamic_description(p, x) +#define AllocTag(p, x) +#define Debug(x) +#define Dout(a, b) +#define DoutEntering(a, b) +#define DoutFatal(a, b) LibcwDoutFatal(::std, , a, b) +#define ForAllDebugChannels(STATEMENT) +#define ForAllDebugObjects(STATEMENT) +#define LibcwDebug(dc_namespace, x) +#define LibcwDout(a, b, c, d) +#define LibcwDoutFatal(a, b, c, d) do { ::std::cerr << d << ::std::endl; ::std::exit(EXIT_FAILURE); } while (1) +#define NEW(x) new x +#define CWDEBUG_ALLOC 0 +#define CWDEBUG_MAGIC 0 +#define CWDEBUG_LOCATION 0 +#define CWDEBUG_LIBBFD 0 +#define CWDEBUG_DEBUG 0 +#define CWDEBUG_DEBUGOUTPUT 0 +#define CWDEBUG_DEBUGM 0 +#define CWDEBUG_DEBUGT 0 +#define CWDEBUG_MARKER 0 + +#define BACKTRACE do { } while(0) + +#endif // !DOXYGEN + +#include +#ifdef DEBUG +#define ASSERT(x) assert(x) +#else +#define ASSERT(x) +#endif + +#else // CWDEBUG + +//! Assert \a x, if debugging is turned on. +#define ASSERT(x) LIBCWD_ASSERT(x) +#define builtin_return_address(addr) ((char*)__builtin_return_address(addr) + libcwd::builtin_return_address_offset) + +#ifndef DEBUGCHANNELS +//! @brief The namespace in which the \c dc namespace is declared. +// +// Libcwd demands that this macro is defined +// before is included and must be the name of the namespace containing +// the \c dc (Debug Channels) namespace. +// +// @sa debug::channels::dc + +#define DEBUGCHANNELS ::debug::channels +#endif +#include +#include +#if CWDEBUG_LOCATION +#include // Needed for 'backtrace'. +#endif + +#define CWD_API __attribute__ ((visibility("default"))) + +//! Debug specific code. +namespace debug { + +void CWD_API init(void); // Initialize debugging code, called once from main. +void CWD_API init_thread(void); // Initialize debugging code, called once for each thread. + +//! @brief Debug Channels (dc) namespace. +// +// @sa debug::channels::dc +namespace channels { // namespace DEBUGCHANNELS + +//! The namespace containing the actual debug channels. +namespace dc { +using namespace libcwd::channels::dc; +using libcwd::channel_ct; + +#ifndef DOXYGEN // Doxygen bug causes a warning here. +// Add the declaration of new debug channels here +// and add their definition in a custom debug.cc file. +extern CWD_API channel_ct viewer; // The normal logging output of the viewer (normally to stderr). +extern CWD_API channel_ct primbackup; +extern CWD_API channel_ct gtk; +extern CWD_API channel_ct sdl; +extern CWD_API channel_ct backtrace; +extern CWD_API channel_ct statemachine; + +#endif + +} // namespace dc +} // namespace DEBUGCHANNELS + +#if CWDEBUG_LOCATION +std::string call_location(void const* return_addr); +#endif + +//! @brief Interface for marking scopes of invisible memory allocations. +// +// Creation of the object does nothing, you have to explicitly call +// InvisibleAllocations::on. Destruction of the object automatically +// cancels any call to \c on of this object. This makes it exception- +// (stack unwinding) and recursive-safe. +struct InvisibleAllocations { + int M_on; //!< The number of times that InvisibleAllocations::on() was called. + //! Constructor. + InvisibleAllocations() : M_on(0) { } + //! Destructor. + ~InvisibleAllocations() { while (M_on > 0) off(); } + //! Set invisible allocations on. Can be called recursively. + void on(void) { libcwd::set_invisible_on(); ++M_on; } + //! Cancel one call to on(). + void off(void) { assert(M_on > 0); --M_on; libcwd::set_invisible_off(); } +}; + +//! @brief Interface for marking scopes with indented debug output. +// +// Creation of the object increments the debug indentation. Destruction +// of the object automatically decrements the indentation again. +struct Indent { + int M_indent; //!< The extra number of spaces that were added to the indentation. + //! Construct an Indent object. + Indent(int indent) : M_indent(indent) { if (M_indent > 0) libcwd::libcw_do.inc_indent(M_indent); } + //! Destructor. + ~Indent() { if (M_indent > 0) libcwd::libcw_do.dec_indent(M_indent); } +}; + +// A class streambuf that splits what is written to two streambufs. +class TeeBuf : public std::streambuf { + private: + std::streambuf* M_sb1; + std::streambuf* M_sb2; + + public: + TeeBuf(std::streambuf* sb1, std::streambuf* sb2) : M_sb1(sb1), M_sb2(sb2) { } + + protected: + virtual int sync(void) { M_sb2->pubsync(); return M_sb1->pubsync(); } + virtual std::streamsize xsputn(char_type const* p, std::streamsize n) { M_sb2->sputn(p, n); return M_sb1->sputn(p, n); } + virtual int_type overflow(int_type c = traits_type::eof()) { M_sb2->sputc(c); return M_sb1->sputc(c); } +}; + +// An ostream that passes what is written to it on to two other ostreams. +class TeeStream : public std::ostream { + private: + TeeBuf M_teebuf; + public: + TeeStream(std::ostream& os1, std::ostream& os2) : std::ostream(&M_teebuf), M_teebuf(os1.rdbuf(), os2.rdbuf()) { } +}; + +#if CWDEBUG_LOCATION +class BackTrace { + private: + boost::shared_array M_buffer; + int M_frames; + public: + BackTrace(void** buffer, int frames) : M_buffer(new void* [frames]), M_frames(frames) { std::memcpy(M_buffer.get(), buffer, sizeof(void*) * frames); } + + friend bool operator<(BackTrace const& bt1, BackTrace const& bt2) + { + if (bt1.M_frames != bt2.M_frames) + return bt1.M_frames < bt2.M_frames; + for (int frame = 0; frame < bt1.M_frames; ++frame) + if (bt1.M_buffer[frame] < bt2.M_buffer[frame]) + return true; + else if (bt1.M_buffer[frame] > bt2.M_buffer[frame]) + return true; + return false; + } + + void dump_backtrace(void) const; + + int frames(void) const { return M_frames; } + boost::shared_array const& buffer(void) const { return M_buffer; } +}; +extern std::vector backtraces; +extern pthread_mutex_t backtrace_mutex; +#define BACKTRACE do { \ + using namespace debug; \ + void* buffer[32]; \ + int frames = backtrace(buffer, 32); \ + size_t size; \ + { \ + pthread_mutex_lock(&backtrace_mutex); \ + backtraces.push_back(BackTrace(buffer, frames)); \ + size = backtraces.size(); \ + pthread_mutex_unlock(&backtrace_mutex); \ + } \ + Dout(dc::backtrace, "Stored backtrace #" << size); \ + } while(0) +#else +#define BACKTRACE do { } while(0) +#endif // CWDEBUG_LOCATION + +} // namespace debug + +//! Debugging macro. +// +// Print "Entering " << \a data to channel \a cntrl and increment +// debugging output indentation until the end of the current scope. +#define DoutEntering(cntrl, data) \ + int __slviewer_debug_indentation = 2; \ + { \ + LIBCWD_TSD_DECLARATION; \ + if (LIBCWD_DO_TSD_MEMBER_OFF(::libcwd::libcw_do) < 0) \ + { \ + ::libcwd::channel_set_bootstrap_st __libcwd_channel_set(LIBCWD_DO_TSD(::libcwd::libcw_do) LIBCWD_COMMA_TSD); \ + bool on; \ + { \ + using namespace LIBCWD_DEBUGCHANNELS; \ + on = (__libcwd_channel_set|cntrl).on; \ + } \ + if (on) \ + Dout(cntrl, "Entering " << data); \ + else \ + __slviewer_debug_indentation = 0; \ + } \ + } \ + debug::Indent __slviewer_debug_indent(__slviewer_debug_indentation); + +#endif // CWDEBUG + +#include "debug_ostream_operators.h" + +#endif // DEBUG_H diff --git a/indra/cwdebug/debug_ostream_operators.h b/indra/cwdebug/debug_ostream_operators.h new file mode 100644 index 000000000..4459e9fab --- /dev/null +++ b/indra/cwdebug/debug_ostream_operators.h @@ -0,0 +1 @@ +// Empty so far... diff --git a/indra/cwdebug/sys.h b/indra/cwdebug/sys.h new file mode 100644 index 000000000..c18df1701 --- /dev/null +++ b/indra/cwdebug/sys.h @@ -0,0 +1,9 @@ +// The following is the libcwd related mandatory part. +// It must be included before any system header file is included. +#ifdef CWDEBUG +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#endif + diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 29fa35619..e88c404eb 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -2,6 +2,7 @@ project(llcommon) +include(Cwdebug) include(00-Common) include(LLCommon) include(Linking) @@ -214,8 +215,14 @@ target_link_libraries( ${EXPAT_LIBRARIES} ${ZLIB_LIBRARIES} ${WINDOWS_LIBRARIES} + ${CWDEBUG_LIBRARIES} ) +if (LINUX) + # When linking with llcommon later, we do not want to link with cwdebug.a again. + set_property(TARGET llcommon PROPERTY LINK_INTERFACE_LIBRARIES "-lapr-1 -laprutil-1 -lz") +endif (LINUX) + if (DARWIN) # Don't embed a full path in the library's install name set_target_properties( diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h index 6e66e9916..d486359c7 100644 --- a/indra/llcommon/linden_common.h +++ b/indra/llcommon/linden_common.h @@ -33,6 +33,8 @@ #ifndef LL_LINDEN_COMMON_H #define LL_LINDEN_COMMON_H +#include "cwdebug.h" + #if defined(LL_WINDOWS) && defined(_DEBUG) # if _MSC_VER >= 1400 // Visual C++ 2005 or later # define _CRTDBG_MAP_ALLOC diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index a769e165c..9912ecba2 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -195,4 +195,9 @@ private: static const char* mAssetTypeHumanNames[]; }; +#ifdef CWDEBUG +#include +inline std::ostream& operator<<(std::ostream& os, LLAssetType::EType type) { return os << LLAssetType::getDesc(type); } +#endif + #endif // LL_LLASSETTYPE diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 4cdfe097d..73ec354bc 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -46,6 +46,7 @@ # include #endif // !LL_WINDOWS #include +#include #include "llapp.h" #include "llapr.h" @@ -162,7 +163,15 @@ namespace { break; } } +#ifdef CWDEBUG + // Include normal logging in libcwd's message processing. + // This takes care of prefixing with thread ID's, locking + // and allows us to (temporarily) turn off normal logging + // output. + Dout(dc::viewer, message); +#else fprintf(stderr, "%s\n", message.c_str()); +#endif #if LL_WINDOWS fflush(stderr); //Now using a buffer. flush is required. #endif @@ -1068,28 +1077,49 @@ namespace LLError switch (site.mLevel) { - case LEVEL_DEBUG: prefix << "DEBUG: "; break; - case LEVEL_INFO: prefix << "INFO: "; break; - case LEVEL_WARN: prefix << "WARNING: "; break; - case LEVEL_ERROR: prefix << "ERROR: "; break; - default: prefix << "XXX: "; break; + case LEVEL_DEBUG: prefix << "DEBUG"; break; + case LEVEL_INFO: prefix << "INFO"; break; + case LEVEL_WARN: prefix << "WARNING"; break; + case LEVEL_ERROR: prefix << "ERROR"; break; + default: prefix << "XXX"; break; }; - - if (settings_w->printLocation) + + bool need_function = true; + if (site.mBroadTag && *site.mBroadTag != '\0') { - prefix << abbreviateFile(site.mFile) - << "(" << site.mLine << ") : "; + prefix << "(\"" << site.mBroadTag << "\")"; +#if LL_DEBUG + // Suppress printing mFunction if mBroadTag is set, starts with + // "Plugin " and ends with "child": a debug message from a plugin. + size_t taglen = strlen(site.mBroadTag); + if (taglen >= 12 && strncmp(site.mBroadTag, "Plugin ", 7) == 0 && + strcmp(site.mBroadTag + taglen - 5, "child") == 0) + { + need_function = false; + } +#endif } + + prefix << ": "; - #if LL_WINDOWS - // DevStudio: __FUNCTION__ already includes the full class name - #else - if (site.mClassInfo != typeid(NoClassInfo)) + if (need_function) { - prefix << className(site.mClassInfo) << "::"; + if (settings_w->printLocation) + { + prefix << abbreviateFile(site.mFile) + << "(" << site.mLine << ") : "; + } + +#if LL_WINDOWS + // DevStudio: __FUNCTION__ already includes the full class name +#else + if (need_function && site.mClassInfo != typeid(NoClassInfo)) + { + prefix << className(site.mClassInfo) << "::"; + } +#endif + prefix << site.mFunction << ": "; } - #endif - prefix << site.mFunction << ": "; if (site.mPrintOnce) { @@ -1218,6 +1248,8 @@ namespace LLError #endif void crashAndLoop(const std::string& message) { + DoutFatal(dc::core, message); + // Now, we go kaboom! int* make_me_crash = NULL; diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 898ed496b..726274c23 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -177,6 +177,7 @@ public: FTM_REFRESH, FTM_SORT, FTM_PICK, + FTM_STATEMACHINE, // Temp FTM_TEMP1, diff --git a/indra/llcommon/llindraconfigfile.h b/indra/llcommon/llindraconfigfile.h index 661f79bd6..17eda906e 100644 --- a/indra/llcommon/llindraconfigfile.h +++ b/indra/llcommon/llindraconfigfile.h @@ -33,8 +33,8 @@ #ifndef LL_LLINDRACONFIGFILE_H #define LL_LLINDRACONFIGFILE_H -#include #include "linden_common.h" +#include #include "lllivefile.h" #include "llsd.h" diff --git a/indra/llcommon/llprocesslauncher.cpp b/indra/llcommon/llprocesslauncher.cpp index e27aaa3c5..ee120fc94 100644 --- a/indra/llcommon/llprocesslauncher.cpp +++ b/indra/llcommon/llprocesslauncher.cpp @@ -32,7 +32,11 @@ #include "linden_common.h" +#include +#include +#include #include "llprocesslauncher.h" +#include "aiaprpool.h" #include #if LL_DARWIN || LL_LINUX @@ -142,6 +146,7 @@ bool LLProcessLauncher::isRunning(void) return (mProcessHandle != 0); } + bool LLProcessLauncher::kill(void) { bool result = true; @@ -201,6 +206,79 @@ static bool reap_pid(pid_t pid) return result; } +#if LL_DEBUG +// Define this to create a temporary pipe(2) between parent and child process, so +// that the child process can report error messages that it encounters when +// trying to execve(2). Most notably failing to start due to missing libraries +// or undefined symbols. +#define DEBUG_PIPE_CHILD_ERROR_REPORTING 1 +#endif + +#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING + +// Called by child process. +static void write_pipe(apr_file_t* out, char const* message) +{ + apr_size_t const bytes_to_write = strlen(message) + 1; // +1 for the length byte. + assert(bytes_to_write < 256); + char buf[256]; + strncpy(buf + 1, message, sizeof(buf) - 1); + *reinterpret_cast(buf) = bytes_to_write - 1; + + apr_size_t bytes_written; + apr_status_t status = apr_file_write_full(out, buf, bytes_to_write, &bytes_written); + if (status != APR_SUCCESS) + { + std::cerr << "apr_file_write_full: " << apr_strerror(status, buf, sizeof(buf)) << std::endl; + } + else if (bytes_written != bytes_to_write) + { + std::cerr << "apr_file_write_full: bytes_written (" << bytes_written << ") != bytes_to_write (" << bytes_to_write << ")!" << std::endl; + } + status = apr_file_flush(out); + if (status != APR_SUCCESS) + { + std::cerr << "apr_file_flush: " << apr_strerror(status, buf, sizeof(buf)) << std::endl; + } + +#ifdef _DEBUG + std::cerr << "apr_file_write_full: Wrote " << bytes_written << " bytes to the pipe." << std::endl; +#endif +} + +// Called by parent process. +static std::string read_pipe(apr_file_t* in, bool timeout_ok = false) +{ + char buf[256]; + unsigned char bytes_to_read; + apr_size_t bytes_read; + apr_status_t status = apr_file_read_full(in, &bytes_to_read, 1, &bytes_read); + if (status != APR_SUCCESS) + { + if (APR_STATUS_IS_TIMEUP(status) && timeout_ok) + { + return "TIMEOUT"; + } + llwarns << "apr_file_read_full: " << apr_strerror(status, buf, sizeof(buf)) << llendl; + assert(APR_STATUS_IS_EOF(status)); + return "END OF FILE"; + } + assert(bytes_read == 1); + status = apr_file_read_full(in, buf, bytes_to_read, &bytes_read); + if (status != APR_SUCCESS) + { + llwarns << "apr_file_read_full: " << apr_strerror(status, buf, sizeof(buf)) << llendl; + assert(status == APR_SUCCESS); // Fail + } + assert(bytes_read == bytes_to_read); + + std::string received(buf, bytes_read); + llinfos << "Received: \"" << received << "\" (bytes read: " << bytes_read << ")" << llendl; + return received; +} + +#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING + int LLProcessLauncher::launch(void) { // If there was already a process associated with this object, kill it. @@ -237,23 +315,96 @@ int LLProcessLauncher::launch(void) } } - // flush all buffers before the child inherits them - ::fflush(NULL); - - pid_t id = vfork(); - if(id == 0) + pid_t id; { - // child process - - ::execv(mExecutable.c_str(), (char * const *)fake_argv); - - // If we reach this point, the exec failed. - // Use _exit() instead of exit() per the vfork man page. - _exit(0); +#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING + // Set up a pipe to the child process for error reporting. + apr_file_t* in; + apr_file_t* out; + AIAPRPool pool; + pool.create(); + apr_status_t status = apr_file_pipe_create_ex(&in, &out, APR_FULL_BLOCK, pool()); + assert(status == APR_SUCCESS); + bool success = (status == APR_SUCCESS); + if (success) + { + apr_interval_time_t const timeout = 10000000; // 10 seconds. + status = apr_file_pipe_timeout_set(in, timeout); + assert(status == APR_SUCCESS); + success = (status == APR_SUCCESS); + } +#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING + + // flush all buffers before the child inherits them + ::fflush(NULL); + + id = vfork(); + if (id == 0) + { + // child process + +#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING + // Tell parent process we're about to call execv. + write_pipe(out, "CALLING EXECV"); +#ifdef _DEBUG + char const* display = getenv("DISPLAY"); + std::cerr << "Calling ::execv(\"" << mExecutable << '"'; + for(int j = 0; j < i; ++j) + std::cerr << ", \"" << fake_argv[j] << '"'; + std::cerr << ") with DISPLAY=\"" << (display ? display : "NULL") << '"' << std::endl; +#endif +#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING + + ::execv(mExecutable.c_str(), (char * const *)fake_argv); + +#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING + status = APR_FROM_OS_ERROR(apr_get_os_error()); + char message[256]; + char errbuf[128]; + apr_strerror(status, errbuf, sizeof(errbuf)); + snprintf(message, sizeof(message), "Child process: execv: %s: %s", mExecutable.c_str(), errbuf); + write_pipe(out, message); +#ifdef _DEBUG + std::cerr << "::execv() failed." << std::endl; +#endif +#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING + + // If we reach this point, the exec failed. + // Use _exit() instead of exit() per the vfork man page. + _exit(0); + } + + // parent process + +#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING + // Close unused pipe end. + apr_file_close(out); + + if (success) + { + // Attempt to do error reporting. + std::string message = read_pipe(in); + success = (message == "CALLING EXECV"); + assert(success); + if (success) + { + status = apr_file_pipe_timeout_set(in, 2000000); // Only wait 2 seconds. + message = read_pipe(in, true); + if (message != "TIMEOUT" && message != "END OF FILE") + { + // Most likely execv failed. + llwarns << message << llendl; + assert(false); // Fail in debug mode. + } + } + } + + // Clean up. + apr_file_close(in); +#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING + } - // parent process - if(current_wd >= 0) { // restore the previous working directory diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 788617953..18842f276 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -39,6 +39,7 @@ #include #include #include +#include "stdtypes.h" // llcommon/stdtypes.h, needed for S32 and U32. // Use to compare the first element only of a pair // e.g. typedef std::set, compare_pair > some_pair_set_t; diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 7ced30939..8bd341457 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -67,6 +67,10 @@ // void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap) { +#ifdef CWDEBUG + debug::init_thread(); +#endif + LLThread *threadp = (LLThread *)datap; // Set thread state to running diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 3dc41e897..f955ccdfd 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -29,13 +29,15 @@ * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ + +#include "linden_common.h" + #include #include #include #include #include "llcrashlogger.h" -#include "linden_common.h" #include "llstring.h" #include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME #include "llerror.h" diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h index f8abe2059..72c1f3fb8 100644 --- a/indra/llcrashlogger/llcrashlogger.h +++ b/indra/llcrashlogger/llcrashlogger.h @@ -32,10 +32,10 @@ #ifndef LLCRASHLOGGER_H #define LLCRASHLOGGER_H -#include - #include "linden_common.h" +#include + #include "llapp.h" #include "llsd.h" #include "llcontrol.h" diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp index cc44696a4..2bca81434 100644 --- a/indra/llimage/tests/llimageworker_test.cpp +++ b/indra/llimage/tests/llimageworker_test.cpp @@ -32,6 +32,7 @@ */ // Precompiled header: almost always required for newview cpp files +#include "../llcommon/linden_common.h" #include #include #include diff --git a/indra/llinventory/llsaleinfo.cpp b/indra/llinventory/llsaleinfo.cpp index b7afb28ad..e51e35e6e 100644 --- a/indra/llinventory/llsaleinfo.cpp +++ b/indra/llinventory/llsaleinfo.cpp @@ -30,8 +30,8 @@ * $/LicenseInfo$ */ -#include #include "linden_common.h" +#include #include "llsaleinfo.h" diff --git a/indra/llmessage/llnetcanary.cpp b/indra/llmessage/llnetcanary.cpp index a714c60f2..57ee6d3a6 100644 --- a/indra/llmessage/llnetcanary.cpp +++ b/indra/llmessage/llnetcanary.cpp @@ -1,6 +1,6 @@ // -#include "llnetcanary.h" #include "linden_common.h" +#include "llnetcanary.h" #include "llerror.h" #ifdef _MSC_VER #include diff --git a/indra/llmessage/llsocks5.cpp b/indra/llmessage/llsocks5.cpp index 7326e806b..d21412f86 100644 --- a/indra/llmessage/llsocks5.cpp +++ b/indra/llmessage/llsocks5.cpp @@ -30,13 +30,12 @@ * $/LicenseInfo$ */ -#include - #include "linden_common.h" #include "net.h" #include "llhost.h" #include "message.h" #include "llsocks5.h" +#include // Static class variable instances diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt index 63a7ad75b..4b5420b6b 100644 --- a/indra/llplugin/CMakeLists.txt +++ b/indra/llplugin/CMakeLists.txt @@ -24,6 +24,7 @@ include_directories( ) set(llplugin_SOURCE_FILES + llpluginclassbasic.cpp llpluginclassmedia.cpp llplugincookiestore.cpp llplugininstance.cpp @@ -37,6 +38,7 @@ set(llplugin_SOURCE_FILES set(llplugin_HEADER_FILES CMakeLists.txt + llpluginclassbasic.h llpluginclassmedia.h llpluginclassmediaowner.h llplugincookiestore.h diff --git a/indra/llplugin/llpluginclassbasic.cpp b/indra/llplugin/llpluginclassbasic.cpp new file mode 100644 index 000000000..0567b157f --- /dev/null +++ b/indra/llplugin/llpluginclassbasic.cpp @@ -0,0 +1,189 @@ +/** + * @file llpluginclassbasic.cpp + * @brief LLPluginClassBasic handles a plugin which knows about the "basic" message class. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#include "linden_common.h" +#include "indra_constants.h" + +#include "llpluginclassbasic.h" +#include "llpluginmessageclasses.h" + +LLPluginClassBasic::LLPluginClassBasic(void) : mPlugin(NULL), mDeleteOK(true) +{ + // Note that this only initializes the base class, the derived class doesn't exist yet! + // Derived classes must therefore call their own reset_impl() from their constructor. + reset(); +} + +LLPluginClassBasic::~LLPluginClassBasic() +{ + llassert_always(mDeleteOK); + delete mPlugin; +} + +bool LLPluginClassBasic::init(std::string const& launcher_filename, std::string const& plugin_filename, bool debug) +{ + LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; + LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; + + mPlugin = new LLPluginProcessParent(this); + mPlugin->setSleepTime(mSleepTime); + + mPlugin->init(launcher_filename, plugin_filename, debug); + + return init_impl(); +} + +void LLPluginClassBasic::reset() +{ + if (mPlugin != NULL) + { + delete mPlugin; + mPlugin = NULL; + } + mSleepTime = 1.0f / 50.0f; + mPriority = PRIORITY_NORMAL; + reset_impl(); +} + +void LLPluginClassBasic::idle(void) +{ + if(mPlugin) + { + mPlugin->idle(); + } + + idle_impl(); + + if(mPlugin && mPlugin->isRunning()) + { + // Send queued messages + while(!mSendQueue.empty()) + { + LLPluginMessage message = mSendQueue.front(); + mSendQueue.pop(); + mPlugin->sendMessage(message); + } + } +} + +char const* LLPluginClassBasic::priorityToString(EPriority priority) +{ + const char* result = "UNKNOWN"; + switch(priority) + { + case PRIORITY_SLEEP: result = "sleep"; break; + case PRIORITY_LOW: result = "low"; break; + case PRIORITY_NORMAL: result = "normal"; break; + case PRIORITY_HIGH: result = "high"; break; + } + + return result; +} + +void LLPluginClassBasic::setPriority(EPriority priority) +{ + if (mPriority != priority) + { + mPriority = priority; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_BASIC, "set_priority"); + + std::string priority_string = priorityToString(priority); + switch(priority) + { + case PRIORITY_SLEEP: + mSleepTime = 1.0f; + break; + case PRIORITY_LOW: + mSleepTime = 1.0f / 25.0f; + break; + case PRIORITY_NORMAL: + mSleepTime = 1.0f / 50.0f; + break; + case PRIORITY_HIGH: + mSleepTime = 1.0f / 100.0f; + break; + } + + message.setValue("priority", priority_string); + sendMessage(message); + + if(mPlugin) + { + mPlugin->setSleepTime(mSleepTime); + } + + LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; + + priorityChanged(mPriority); + } +} + +/* virtual */ +void LLPluginClassBasic::receivePluginMessage(const LLPluginMessage &message) +{ + std::string message_class = message.getClass(); + + if (message_class == LLPLUGIN_MESSAGE_CLASS_BASIC) + { + std::string message_name = message.getName(); + + // This class hasn't defined any incoming messages yet. +// if (message_name == "message_name") +// { +// } +// else + { + LL_WARNS("Plugin") << "Unknown " << message_class << " class message: " << message_name << LL_ENDL; + } + } +} + +// This is the viewer process (the parent process) +// +// Call this function to send a message to a plugin. +// It calls LLPluginProcessParent::sendMessage. +void LLPluginClassBasic::sendMessage(LLPluginMessage const& message) +{ + if(mPlugin && mPlugin->isRunning()) + { + mPlugin->sendMessage(message); + } + else + { + // The plugin isn't set up yet -- queue this message to be sent after initialization. + mSendQueue.push(message); + } +} diff --git a/indra/llplugin/llpluginclassbasic.h b/indra/llplugin/llpluginclassbasic.h new file mode 100644 index 000000000..6c0602608 --- /dev/null +++ b/indra/llplugin/llpluginclassbasic.h @@ -0,0 +1,129 @@ +/** + * @file llpluginclassbasic.h + * @brief LLPluginClassBasic handles interaction with a plugin which knows about the "basic" message class. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * + * @endcond + */ + +#ifndef LL_LLPLUGINCLASSBASIC_H +#define LL_LLPLUGINCLASSBASIC_H + +#include "llerror.h" // Needed for LOG_CLASS +#include "stdtypes.h" // Needed for F64 +#include "llpluginprocessparent.h" +#include "llpluginclassmediaowner.h" +#include "llpluginmessage.h" +#include +#include + +class LLPluginClassBasic : public LLPluginProcessParentOwner +{ + LOG_CLASS(LLPluginClassBasic); + +public: + LLPluginClassBasic(void); + virtual ~LLPluginClassBasic(); + + // Local initialization, called when creating a plugin process. Return true if successful. + bool init(std::string const& launcher_filename, std::string const& plugin_filename, bool debug); + + // Undoes everything init did. Called when destroying a plugin process. + void reset(void); + + void idle(void); + + // Send message to the plugin, either queueing or sending directly. + void sendMessage(LLPluginMessage const& message); + + // "Loading" means uninitialized or any state prior to fully running (processing commands). + bool isPluginLoading(void) const { return mPlugin ? mPlugin->isLoading() : false; } + + // "Running" means the steady state -- i.e. processing messages. + bool isPluginRunning(void) const { return mPlugin ? mPlugin->isRunning() : false; } + + // "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally). + bool isPluginExited(void) const { return mPlugin ? mPlugin->isDone() : false; } + + std::string getPluginVersion() const { return mPlugin ? mPlugin->getPluginVersion() : std::string(""); } + + bool getDisableTimeout() const { return mPlugin ? mPlugin->getDisableTimeout() : false; } + + void setDisableTimeout(bool disable) { if (mPlugin) mPlugin->setDisableTimeout(disable); } + + enum EPriority + { + PRIORITY_SLEEP, // Sleep 1 second every message. + PRIORITY_LOW, // Sleep 1/25 second. + PRIORITY_NORMAL, // Sleep 1/50 second. + PRIORITY_HIGH // Sleep 1/100 second. + }; + + static char const* priorityToString(EPriority priority); + void setPriority(EPriority priority); + +protected: + EPriority mPriority; + LLPluginProcessParent* mPlugin; + +private: + F64 mSleepTime; + std::queue mSendQueue; // Used to queue messages while the plugin initializes. + +protected: + // Called as last function when calling 'init()'. + virtual bool init_impl(void) { return true; } + + // Called as last function when calling 'reset()'. + virtual void reset_impl(void) { } + + // Called from idle() before flushing messages to the plugin. + virtual void idle_impl(void) { } + + // Called from setPriority. + virtual void priorityChanged(EPriority priority) { } + + // Inherited from LLPluginProcessParentOwner. + /*virtual*/ void receivePluginMessage(LLPluginMessage const&); + + // Inherited from LLPluginProcessParentOwner. + /*virtual*/ void receivedShutdown() { mPlugin->exitState(); } + + //-------------------------------------- + // Debug use only + // +private: + bool mDeleteOK; + +public: + void setDeleteOK(bool flag) { mDeleteOK = flag; } +}; + +#endif // LL_LLPLUGINCLASSBASIC_H diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 85241bec1..c8b903e58 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -54,49 +54,24 @@ static int nextPowerOf2( int value ) return next_power_of_2; } -LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner) +LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner): mOwner(owner) { - mOwner = owner; - mPlugin = NULL; - reset(); - - //debug use - mDeleteOK = true ; + // Most initialization is done with reset_impl(), which we call here + // in order to avoid code duplication. + LLPluginClassMedia::reset_impl(); } - -LLPluginClassMedia::~LLPluginClassMedia() +bool LLPluginClassMedia::init_impl(void) { - llassert_always(mDeleteOK) ; - reset(); -} - -bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug) -{ - LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; - LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; - - mPlugin = new LLPluginProcessParent(this); - mPlugin->setSleepTime(mSleepTime); - // Queue up the media init message -- it will be sent after all the currently queued messages. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init"); sendMessage(message); - - mPlugin->init(launcher_filename, plugin_filename, debug); return true; } - -void LLPluginClassMedia::reset() +void LLPluginClassMedia::reset_impl(void) { - if(mPlugin != NULL) - { - delete mPlugin; - mPlugin = NULL; - } - mTextureParamsReceived = false; mRequestedTextureDepth = 0; mRequestedTextureInternalFormat = 0; @@ -125,14 +100,12 @@ void LLPluginClassMedia::reset() mDirtyRect = LLRect::null; mAutoScaleMedia = false; mRequestedVolume = 1.0f; - mPriority = PRIORITY_NORMAL; mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; mAllowDownsample = false; mPadding = 0; mLastMouseX = 0; mLastMouseY = 0; mStatus = LLPluginClassMediaOwner::MEDIA_NONE; - mSleepTime = 1.0f / 100.0f; mCanCut = false; mCanCopy = false; mCanPaste = false; @@ -158,13 +131,8 @@ void LLPluginClassMedia::reset() mLoadedDuration = 0.0f; } -void LLPluginClassMedia::idle(void) +void LLPluginClassMedia::idle_impl(void) { - if(mPlugin) - { - mPlugin->idle(); - } - if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked())) { // Can't process a size change at this time @@ -260,17 +228,6 @@ void LLPluginClassMedia::idle(void) LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL; } } - - if(mPlugin && mPlugin->isRunning()) - { - // Send queued messages - while(!mSendQueue.empty()) - { - LLPluginMessage message = mSendQueue.front(); - mSendQueue.pop(); - mPlugin->sendMessage(message); - } - } } int LLPluginClassMedia::getTextureWidth() const @@ -295,18 +252,16 @@ unsigned char* LLPluginClassMedia::getBitsData() void LLPluginClassMedia::setSize(int width, int height) { - if((width > 0) && (height > 0)) + if (width <= 0 || height <= 0) + { + width = height = -1; + } + if (mSetMediaWidth != width || mSetMediaHeight != height) { mSetMediaWidth = width; mSetMediaHeight = height; + setSizeInternal(); } - else - { - mSetMediaWidth = -1; - mSetMediaHeight = -1; - } - - setSizeInternal(); } void LLPluginClassMedia::setSizeInternal(void) @@ -335,7 +290,7 @@ void LLPluginClassMedia::setSizeInternal(void) { switch(mPriority) { - case PRIORITY_SLIDESHOW: + case PRIORITY_SLEEP: case PRIORITY_LOW: // Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) @@ -584,71 +539,10 @@ void LLPluginClassMedia::loadURI(const std::string &uri) sendMessage(message); } -const char* LLPluginClassMedia::priorityToString(EPriority priority) +void LLPluginClassMedia::priorityChanged(EPriority priority) { - const char* result = "UNKNOWN"; - switch(priority) - { - case PRIORITY_UNLOADED: result = "unloaded"; break; - case PRIORITY_STOPPED: result = "stopped"; break; - case PRIORITY_HIDDEN: result = "hidden"; break; - case PRIORITY_SLIDESHOW: result = "slideshow"; break; - case PRIORITY_LOW: result = "low"; break; - case PRIORITY_NORMAL: result = "normal"; break; - case PRIORITY_HIGH: result = "high"; break; - } - - return result; -} - -void LLPluginClassMedia::setPriority(EPriority priority) -{ - if(mPriority != priority) - { - mPriority = priority; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); - - std::string priority_string = priorityToString(priority); - switch(priority) - { - case PRIORITY_UNLOADED: - mSleepTime = 1.0f; - break; - case PRIORITY_STOPPED: - mSleepTime = 1.0f; - break; - case PRIORITY_HIDDEN: - mSleepTime = 1.0f; - break; - case PRIORITY_SLIDESHOW: - mSleepTime = 1.0f; - break; - case PRIORITY_LOW: - mSleepTime = 1.0f / 25.0f; - break; - case PRIORITY_NORMAL: - mSleepTime = 1.0f / 50.0f; - break; - case PRIORITY_HIGH: - mSleepTime = 1.0f / 100.0f; - break; - } - - message.setValue("priority", priority_string); - - sendMessage(message); - - if(mPlugin) - { - mPlugin->setSleepTime(mSleepTime); - } - - LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; - - // This may affect the calculated size, so recalculate it here. - setSizeInternal(); - } + // This may affect the calculated size, so recalculate it here. + setSizeInternal(); } void LLPluginClassMedia::setLowPrioritySizeLimit(int size) @@ -657,7 +551,6 @@ void LLPluginClassMedia::setLowPrioritySizeLimit(int size) if(mLowPrioritySizeLimit != power) { mLowPrioritySizeLimit = power; - // This may affect the calculated size, so recalculate it here. setSizeInternal(); } @@ -726,7 +619,11 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) { std::string message_class = message.getClass(); - if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + if (message_class == LLPLUGIN_MESSAGE_CLASS_BASIC) + { + LLPluginClassBasic::receivePluginMessage(message); + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) { std::string message_name = message.getName(); if(message_name == "texture_params") @@ -777,7 +674,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mDirtyRect.unionWith(newDirtyRect); } - LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" + LL_DEBUGS("PluginUpdated") << "adjusted incoming rect is: (" << newDirtyRect.mLeft << ", " << newDirtyRect.mTop << ", " << newDirtyRect.mRight << ", " @@ -1003,10 +900,9 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) // } // else { - LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + LL_WARNS("Plugin") << "Unknown " << message_class << " class message: " << message_name << LL_ENDL; } } - } /* virtual */ @@ -1029,19 +925,6 @@ void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event) } } -void LLPluginClassMedia::sendMessage(const LLPluginMessage &message) -{ - if(mPlugin && mPlugin->isRunning()) - { - mPlugin->sendMessage(message); - } - else - { - // The plugin isn't set up yet -- queue this message to be sent after initialization. - mSendQueue.push(message); - } -} - //////////////////////////////////////////////////////////// // MARK: media_browser class functions bool LLPluginClassMedia::pluginSupportsMediaBrowser(void) diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 0004971c6..2882de180 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -36,29 +36,16 @@ #ifndef LL_LLPLUGINCLASSMEDIA_H #define LL_LLPLUGINCLASSMEDIA_H -#include "llgltypes.h" -#include "llpluginprocessparent.h" +#include "llpluginclassbasic.h" #include "llrect.h" -#include "llpluginclassmediaowner.h" -#include #include "v4color.h" -class LLPluginClassMedia : public LLPluginProcessParentOwner +class LLPluginClassMedia : public LLPluginClassBasic { LOG_CLASS(LLPluginClassMedia); + public: LLPluginClassMedia(LLPluginClassMediaOwner *owner); - virtual ~LLPluginClassMedia(); - - // local initialization, called by the media manager when creating a source - virtual bool init(const std::string &launcher_filename, - const std::string &plugin_filename, - bool debug); - - // undoes everything init() didm called by the media manager when destroying a source - virtual void reset(); - - void idle(void); // All of these may return 0 or an actual valid value. // Callers need to check the return for 0, and not use the values in that case. @@ -101,22 +88,22 @@ public: bool getDirty(LLRect *dirty_rect = NULL); void resetDirty(void); - typedef enum + enum EMouseEventType { MOUSE_EVENT_DOWN, MOUSE_EVENT_UP, MOUSE_EVENT_MOVE, MOUSE_EVENT_DOUBLE_CLICK - }EMouseEventType; + }; void mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers); - typedef enum + enum EKeyEventType { KEY_EVENT_DOWN, KEY_EVENT_UP, KEY_EVENT_REPEAT - }EKeyEventType; + }; bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); @@ -127,39 +114,13 @@ public: void loadURI(const std::string &uri); - // "Loading" means uninitialized or any state prior to fully running (processing commands) - bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; }; - - // "Running" means the steady state -- i.e. processing messages - bool isPluginRunning(void) { return mPlugin?mPlugin->isRunning():false; }; - - // "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally) - bool isPluginExited(void) { return mPlugin?mPlugin->isDone():false; }; - - std::string getPluginVersion() { return mPlugin?mPlugin->getPluginVersion():std::string(""); }; - - bool getDisableTimeout() { return mPlugin?mPlugin->getDisableTimeout():false; }; - void setDisableTimeout(bool disable) { if(mPlugin) mPlugin->setDisableTimeout(disable); }; - // Inherited from LLPluginProcessParentOwner /* virtual */ void receivePluginMessage(const LLPluginMessage &message); /* virtual */ void pluginLaunchFailed(); /* virtual */ void pluginDied(); + // Inherited from LLPluginClassBasic + /* virtual */ void priorityChanged(EPriority priority); - - typedef enum - { - PRIORITY_UNLOADED, // media plugin isn't even loaded. - PRIORITY_STOPPED, // media is not playing, shouldn't need to update at all. - PRIORITY_HIDDEN, // media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc. - PRIORITY_SLIDESHOW, // media is in the far distance, updates very infrequently - PRIORITY_LOW, // media is in the distance, may be rendered at reduced size - PRIORITY_NORMAL, // normal (default) priority - PRIORITY_HIGH // media has user focus and/or is taking up most of the screen - }EPriority; - - static const char* priorityToString(EPriority priority); - void setPriority(EPriority priority); void setLowPrioritySizeLimit(int size); F64 getCPUUsage(); @@ -256,22 +217,23 @@ public: void initializeUrlHistory(const LLSD& url_history); protected: - - LLPluginClassMediaOwner *mOwner; + virtual bool init_impl(void); + virtual void reset_impl(void); + virtual void idle_impl(void); // Notify this object's owner that an event has occurred. void mediaEvent(LLPluginClassMediaOwner::EMediaEvent event); - void sendMessage(const LLPluginMessage &message); // Send message internally, either queueing or sending directly. - std::queue mSendQueue; // Used to queue messages while the plugin initializes. - void setSizeInternal(void); +protected: + LLPluginClassMediaOwner *mOwner; + bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true S32 mRequestedTextureDepth; - LLGLenum mRequestedTextureInternalFormat; - LLGLenum mRequestedTextureFormat; - LLGLenum mRequestedTextureType; + U32 mRequestedTextureInternalFormat; + U32 mRequestedTextureFormat; + U32 mRequestedTextureType; bool mRequestedTextureSwapBytes; bool mRequestedTextureCoordsOpenGL; @@ -313,16 +275,11 @@ protected: float mRequestedVolume; - // Priority of this media stream - EPriority mPriority; int mLowPrioritySizeLimit; bool mAllowDownsample; int mPadding; - - LLPluginProcessParent *mPlugin; - LLRect mDirtyRect; std::string translateModifiers(MASK modifiers); @@ -332,8 +289,6 @@ protected: int mLastMouseY; LLPluginClassMediaOwner::EMediaStatus mStatus; - - F64 mSleepTime; bool mCanCut; bool mCanCopy; @@ -363,15 +318,6 @@ protected: F64 mDuration; F64 mCurrentRate; F64 mLoadedDuration; - -//-------------------------------------- - //debug use only - // -private: - bool mDeleteOK ; -public: - void setDeleteOK(bool flag) { mDeleteOK = flag ;} -//-------------------------------------- }; #endif // LL_LLPLUGINCLASSMEDIA_H diff --git a/indra/llplugin/llplugininstance.cpp b/indra/llplugin/llplugininstance.cpp index 3a1395cd2..914eadcce 100644 --- a/indra/llplugin/llplugininstance.cpp +++ b/indra/llplugin/llplugininstance.cpp @@ -55,8 +55,8 @@ const char *LLPluginInstance::PLUGIN_INIT_FUNCTION_NAME = "LLPluginInitEntryPoin */ LLPluginInstance::LLPluginInstance(LLPluginInstanceMessageListener *owner) : mDSOHandle(NULL), - mPluginUserData(NULL), - mPluginSendMessageFunction(NULL) + mPluginObject(NULL), + mReceiveMessageFunction(NULL) { mOwner = owner; } @@ -109,9 +109,9 @@ int LLPluginInstance::load(std::string &plugin_file) if(result == APR_SUCCESS) { - result = init_function(staticReceiveMessage, (void*)this, &mPluginSendMessageFunction, &mPluginUserData); + result = init_function(&LLPluginInstance::staticReceiveMessage, this, &mReceiveMessageFunction, &mPluginObject); - if(result != APR_SUCCESS) + if(result != 0) { LL_WARNS("Plugin") << "call to init function failed with error " << result << LL_ENDL; } @@ -120,6 +120,14 @@ int LLPluginInstance::load(std::string &plugin_file) return (int)result; } +// This is the SLPlugin process (the child process). +// This is not part of a DSO. +// +// This function is called from LLPluginProcessChild::receiveMessageRaw +// for messages received from the viewer that are not internal. +// +// It sends the message to the DSO by calling the registered 'received' +// function (for example, FilepickerPlugin::receiveMessage). /** * Sends a message to the plugin. * @@ -127,10 +135,10 @@ int LLPluginInstance::load(std::string &plugin_file) */ void LLPluginInstance::sendMessage(const std::string &message) { - if(mPluginSendMessageFunction) + if(mReceiveMessageFunction) { LL_DEBUGS("Plugin") << "sending message to plugin: \"" << message << "\"" << LL_ENDL; - mPluginSendMessageFunction(message.c_str(), &mPluginUserData); + mReceiveMessageFunction(message.c_str(), &mPluginObject); } else { @@ -147,14 +155,19 @@ void LLPluginInstance::idle(void) } // static -void LLPluginInstance::staticReceiveMessage(const char *message_string, void **user_data) +void LLPluginInstance::staticReceiveMessage(char const* message_string, LLPluginInstance** self_ptr) { - // TODO: validate that the user_data argument is still a valid LLPluginInstance pointer + // TODO: validate that the self argument is still a valid LLPluginInstance pointer // we could also use a key that's looked up in a map (instead of a direct pointer) for safety, but that's probably overkill - LLPluginInstance *self = (LLPluginInstance*)*user_data; - self->receiveMessage(message_string); + (*self_ptr)->receiveMessage(message_string); } +// This is the SLPlugin process. +// This is not part of a DSO. +// +// This function is called by a loaded DSO (through a function pointer, it +// is called from BasicPluginBase::sendMessage) for messages it wants to +// send to the viewer. It calls LLPluginProcessChild::receivePluginMessage. /** * Plugin receives message from plugin loader shell. * diff --git a/indra/llplugin/llplugininstance.h b/indra/llplugin/llplugininstance.h index 9cf6075ff..faa1cbb7f 100644 --- a/indra/llplugin/llplugininstance.h +++ b/indra/llplugin/llplugininstance.h @@ -51,6 +51,8 @@ public: virtual void receivePluginMessage(const std::string &message) = 0; }; +class BasicPluginBase; + /** * @brief LLPluginInstance handles loading the dynamic library of a plugin and setting up its entry points for message passing. */ @@ -79,26 +81,28 @@ public: * @param[in] message_string Null-terminated C string * @param[in] user_data The opaque reference that the callee supplied during setup. */ - typedef void (*sendMessageFunction) (const char *message_string, void **user_data); + typedef void (*receiveMessageFunction)(char const* message_string, BasicPluginBase** plugin_object); + + typedef void (*sendMessageFunction)(char const* message_string, LLPluginInstance** plugin_instance); /** The signature of the plugin init function. TODO:DOC check direction (pluging loader shell to plugin?) * * @param[in] host_user_data Data from plugin loader shell. * @param[in] plugin_send_function Function for sending from the plugin loader shell to plugin. */ - typedef int (*pluginInitFunction) (sendMessageFunction host_send_func, void *host_user_data, sendMessageFunction *plugin_send_func, void **plugin_user_data); + typedef int (*pluginInitFunction)(sendMessageFunction send_message_function, LLPluginInstance* plugin_instance, receiveMessageFunction* receive_message_function, BasicPluginBase** plugin_object); /** Name of plugin init function */ static const char *PLUGIN_INIT_FUNCTION_NAME; private: - static void staticReceiveMessage(const char *message_string, void **user_data); + static void staticReceiveMessage(char const* message_string, LLPluginInstance** plugin_instance); void receiveMessage(const char *message_string); apr_dso_handle_t *mDSOHandle; - void *mPluginUserData; - sendMessageFunction mPluginSendMessageFunction; + BasicPluginBase* mPluginObject; + receiveMessageFunction mReceiveMessageFunction; LLPluginInstanceMessageListener *mOwner; }; diff --git a/indra/llplugin/llpluginmessage.h b/indra/llplugin/llpluginmessage.h index fe504c8b9..7bc4ea12d 100644 --- a/indra/llplugin/llpluginmessage.h +++ b/indra/llplugin/llpluginmessage.h @@ -99,8 +99,17 @@ public: // (this clears out all existing state before starting the parse) // Returns -1 on failure, otherwise returns the number of key/value pairs in the message. int parse(const std::string &message); - - + + enum LLPLUGIN_LOG_LEVEL { + LOG_LEVEL_DEBUG, + LOG_LEVEL_INFO, + LOG_LEVEL_WARN, + LOG_LEVEL_ERR, + }; + + // For debugging purposes. + friend std::ostream& operator<<(std::ostream& os, LLPluginMessage const& message) { return os << message.mMessage; } + private: LLSD mMessage; diff --git a/indra/llplugin/llpluginmessageclasses.h b/indra/llplugin/llpluginmessageclasses.h index 8812a1676..b61720ab4 100644 --- a/indra/llplugin/llpluginmessageclasses.h +++ b/indra/llplugin/llpluginmessageclasses.h @@ -48,6 +48,9 @@ #define LLPLUGIN_MESSAGE_CLASS_BASE "base" #define LLPLUGIN_MESSAGE_CLASS_BASE_VERSION "1.0" +#define LLPLUGIN_MESSAGE_CLASS_BASIC "basic" +#define LLPLUGIN_MESSAGE_CLASS_BASIC_VERSION "1.0" + #define LLPLUGIN_MESSAGE_CLASS_MEDIA "media" #define LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION "1.0" diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp index ebac3c52b..7aaa09372 100644 --- a/indra/llplugin/llpluginmessagepipe.cpp +++ b/indra/llplugin/llpluginmessagepipe.cpp @@ -89,6 +89,16 @@ bool LLPluginMessagePipeOwner::writeMessageRaw(const std::string &message) return result; } +bool LLPluginMessagePipeOwner::flushMessages(void) +{ + bool result = true; + if (mMessagePipe != NULL) + { + result = mMessagePipe->flushMessages(); + } + return result; +} + void LLPluginMessagePipeOwner::killMessagePipe(void) { if(mMessagePipe != NULL) @@ -163,26 +173,32 @@ bool LLPluginMessagePipe::pump(F64 timeout) return result; } -bool LLPluginMessagePipe::pumpOutput() +static apr_interval_time_t const flush_max_block_time = 10000000; // Even when flushing, give up after 10 seconds. +static apr_interval_time_t const flush_min_timeout = 1000; // When flushing, initially timeout after 1 ms. +static apr_interval_time_t const flush_max_timeout = 50000; // Never wait longer than 50 ms. + +// DO NOT SET 'flush' TO TRUE WHEN CALLED ON THE VIEWER SIDE! +// flush is only intended for plugin-side. +bool LLPluginMessagePipe::pumpOutput(bool flush) { bool result = true; if(mSocket) { - apr_status_t status; - apr_size_t size; + apr_interval_time_t flush_time_left_usec = flush_max_block_time; + apr_interval_time_t timeout_usec = flush ? flush_min_timeout : 0; LLMutexLock lock(&mOutputMutex); - if(!mOutput.empty()) + while(result && !mOutput.empty()) { // write any outgoing messages - size = (apr_size_t)mOutput.size(); + apr_size_t size = (apr_size_t)mOutput.size(); - setSocketTimeout(0); + setSocketTimeout(timeout_usec); // LL_INFOS("Plugin") << "before apr_socket_send, size = " << size << LL_ENDL; - status = apr_socket_send( + apr_status_t status = apr_socket_send( mSocket->getSocket(), (const char*)mOutput.data(), &size); @@ -193,12 +209,29 @@ bool LLPluginMessagePipe::pumpOutput() { // success mOutput = mOutput.substr(size); + break; } - else if(APR_STATUS_IS_EAGAIN(status)) + else if(APR_STATUS_IS_EAGAIN(status) || APR_STATUS_IS_TIMEUP(status)) { // Socket buffer is full... // remove the written part from the buffer and try again later. mOutput = mOutput.substr(size); + if (!flush) + break; + flush_time_left_usec -= timeout_usec; + if (flush_time_left_usec <= 0) + { + result = false; + } + else if (size == 0) + { + // Nothing at all was written. Increment wait time. + timeout_usec = std::min(flush_max_timeout, 2 * timeout_usec); + } + else + { + timeout_usec = std::max(flush_min_timeout, timeout_usec / 2); + } } else if(APR_STATUS_IS_EOF(status)) { diff --git a/indra/llplugin/llpluginmessagepipe.h b/indra/llplugin/llpluginmessagepipe.h index 6eedca27f..1e71caf42 100644 --- a/indra/llplugin/llpluginmessagepipe.h +++ b/indra/llplugin/llpluginmessagepipe.h @@ -61,6 +61,8 @@ protected: bool canSendMessage(void); // call this to send a message over the pipe bool writeMessageRaw(const std::string &message); + // call this to attempt to flush all messages for 10 seconds long. + bool flushMessages(void); // call this to close the pipe void killMessagePipe(void); @@ -79,8 +81,10 @@ public: void clearOwner(void); bool pump(F64 timeout = 0.0f); - bool pumpOutput(); + bool pumpOutput(bool flush = false); bool pumpInput(F64 timeout = 0.0f); + + bool flushMessages(void) { return pumpOutput(true); } protected: void processInput(void); diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index d2238236f..fdcb4f6a8 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -227,6 +227,7 @@ void LLPluginProcessChild::idle(void) case STATE_DONE: // just sit here. + LL_WARNS("Plugin") << "Calling LLPluginProcessChild::idle while in STATE_DONE!" << LL_ENDL; break; } @@ -286,6 +287,11 @@ bool LLPluginProcessChild::isDone(void) return result; } +// This is the SLPlugin process. +// This is not part of a DSO. +// +// This function is called by SLPlugin to send a message (originating from +// SLPlugin itself) to the loaded DSO. It calls LLPluginInstance::sendMessage. void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message) { if (mInstance) @@ -305,15 +311,26 @@ void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message) } } +// This is the SLPlugin process (the child process). +// This is not part of a DSO. +// +// This function is called by SLPlugin to send 'message' to the viewer (the parent process). void LLPluginProcessChild::sendMessageToParent(const LLPluginMessage &message) { std::string buffer = message.generate(); LL_DEBUGS("Plugin") << "Sending to parent: " << buffer << LL_ENDL; + // Write the serialized message to the pipe. writeMessageRaw(buffer); } +// This is the SLPlugin process (the child process). +// This is not part of a DSO. +// +// This function is called when the serialized message 'message' was received from the viewer. +// It parses the message and handles LLPLUGIN_MESSAGE_CLASS_INTERNAL. +// Other message classes are passed on to LLPluginInstance::sendMessage. void LLPluginProcessChild::receiveMessageRaw(const std::string &message) { // Incoming message from the TCP Socket @@ -449,7 +466,17 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message) } } -/* virtual */ +// This is the SLPlugin process. +// This is not part of a DSO. +// +// This function is called from LLPluginInstance::receiveMessage +// for messages from a loaded DSO that have to be passed to the +// viewer. +// +// It handles the base messages that are responses to messages sent by this +// class, and passes the rest on to LLPluginMessagePipeOwner::writeMessageRaw +// to be written to the pipe. +/* virtual */ void LLPluginProcessChild::receivePluginMessage(const std::string &message) { LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL; @@ -527,6 +554,26 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message) } } } + else if (message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) + { + bool flush = false; + std::string message_name = parsed.getName(); + if(message_name == "shutdown") + { + // The plugin is finished. + setState(STATE_UNLOADING); + flush = true; + } + else if (message_name == "flush") + { + flush = true; + passMessage = false; + } + if (flush) + { + flushMessages(); + } + } } if(passMessage) diff --git a/indra/llplugin/llpluginprocesschild.h b/indra/llplugin/llpluginprocesschild.h index 5d643d792..66082db7c 100644 --- a/indra/llplugin/llpluginprocesschild.h +++ b/indra/llplugin/llpluginprocesschild.h @@ -88,7 +88,7 @@ private: STATE_PLUGIN_LOADED, // plugin library has been loaded STATE_PLUGIN_INITIALIZING, // plugin is processing init message STATE_RUNNING, // steady state (processing messages) - STATE_UNLOADING, // plugin has sent shutdown_response and needs to be unloaded + STATE_UNLOADING, // plugin has sent shutdown and needs to be unloaded STATE_UNLOADED, // plugin has been unloaded STATE_ERROR, // generic bailout state STATE_DONE // state machine will sit in this state after either error or normal termination. diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 2cb6b2832..0d361324e 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -38,6 +38,9 @@ #include "llpluginprocessparent.h" #include "llpluginmessagepipe.h" #include "llpluginmessageclasses.h" +#if LL_LINUX +#include +#endif #include "llapr.h" @@ -101,6 +104,7 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner) mDebug = false; mBlocked = false; mPolledInput = false; + mReceivedShutdown = false; mPollFD.client_data = NULL; mPollFDPool.create(); @@ -162,6 +166,8 @@ void LLPluginProcessParent::errorState(void) { if(mState < STATE_RUNNING) setState(STATE_LAUNCH_FAILURE); + else if (mReceivedShutdown) + setState(STATE_EXITING); else setState(STATE_ERROR); } @@ -373,14 +379,12 @@ void LLPluginProcessParent::idle(void) { if(mDebug) { - #if LL_DARWIN // If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue. - + std::stringstream cmd; + +#if LL_DARWIN // The command we're constructing would look like this on the command line: // osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell' - - std::stringstream cmd; - mDebugger.setExecutable("/usr/bin/osascript"); mDebugger.addArgument("-e"); mDebugger.addArgument("tell application \"Terminal\""); @@ -392,19 +396,32 @@ void LLPluginProcessParent::idle(void) mDebugger.addArgument("-e"); mDebugger.addArgument("end tell"); mDebugger.launch(); - - #elif LL_LINUX - - std::stringstream cmd; - - mDebugger.setExecutable("/usr/bin/gnome-terminal"); - mDebugger.addArgument("--geometry=165x24-0+0"); - mDebugger.addArgument("-e"); - cmd << "/usr/bin/gdb -n /proc/" << mProcess.getProcessID() << "/exe " << mProcess.getProcessID(); - mDebugger.addArgument(cmd.str()); +#elif LL_LINUX + // The command we're constructing would look like this on the command line: + // /usr/bin/xterm -geometry 160x24-0+0 -e '/usr/bin/gdb -n /proc/12345/exe 12345' + // This can be changed by setting the following environment variables, for example: + // export LL_DEBUG_TERMINAL_COMMAND="/usr/bin/gnome-terminal --geometry=165x24-0+0 -e %s" + // export LL_DEBUG_GDB_PATH=/usr/bin/gdb + char const* env; + std::string const terminal_command = (env = getenv("LL_DEBUG_TERMINAL_COMMAND")) ? env : "/usr/bin/xterm -geometry 160x24+0+0 -e %s"; + char const* const gdb_path = (env = getenv("LL_DEBUG_GDB_PATH")) ? env : "/usr/bin/gdb"; + cmd << gdb_path << " -n /proc/" << mProcess.getProcessID() << "/exe " << mProcess.getProcessID(); + std::vector tokens = boost::program_options::split_unix(terminal_command, " "); + std::vector::iterator token = tokens.begin(); + mDebugger.setExecutable(*token); + while (++token != tokens.end()) + { + if (*token == "%s") + { + mDebugger.addArgument(cmd.str()); + } + else + { + mDebugger.addArgument(*token); + } + } mDebugger.launch(); - - #endif +#endif } // This will allow us to time out if the process never starts. @@ -565,6 +582,9 @@ void LLPluginProcessParent::setSleepTime(F64 sleep_time, bool force_send) } } +// This is the viewer process (the parent process) +// +// This function is called to send a message to the plugin. void LLPluginProcessParent::sendMessage(const LLPluginMessage &message) { if(message.hasValue("blocking_response")) @@ -574,9 +594,23 @@ void LLPluginProcessParent::sendMessage(const LLPluginMessage &message) // reset the heartbeat timer, since there will have been no heartbeats while the plugin was blocked. mHeartbeat.setTimerExpirySec(mPluginLockupTimeout); } + if (message.hasValue("gorgon")) + { + // After this message it is expected that the plugin will not send any more messages for a long time. + mBlocked = true; + } std::string buffer = message.generate(); - LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL; +#if LL_DEBUG + if (message.getName() == "mouse_event") + { + LL_DEBUGS("PluginMouseEvent") << "Sending: " << buffer << LL_ENDL; + } + else + { + LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL; + } +#endif writeMessageRaw(buffer); // Try to send message immediately. @@ -622,6 +656,16 @@ void LLPluginProcessParent::setMessagePipe(LLPluginMessagePipe *message_pipe) } } +apr_status_t LLPluginProcessParent::socketError(apr_status_t error) +{ + mSocketError = error; + if (APR_STATUS_IS_EPIPE(error)) + { + errorState(); + } + return error; +}; + //static void LLPluginProcessParent::dirtyPollSet() { @@ -838,9 +882,13 @@ void LLPluginProcessParent::servicePoll() } } +// This the viewer process (the parent process). +// +// This function is called when a message is received from a plugin. +// It parses the message and passes it on to LLPluginProcessParent::receiveMessage. void LLPluginProcessParent::receiveMessageRaw(const std::string &message) { - LL_DEBUGS("Plugin") << "Received: " << message << LL_ENDL; + LL_DEBUGS("PluginRaw") << "Received: " << message << LL_ENDL; LLPluginMessage parsed; if(parsed.parse(message) != -1) @@ -849,6 +897,13 @@ void LLPluginProcessParent::receiveMessageRaw(const std::string &message) { mBlocked = true; } + if(parsed.hasValue("perseus")) + { + mBlocked = false; + + // reset the heartbeat timer, since there will have been no heartbeats while the plugin was blocked. + mHeartbeat.setTimerExpirySec(mPluginLockupTimeout); + } if(mPolledInput) { @@ -891,6 +946,12 @@ void LLPluginProcessParent::receiveMessageEarly(const LLPluginMessage &message) } } +// This is the viewer process (the parent process). +// +// This function is called for messages that have to +// be written to the plugin. +// Note that LLPLUGIN_MESSAGE_CLASS_INTERNAL messages +// are not sent to the plugin, but are handled here. void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) { std::string message_class = message.getClass(); @@ -949,8 +1010,13 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) mCPUUsage = message.getValueReal("cpu_usage"); - LL_DEBUGS("Plugin") << "cpu usage reported as " << mCPUUsage << LL_ENDL; - + LL_DEBUGS("PluginHeartbeat") << "cpu usage reported as " << mCPUUsage << LL_ENDL; + } + else if(message_name == "shutdown") + { + LL_INFOS("Plugin") << "received shutdown message" << LL_ENDL; + mReceivedShutdown = true; + mOwner->receivedShutdown(); } else if(message_name == "shm_add_response") { @@ -970,6 +1036,30 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) mSharedMemoryRegions.erase(iter); } } + else if(message_name == "log_message") + { + std::string msg=message.getValue("message"); + S32 level=message.getValueS32("log_level"); + + switch(level) + { + case LLPluginMessage::LOG_LEVEL_DEBUG: + LL_DEBUGS("Plugin child")<getParentFloater(floater_to_close)) { + if(floater_to_close == previous_floater) + { + break; + } if(floater_to_close->isCloseable()) { return floater_to_close; } + previous_floater = floater_to_close; } return NULL; diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 29b50d7bc..28fcd7751 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -524,7 +524,11 @@ std::string LLDir::getTempFilename() const std::string LLDir::getScrubbedFileName(const std::string uncleanFileName) { std::string name(uncleanFileName); - const std::string illegalChars(getForbiddenFileChars()); + std::string illegalChars(getForbiddenFileChars()); +#if LL_LINUX || LL_SOLARIS + // Spaces in filenames are REALLY annoying on UNIX. + illegalChars += ' '; +#endif // replace any illegal file chars with and underscore '_' for( unsigned int i = 0; i < illegalChars.length(); i++ ) { diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt deleted file mode 100644 index 9858d093e..000000000 --- a/indra/media_plugins/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# -*- cmake -*- - -add_subdirectory(base) - -add_subdirectory(webkit) - -if (LINUX) - add_subdirectory(gstreamer010) -endif (LINUX) - -if (DARWIN OR WINDOWS) - add_subdirectory(quicktime) -endif (DARWIN OR WINDOWS) - -add_subdirectory(example) diff --git a/indra/media_plugins/example/media_plugin_example.cpp b/indra/media_plugins/example/media_plugin_example.cpp deleted file mode 100644 index da7de0179..000000000 --- a/indra/media_plugins/example/media_plugin_example.cpp +++ /dev/null @@ -1,412 +0,0 @@ -/** - * @file media_plugin_example.cpp - * @brief Example plugin for LLMedia API plugin system - * - * @cond - * $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$ - * @endcond - */ - -#include "linden_common.h" - -#include "llgl.h" -#include "llplugininstance.h" -#include "llpluginmessage.h" -#include "llpluginmessageclasses.h" -#include "media_plugin_base.h" - -#include - -//////////////////////////////////////////////////////////////////////////////// -// -class MediaPluginExample : - public MediaPluginBase -{ - public: - MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ); - ~MediaPluginExample(); - - /*virtual*/ void receiveMessage( const char* message_string ); - - private: - bool init(); - void update( F64 milliseconds ); - void write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ); - bool mFirstTime; - - time_t mLastUpdateTime; - enum Constants { ENumObjects = 10 }; - unsigned char* mBackgroundPixels; - int mColorR[ ENumObjects ]; - int mColorG[ ENumObjects ]; - int mColorB[ ENumObjects ]; - int mXpos[ ENumObjects ]; - int mYpos[ ENumObjects ]; - int mXInc[ ENumObjects ]; - int mYInc[ ENumObjects ]; - int mBlockSize[ ENumObjects ]; - bool mMouseButtonDown; - bool mStopAction; -}; - -//////////////////////////////////////////////////////////////////////////////// -// -MediaPluginExample::MediaPluginExample( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ) : - MediaPluginBase( host_send_func, host_user_data ) -{ - mFirstTime = true; - mWidth = 0; - mHeight = 0; - mDepth = 4; - mPixels = 0; - mMouseButtonDown = false; - mStopAction = false; - mLastUpdateTime = 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// -MediaPluginExample::~MediaPluginExample() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginExample::receiveMessage( const char* message_string ) -{ -// std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl; - LLPluginMessage message_in; - - if(message_in.parse(message_string) >= 0) - { - std::string message_class = message_in.getClass(); - std::string message_name = message_in.getName(); - if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) - { - if(message_name == "init") - { - LLPluginMessage message("base", "init_response"); - LLSD versions = LLSD::emptyMap(); - versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; - versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; - versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; - message.setValueLLSD("versions", versions); - - std::string plugin_version = "Example plugin 1.0..0"; - message.setValue("plugin_version", plugin_version); - sendMessage(message); - } - else if(message_name == "idle") - { - // no response is necessary here. - F64 time = message_in.getValueReal("time"); - - // Convert time to milliseconds for update() - update((int)(time * 1000.0f)); - } - else if(message_name == "cleanup") - { - } - 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); - } - else - { -// std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl; - } - - // Send the response so it can be cleaned up. - LLPluginMessage message("base", "shm_remove_response"); - message.setValue("name", name); - sendMessage(message); - } - else - { -// std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl; - } - } - else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) - { - if(message_name == "init") - { - // Plugin gets to decide the texture parameters to use. - mDepth = 4; - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); - message.setValueS32("default_width", 1024); - message.setValueS32("default_height", 1024); - message.setValueS32("depth", mDepth); - message.setValueU32("internalformat", GL_RGBA); - message.setValueU32("format", GL_RGBA); - message.setValueU32("type", GL_UNSIGNED_BYTE); - message.setValueBoolean("coords_opengl", true); - 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"); - - 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; - mWidth = width; - mHeight = height; - - mTextureWidth = texture_width; - mTextureHeight = 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); - - } - else if(message_name == "load_uri") - { - } - else if(message_name == "mouse_event") - { - std::string event = message_in.getValue("event"); - if(event == "down") - { - - } - else if(event == "up") - { - } - else if(event == "double_click") - { - } - } - } - else - { -// std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl; - }; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginExample::write_pixel( int x, int y, unsigned char r, unsigned char g, unsigned char b ) -{ - // make sure we don't write outside the buffer - if ( ( x < 0 ) || ( x >= mWidth ) || ( y < 0 ) || ( y >= mHeight ) ) - return; - - if ( mBackgroundPixels != NULL ) - { - unsigned char *pixel = mBackgroundPixels; - pixel += y * mWidth * mDepth; - pixel += ( x * mDepth ); - pixel[ 0 ] = b; - pixel[ 1 ] = g; - pixel[ 2 ] = r; - - setDirty( x, y, x + 1, y + 1 ); - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginExample::update( F64 milliseconds ) -{ - if ( mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048 ) - return; - - if ( mPixels == 0 ) - return; - - if ( mFirstTime ) - { - for( int n = 0; n < ENumObjects; ++n ) - { - mXpos[ n ] = ( mWidth / 2 ) + rand() % ( mWidth / 16 ) - ( mWidth / 32 ); - mYpos[ n ] = ( mHeight / 2 ) + rand() % ( mHeight / 16 ) - ( mHeight / 32 ); - - mColorR[ n ] = rand() % 0x60 + 0x60; - mColorG[ n ] = rand() % 0x60 + 0x60; - mColorB[ n ] = rand() % 0x60 + 0x60; - - mXInc[ n ] = 0; - while ( mXInc[ n ] == 0 ) - mXInc[ n ] = rand() % 7 - 3; - - mYInc[ n ] = 0; - while ( mYInc[ n ] == 0 ) - mYInc[ n ] = rand() % 9 - 4; - - mBlockSize[ n ] = rand() % 0x30 + 0x10; - }; - - delete [] mBackgroundPixels; - - mBackgroundPixels = new unsigned char[ mWidth * mHeight * mDepth ]; - - mFirstTime = false; - }; - - if ( mStopAction ) - return; - - if ( time( NULL ) > mLastUpdateTime + 3 ) - { - const int num_squares = rand() % 20 + 4; - int sqr1_r = rand() % 0x80 + 0x20; - int sqr1_g = rand() % 0x80 + 0x20; - int sqr1_b = rand() % 0x80 + 0x20; - int sqr2_r = rand() % 0x80 + 0x20; - int sqr2_g = rand() % 0x80 + 0x20; - int sqr2_b = rand() % 0x80 + 0x20; - - for ( int y1 = 0; y1 < num_squares; ++y1 ) - { - for ( int x1 = 0; x1 < num_squares; ++x1 ) - { - int px_start = mWidth * x1 / num_squares; - int px_end = ( mWidth * ( x1 + 1 ) ) / num_squares; - int py_start = mHeight * y1 / num_squares; - int py_end = ( mHeight * ( y1 + 1 ) ) / num_squares; - - for( int y2 = py_start; y2 < py_end; ++y2 ) - { - for( int x2 = px_start; x2 < px_end; ++x2 ) - { - int rowspan = mWidth * mDepth; - - if ( ( y1 % 2 ) ^ ( x1 % 2 ) ) - { - mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr1_r; - mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr1_g; - mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr1_b; - } - else - { - mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 0 ] = sqr2_r; - mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 1 ] = sqr2_g; - mBackgroundPixels[ y2 * rowspan + x2 * mDepth + 2 ] = sqr2_b; - }; - }; - }; - }; - }; - - time( &mLastUpdateTime ); - }; - - memcpy( mPixels, mBackgroundPixels, mWidth * mHeight * mDepth ); - - for( int n = 0; n < ENumObjects; ++n ) - { - if ( rand() % 50 == 0 ) - { - mXInc[ n ] = 0; - while ( mXInc[ n ] == 0 ) - mXInc[ n ] = rand() % 7 - 3; - - mYInc[ n ] = 0; - while ( mYInc[ n ] == 0 ) - mYInc[ n ] = rand() % 9 - 4; - }; - - if ( mXpos[ n ] + mXInc[ n ] < 0 || mXpos[ n ] + mXInc[ n ] >= mWidth - mBlockSize[ n ] ) - mXInc[ n ] =- mXInc[ n ]; - - if ( mYpos[ n ] + mYInc[ n ] < 0 || mYpos[ n ] + mYInc[ n ] >= mHeight - mBlockSize[ n ] ) - mYInc[ n ] =- mYInc[ n ]; - - mXpos[ n ] += mXInc[ n ]; - mYpos[ n ] += mYInc[ n ]; - - for( int y = 0; y < mBlockSize[ n ]; ++y ) - { - for( int x = 0; x < mBlockSize[ n ]; ++x ) - { - mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 0 ] = mColorR[ n ]; - mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 1 ] = mColorG[ n ]; - mPixels[ ( mXpos[ n ] + x ) * mDepth + ( mYpos[ n ] + y ) * mDepth * mWidth + 2 ] = mColorB[ n ]; - }; - }; - }; - - setDirty( 0, 0, mWidth, mHeight ); -}; - -//////////////////////////////////////////////////////////////////////////////// -// -bool MediaPluginExample::init() -{ - LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text" ); - message.setValue( "name", "Example Plugin" ); - sendMessage( message ); - - return true; -}; - -//////////////////////////////////////////////////////////////////////////////// -// -int init_media_plugin( LLPluginInstance::sendMessageFunction host_send_func, - void* host_user_data, - LLPluginInstance::sendMessageFunction *plugin_send_func, - void **plugin_user_data ) -{ - MediaPluginExample* self = new MediaPluginExample( host_send_func, host_user_data ); - *plugin_send_func = MediaPluginExample::staticReceiveMessage; - *plugin_user_data = ( void* )self; - - return 0; -} - diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h deleted file mode 100644 index 6bc272c00..000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @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/gstreamer010/llmediaimplgstreamer_syms.cpp b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp deleted file mode 100644 index 2e4baaa9e..000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/** - * @file llmediaimplgstreamer_syms.cpp - * @brief dynamic GStreamer symbol-grabbing code - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#if LL_GSTREAMER010_ENABLED - -#include - -extern "C" { -#include - -#include "apr_pools.h" -#include "apr_dso.h" -} - -#include "llmediaimplgstreamertriviallogging.h" - -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL -#include "llmediaimplgstreamer_syms_raw.inc" -#include "llmediaimplgstreamer_syms_rawv.inc" -#undef LL_GST_SYM - -// a couple of stubs for disgusting reasons -GstDebugCategory* -ll_gst_debug_category_new(gchar *name, guint color, gchar *description) -{ - static GstDebugCategory dummy; - return &dummy; -} -void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname) -{ -} - -static bool sSymsGrabbed = false; -static apr_pool_t *sSymGSTDSOMemoryPool = NULL; -static apr_dso_handle_t *sSymGSTDSOHandleG = NULL; -static apr_dso_handle_t *sSymGSTDSOHandleV = NULL; - - -bool grab_gst_syms(std::string gst_dso_name, - std::string gst_dso_name_vid) -{ - if (sSymsGrabbed) - { - // already have grabbed good syms - return TRUE; - } - - bool sym_error = false; - bool rtn = false; - apr_status_t rv; - apr_dso_handle_t *sSymGSTDSOHandle = NULL; - -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##GSTSYM, sSymGSTDSOHandle, #GSTSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #GSTSYM); if (REQ) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #GSTSYM, (void*)ll##GSTSYM);}while(0) - - //attempt to load the shared libraries - apr_pool_create(&sSymGSTDSOMemoryPool, NULL); - - if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle, - gst_dso_name.c_str(), - sSymGSTDSOMemoryPool) )) - { - INFOMSG("Found DSO: %s", gst_dso_name.c_str()); -#include "llmediaimplgstreamer_syms_raw.inc" - - if ( sSymGSTDSOHandle ) - { - sSymGSTDSOHandleG = sSymGSTDSOHandle; - sSymGSTDSOHandle = NULL; - } - - if ( APR_SUCCESS == - (rv = apr_dso_load(&sSymGSTDSOHandle, - gst_dso_name_vid.c_str(), - sSymGSTDSOMemoryPool) )) - { - INFOMSG("Found DSO: %s", gst_dso_name_vid.c_str()); -#include "llmediaimplgstreamer_syms_rawv.inc" - rtn = !sym_error; - } - else - { - INFOMSG("Couldn't load DSO: %s", gst_dso_name_vid.c_str()); - rtn = false; // failure - } - } - else - { - INFOMSG("Couldn't load DSO: %s", gst_dso_name.c_str()); - rtn = false; // failure - } - - if (sym_error) - { - WARNMSG("Failed to find necessary symbols in GStreamer libraries."); - } - - if ( sSymGSTDSOHandle ) - { - sSymGSTDSOHandleV = sSymGSTDSOHandle; - sSymGSTDSOHandle = NULL; - } -#undef LL_GST_SYM - - sSymsGrabbed = !!rtn; - return rtn; -} - - -void ungrab_gst_syms() -{ - // should be safe to call regardless of whether we've - // actually grabbed syms. - - if ( sSymGSTDSOHandleG ) - { - apr_dso_unload(sSymGSTDSOHandleG); - sSymGSTDSOHandleG = NULL; - } - - if ( sSymGSTDSOHandleV ) - { - apr_dso_unload(sSymGSTDSOHandleV); - sSymGSTDSOHandleV = NULL; - } - - if ( sSymGSTDSOMemoryPool ) - { - apr_pool_destroy(sSymGSTDSOMemoryPool); - sSymGSTDSOMemoryPool = NULL; - } - - // NULL-out all of the symbols we'd grabbed -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{ll##GSTSYM = NULL;}while(0) -#include "llmediaimplgstreamer_syms_raw.inc" -#include "llmediaimplgstreamer_syms_rawv.inc" -#undef LL_GST_SYM - - sSymsGrabbed = false; -} - - -#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h deleted file mode 100644 index d1559089c..000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file llmediaimplgstreamer_syms.h - * @brief dynamic GStreamer symbol-grabbing code - * - * @cond - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#include "linden_common.h" - -#if LL_GSTREAMER010_ENABLED - -extern "C" { -#include -} - -bool grab_gst_syms(std::string gst_dso_name, - std::string gst_dso_name_vid); -void ungrab_gst_syms(); - -#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) extern RTN (*ll##GSTSYM)(__VA_ARGS__) -#include "llmediaimplgstreamer_syms_raw.inc" -#include "llmediaimplgstreamer_syms_rawv.inc" -#undef LL_GST_SYM - -// regrettable hacks to give us better runtime compatibility with older systems -#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0) -#define llg_return_val_if_fail(COND,V) do{if (!(COND)) return V;}while(0) - -// regrettable hacks because GStreamer was not designed for runtime loading -#undef GST_TYPE_MESSAGE -#define GST_TYPE_MESSAGE (llgst_message_get_type()) -#undef GST_TYPE_OBJECT -#define GST_TYPE_OBJECT (llgst_object_get_type()) -#undef GST_TYPE_PIPELINE -#define GST_TYPE_PIPELINE (llgst_pipeline_get_type()) -#undef GST_TYPE_ELEMENT -#define GST_TYPE_ELEMENT (llgst_element_get_type()) -#undef GST_TYPE_VIDEO_SINK -#define GST_TYPE_VIDEO_SINK (llgst_video_sink_get_type()) -// more regrettable hacks to stub-out these .h-exposed GStreamer internals -void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname); -#undef _gst_debug_register_funcptr -#define _gst_debug_register_funcptr ll_gst_debug_register_funcptr -GstDebugCategory* ll_gst_debug_category_new(gchar *name, guint color, gchar *description); -#undef _gst_debug_category_new -#define _gst_debug_category_new ll_gst_debug_category_new -#undef __gst_debug_enabled -#define __gst_debug_enabled (0) - -// more hacks -#define LLGST_MESSAGE_TYPE_NAME(M) (llgst_message_type_get_name(GST_MESSAGE_TYPE(M))) - -#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc deleted file mode 100644 index b33e59363..000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc +++ /dev/null @@ -1,51 +0,0 @@ - -// required symbols to grab -LL_GST_SYM(true, gst_pad_peer_accept_caps, gboolean, GstPad *pad, GstCaps *caps); -LL_GST_SYM(true, gst_buffer_new, GstBuffer*, void); -LL_GST_SYM(true, gst_buffer_set_caps, void, GstBuffer*, GstCaps *); -LL_GST_SYM(true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*); -LL_GST_SYM(true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err); -LL_GST_SYM(true, gst_message_get_type, GType, void); -LL_GST_SYM(true, gst_message_type_get_name, const gchar*, GstMessageType type); -LL_GST_SYM(true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug); -LL_GST_SYM(true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug); -LL_GST_SYM(true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending); -LL_GST_SYM(true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state); -LL_GST_SYM(true, gst_object_unref, void, gpointer object); -LL_GST_SYM(true, gst_object_get_type, GType, void); -LL_GST_SYM(true, gst_pipeline_get_type, GType, void); -LL_GST_SYM(true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline); -LL_GST_SYM(true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data); -LL_GST_SYM(true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name); -LL_GST_SYM(true, gst_element_get_type, GType, void); -LL_GST_SYM(true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template); -LL_GST_SYM(true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp); -LL_GST_SYM(true, gst_element_class_set_details, void, GstElementClass *klass, const GstElementDetails *details); -LL_GST_SYM(true, gst_caps_unref, void, GstCaps* caps); -LL_GST_SYM(true, gst_caps_ref, GstCaps *, GstCaps* caps); -//LL_GST_SYM(true, gst_caps_is_empty, gboolean, const GstCaps *caps); -LL_GST_SYM(true, gst_caps_from_string, GstCaps *, const gchar *string); -LL_GST_SYM(true, gst_caps_replace, void, GstCaps **caps, GstCaps *newcaps); -LL_GST_SYM(true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index); -LL_GST_SYM(true, gst_caps_copy, GstCaps *, const GstCaps * caps); -//LL_GST_SYM(true, gst_caps_intersect, GstCaps *, const GstCaps *caps1, const GstCaps *caps2); -LL_GST_SYM(true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type); -LL_GST_SYM(true, _gst_plugin_register_static, void, GstPluginDesc *desc); -LL_GST_SYM(true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value); -LL_GST_SYM(true, gst_structure_get_value, G_CONST_RETURN GValue *, const GstStructure *structure, const gchar *fieldname); -LL_GST_SYM(true, gst_value_get_fraction_numerator, gint, const GValue *value); -LL_GST_SYM(true, gst_value_get_fraction_denominator, gint, const GValue *value); -LL_GST_SYM(true, gst_structure_get_name, G_CONST_RETURN gchar *, const GstStructure *structure); -LL_GST_SYM(true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64); - -// optional symbols to grab -LL_GST_SYM(false, gst_registry_fork_set_enabled, void, gboolean enabled); -LL_GST_SYM(false, gst_segtrap_set_enabled, void, gboolean enabled); -LL_GST_SYM(false, gst_message_parse_buffering, void, GstMessage *message, gint *percent); -LL_GST_SYM(false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug); -LL_GST_SYM(false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur); -LL_GST_SYM(false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano); - -// GStreamer 'internal' symbols which may not be visible in some runtimes but are still used in expanded GStreamer header macros - yuck! We'll substitute our own stubs for these. -//LL_GST_SYM(true, _gst_debug_register_funcptr, void, GstDebugFuncPtr func, gchar* ptrname); -//LL_GST_SYM(true, _gst_debug_category_new, GstDebugCategory *, gchar *name, guint color, gchar *description); diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc deleted file mode 100644 index 14fbcb48b..000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc +++ /dev/null @@ -1,5 +0,0 @@ - -// required symbols to grab -LL_GST_SYM(true, gst_video_sink_get_type, GType, void); - -// optional symbols to grab diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h deleted file mode 100644 index e7b31bec9..000000000 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @file llmediaimplgstreamertriviallogging.h - * @brief minimal logging utilities. - * - * @cond - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#ifndef __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ -#define __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ - -#include - -extern "C" { -#include -#include -} - -///////////////////////////////////////////////////////////////////////// -// Debug/Info/Warning macros. -#define MSGMODULEFOO "(media plugin)" -#define STDERRMSG(...) do{\ - fprintf(stderr, " pid:%d: ", (int)getpid());\ - fprintf(stderr, MSGMODULEFOO " %s:%d: ", __FUNCTION__, __LINE__);\ - fprintf(stderr, __VA_ARGS__);\ - fputc('\n',stderr);\ - }while(0) -#define NULLMSG(...) do{}while(0) - -#define DEBUGMSG NULLMSG -#define INFOMSG STDERRMSG -#define WARNMSG STDERRMSG -///////////////////////////////////////////////////////////////////////// - -#endif /* __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ */ diff --git a/indra/media_plugins/webkit/dummy_volume_catcher.cpp b/indra/media_plugins/webkit/dummy_volume_catcher.cpp deleted file mode 100644 index d54b31b2a..000000000 --- a/indra/media_plugins/webkit/dummy_volume_catcher.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @file dummy_volume_catcher.cpp - * @brief A null implementation of the "VolumeCatcher" class for platforms where it's not implemented yet. - * - * @cond - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#include "volume_catcher.h" - - -class VolumeCatcherImpl -{ -}; - -///////////////////////////////////////////////////// - -VolumeCatcher::VolumeCatcher() -{ - pimpl = NULL; -} - -VolumeCatcher::~VolumeCatcher() -{ -} - -void VolumeCatcher::setVolume(F32 volume) -{ -} - -void VolumeCatcher::setPan(F32 pan) -{ -} - -void VolumeCatcher::pump() -{ -} - diff --git a/indra/media_plugins/webkit/volume_catcher.h b/indra/media_plugins/webkit/volume_catcher.h deleted file mode 100644 index 337f2913d..000000000 --- a/indra/media_plugins/webkit/volume_catcher.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @file volume_catcher.h - * @brief Interface to a class with platform-specific implementations that allows control of the audio volume of all sources in the current process. - * - * @cond - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -#ifndef VOLUME_CATCHER_H -#define VOLUME_CATCHER_H - -#include "linden_common.h" - -class VolumeCatcherImpl; - -class VolumeCatcher -{ - public: - VolumeCatcher(); - ~VolumeCatcher(); - - void setVolume(F32 volume); // 0.0 - 1.0 - - // Set the left-right pan of audio sources - // where -1.0 = left, 0 = center, and 1.0 = right - void setPan(F32 pan); - - void pump(); // call this at least a few times a second if you can - it affects how quickly we can 'catch' a new audio source and adjust its volume - - private: - VolumeCatcherImpl *pimpl; -}; - -#endif // VOLUME_CATCHER_H diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 4ee02c06e..cd5a30260 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -22,6 +22,7 @@ include(LLInventory) include(LLMath) include(LLMessage) include(LLPlugin) +include(AIStateMachine) include(LLPrimitive) include(LLRender) include(LLUI) @@ -43,6 +44,7 @@ if (WINDOWS) endif (WINDOWS) include_directories( + ${CMAKE_SOURCE_DIR}/newview ${DBUSGLIB_INCLUDE_DIRS} ${HUNSPELL_INCLUDE_DIR} ${ELFIO_INCLUDE_DIR} @@ -133,7 +135,6 @@ set(viewer_SOURCE_FILES lldebugmessagebox.cpp lldebugview.cpp lldelayedgestureerror.cpp - lldirpicker.cpp lldrawable.cpp lldrawpoolalpha.cpp lldrawpoolavatar.cpp @@ -155,7 +156,6 @@ set(viewer_SOURCE_FILES llface.cpp llfasttimerview.cpp llfeaturemanager.cpp - llfilepicker.cpp llfirstuse.cpp llflexibleobject.cpp llfloaterabout.cpp @@ -443,6 +443,8 @@ set(viewer_SOURCE_FILES llviewerkeyboard.cpp llviewerlayer.cpp llviewermedia.cpp + llviewermediaeventemitter.cpp + llviewermediaobserver.cpp llviewermediafocus.cpp llviewermedia_streamingaudio.cpp llviewermenu.cpp @@ -457,6 +459,7 @@ set(viewer_SOURCE_FILES llviewerparceloverlay.cpp llviewerpartsim.cpp llviewerpartsource.cpp + llviewerpluginmanager.cpp llviewerregion.cpp llviewershadermgr.cpp llviewerstats.cpp @@ -608,7 +611,6 @@ set(viewer_HEADER_FILES lldebugmessagebox.h lldebugview.h lldelayedgestureerror.h - lldirpicker.h lldrawable.h lldrawpool.h lldrawpoolalpha.h @@ -631,7 +633,6 @@ set(viewer_HEADER_FILES llface.h llfasttimerview.h llfeaturemanager.h - llfilepicker.h llfirstuse.h llflexibleobject.h llfloaterabout.h @@ -920,6 +921,7 @@ set(viewer_HEADER_FILES llviewerkeyboard.h llviewerlayer.h llviewermedia.h + llviewermediaeventemitter.h llviewermediaobserver.h llviewermediafocus.h llviewermenu.h @@ -934,6 +936,7 @@ set(viewer_HEADER_FILES llviewerparceloverlay.h llviewerpartsim.h llviewerpartsource.h + llviewerpluginmanager.h llviewerprecompiledheaders.h llviewerregion.h llviewershadermgr.h @@ -1423,6 +1426,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLINVENTORY_LIBRARIES} ${LLMESSAGE_LIBRARIES} ${LLPLUGIN_LIBRARIES} + ${AISTATEMACHINE_LIBRARIES} ${LLPRIMITIVE_LIBRARIES} ${LLRENDER_LIBRARIES} ${FREETYPE_LIBRARIES} diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml index 6bf7613f7..cbfda6de4 100644 --- a/indra/newview/app_settings/logcontrol.xml +++ b/indra/newview/app_settings/logcontrol.xml @@ -42,6 +42,15 @@ ShaderLoading Openjpeg + + Plugin + Plugin child + + PluginRaw child + + + + diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 24d9c80f8..944b1fef0 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1952,7 +1952,7 @@ PluginAttachDebuggerToPlugins Comment - TODO: understand what this actually does -.-sg + Opens a terminal window with a debugger and attach it, every time a new SLPlugin process is started. Persist 1 Type @@ -11399,6 +11399,17 @@ Value 0 + StateMachineMaxTime + + Comment + Maximum time per frame spent executing AIStateMachine objects, in miliseconds + Persist + 1 + Type + U32 + Value + 20 + StatsAutoRun Comment diff --git a/indra/newview/ascentkeyword.cpp b/indra/newview/ascentkeyword.cpp index bcbc8a28e..65efe3958 100644 --- a/indra/newview/ascentkeyword.cpp +++ b/indra/newview/ascentkeyword.cpp @@ -33,6 +33,7 @@ #include "ascentkeyword.h" #include "llviewercontrol.h" +#include "llui.h" #include diff --git a/indra/newview/floaterlocalassetbrowse.cpp b/indra/newview/floaterlocalassetbrowse.cpp index 76fa162b1..c643c636d 100644 --- a/indra/newview/floaterlocalassetbrowse.cpp +++ b/indra/newview/floaterlocalassetbrowse.cpp @@ -55,7 +55,7 @@ this feature is still a work in progress. #include #include "llviewertexturelist.h" #include "llviewerobjectlist.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llviewermenufile.h" #include "llfloaterimagepreview.h" #include "llfile.h" @@ -453,23 +453,27 @@ LocalAssetBrowser::~LocalAssetBrowser() void LocalAssetBrowser::AddBitmap() { - LLFilePicker& picker = LLFilePicker::instance(); - if ( !picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE) ) - { return; } + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_IMAGE, "", "image", true); + filepicker->run(boost::bind(&LocalAssetBrowser::AddBitmap_continued, filepicker)); +} + +void LocalAssetBrowser::AddBitmap_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + return; bool change_happened = false; - std::string filename = picker.getFirstFile(); - while( !filename.empty() ) + std::vector const& filenames(filepicker->getFilenames()); + for(std::vector::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { - LocalBitmap* unit = new LocalBitmap( filename ); + LocalBitmap* unit = new LocalBitmap(*filename); if ( unit->getIfValidBool() ) { loaded_bitmaps.push_back( unit ); change_happened = true; } - - filename = picker.getNextFile(); } if ( change_happened ) diff --git a/indra/newview/floaterlocalassetbrowse.h b/indra/newview/floaterlocalassetbrowse.h index 6ee1c75a3..42620e314 100644 --- a/indra/newview/floaterlocalassetbrowse.h +++ b/indra/newview/floaterlocalassetbrowse.h @@ -169,6 +169,7 @@ class LocalBitmap */ +class AIFilePicker; class LocalAssetBrowser { @@ -181,6 +182,7 @@ class LocalAssetBrowser static void setLayerUpdated(bool toggle) { mLayerUpdated = toggle; } static void setSculptUpdated(bool toggle) { mSculptUpdated = toggle; } static void AddBitmap(void); + static void AddBitmap_continued(AIFilePicker* filepicker); static void DelBitmap( std::vector, S32 column = BITMAPLIST_COL_ID ); /* UpdateTextureCtrlList was made public cause texturectrl requests it once on spawn diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 420a9ae67..a2a4ed386 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -72,6 +72,7 @@ #include "llmutelist.h" #include "llurldispatcher.h" #include "llurlhistory.h" +#include "statemachine/aifilepicker.h" #include "llfirstuse.h" #include "llrender.h" #include "llfont.h" @@ -1353,6 +1354,9 @@ bool LLAppViewer::cleanup() // Save URL history file LLURLHistory::saveFile("url_history.xml"); + // Save file- and dirpicker {context, default paths} map. + AIFilePicker::saveFile("filepicker_contexts.xml"); + // save mute list. gMuteList used to also be deleted here too. LLMuteList::getInstance()->cache(gAgent.getID()); diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index a19ad5658..4e4bbcb43 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -98,6 +98,9 @@ static void exceptionTerminateHandler() int main( int argc, char **argv ) { + Debug(debug::init()); + Debug(libcw_do.on()); + LLMemType mt1(LLMemType::MTYPE_STARTUP); #if LL_SOLARIS && defined(__sparc) diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 042a53632..d910ab4b2 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -38,7 +38,6 @@ #include "llagent.h" #include "llcompilequeue.h" #include "llfloaterbuycurrency.h" -#include "llfilepicker.h" #include "llnotify.h" #include "llinventorymodel.h" #include "llinventoryview.h" @@ -129,7 +128,7 @@ void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason) break; } LLUploadDialog::modalUploadFinished(); - LLFilePicker::instance().reset(); // unlock file picker when bulk upload fails + //AIFIXME? LLFilePicker::instance().reset(); // unlock file picker when bulk upload fails } //virtual @@ -293,7 +292,7 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) view->getPanel()->setSelection(content["new_inventory_item"].asUUID(), TAKE_FOCUS_NO); if((LLAssetType::AT_TEXTURE == asset_type || LLAssetType::AT_SOUND == asset_type) - && LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD) + /* AIFIXME: && LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD */) { view->getPanel()->openSelected(); } @@ -309,7 +308,8 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) // remove the "Uploading..." message LLUploadDialog::modalUploadFinished(); - + +#if 0 // AIFIXME: This needs to be done in some other way. // *FIX: This is a pretty big hack. What this does is check the // file picker if there are any more pending uploads. If so, // upload that file. @@ -339,6 +339,7 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) everyone_perms, display_name, callback, expected_upload_cost, userdata); } +#endif } LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data, diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp index bba4d021c..6063995cf 100644 --- a/indra/newview/llcallbacklist.cpp +++ b/indra/newview/llcallbacklist.cpp @@ -47,7 +47,7 @@ LLCallbackList gIdleCallbacks; // Member functions // -LLCallbackList::LLCallbackList() +LLCallbackList::LLCallbackList() : mLoopingOverCallbackList(false) { // nothing } @@ -96,7 +96,15 @@ BOOL LLCallbackList::deleteFunction( callback_t func, void *data) callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t); if (iter != mCallbackList.end()) { - mCallbackList.erase(iter); + if (mLoopingOverCallbackList) + { + iter->first = NULL; // Mark for removal later (when we return to LLCallbackList::callFunctions). + mNeedErase = true; + } + else + { + mCallbackList.erase(iter); + } return TRUE; } else @@ -108,16 +116,38 @@ BOOL LLCallbackList::deleteFunction( callback_t func, void *data) void LLCallbackList::deleteAllFunctions() { + llassert(!mLoopingOverCallbackList); // Only called from unit tests. mCallbackList.clear(); } void LLCallbackList::callFunctions() { - for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) + llassert(!mLoopingOverCallbackList); + mLoopingOverCallbackList = true; + mNeedErase = false; + for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ++iter) { - callback_list_t::iterator curiter = iter++; - curiter->first(curiter->second); + if (iter->first) // Not pending removal? + { + iter->first(iter->second); // This can theorectically set any iter->first to NULL, which means the entry should be erased. + } + } + mLoopingOverCallbackList = false; + if (mNeedErase) + { + callback_list_t::iterator iter = mCallbackList.begin(); + while (iter != mCallbackList.end()) + { + if (!iter->first) + { + iter = mCallbackList.erase(iter); + } + else + { + ++iter; + } + } } } diff --git a/indra/newview/llcallbacklist.h b/indra/newview/llcallbacklist.h index be0fe9f5c..240346478 100644 --- a/indra/newview/llcallbacklist.h +++ b/indra/newview/llcallbacklist.h @@ -53,9 +53,11 @@ public: protected: // Use a list so that the callbacks are ordered in case that matters - typedef std::pair callback_pair_t; + typedef std::pair callback_pair_t; // callback_t is a (function) pointer. If it is NULL it means that the entry should be considered deleted. typedef std::list callback_list_t; callback_list_t mCallbackList; + bool mLoopingOverCallbackList; // True while looping over mCallbackList and calling the callback_t functions (see callFunctions). + bool mNeedErase; // True when deleteFunction was called while mLoopingOverCallbackList was true. }; extern LLCallbackList gIdleCallbacks; diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 27661567e..418ea1bf0 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -83,6 +83,7 @@ static struct ft_display_info ft_display_table[] = { LLFastTimer::FTM_KEYHANDLER, " Keyboard", &LLColor4::grey1, 0 }, { LLFastTimer::FTM_SLEEP, " Sleep", &LLColor4::grey2, 0 }, { LLFastTimer::FTM_IDLE, " Idle", &blue0, 0 }, + { LLFastTimer::FTM_STATEMACHINE, " State Machines", &LLColor4::yellow1, 0 }, { LLFastTimer::FTM_PUMP, " Pump", &LLColor4::magenta2, 1 }, { LLFastTimer::FTM_CURL, " Curl", &LLColor4::magenta3, 0 }, { LLFastTimer::FTM_PUMPIO, " PumpIO", &LLColor4::magenta1, 0 }, diff --git a/indra/newview/llfloaterblacklist.cpp b/indra/newview/llfloaterblacklist.cpp index e565f1434..ff76ec407 100644 --- a/indra/newview/llfloaterblacklist.cpp +++ b/indra/newview/llfloaterblacklist.cpp @@ -7,7 +7,7 @@ #include "llsdserialize.h" #include "llscrolllistctrl.h" #include "llcheckboxctrl.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llviewerwindow.h" #include "llviewercontrol.h" #include "lldate.h" @@ -241,10 +241,17 @@ void LLFloaterBlacklist::saveToDisk() //static void LLFloaterBlacklist::onClickSave(void* user_data) { - LLFilePicker& file_picker = LLFilePicker::instance(); - if(file_picker.getSaveFile( LLFilePicker::FFSAVE_BLACKLIST, LLDir::getScrubbedFileName("untitled.blacklist"))) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open("untitled.blacklist", FFSAVE_BLACKLIST); + filepicker->run(boost::bind(&LLFloaterBlacklist::onClickSave_continued, filepicker)); +} + +//static +void LLFloaterBlacklist::onClickSave_continued(AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) { - std::string file_name = file_picker.getFirstFile(); + std::string file_name = filepicker->getFilename(); llofstream export_file(file_name); LLSD data; for(std::map::iterator iter = blacklist_entries.begin(); iter != blacklist_entries.end(); ++iter) @@ -259,10 +266,16 @@ void LLFloaterBlacklist::onClickSave(void* user_data) //static void LLFloaterBlacklist::onClickLoad(void* user_data) { - LLFilePicker& file_picker = LLFilePicker::instance(); - if(file_picker.getOpenFile(LLFilePicker::FFLOAD_BLACKLIST)) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_BLACKLIST); + filepicker->run(boost::bind(&LLFloaterBlacklist::onClickLoad_continued, filepicker)); +} + +void LLFloaterBlacklist::onClickLoad_continued(AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) { - std::string file_name = file_picker.getFirstFile(); + std::string file_name = filepicker->getFilename(); llifstream xml_file(file_name); if(!xml_file.is_open()) return; LLSD data; diff --git a/indra/newview/llfloaterblacklist.h b/indra/newview/llfloaterblacklist.h index c35185721..c718fd71d 100644 --- a/indra/newview/llfloaterblacklist.h +++ b/indra/newview/llfloaterblacklist.h @@ -2,6 +2,9 @@ #ifndef LL_LLFLOATERBLACKLIST_H #define LL_LLFLOATERBLACKLIST_H #include "llfloater.h" + +class AIFilePicker; + class LLFloaterBlacklist : LLFloater { public: @@ -42,7 +45,9 @@ private: static void onClickAdd(void* user_data); static void onClickClear(void* user_data); static void onClickSave(void* user_data); + static void onClickSave_continued(AIFilePicker* filepicker); static void onClickLoad(void* user_data); + static void onClickLoad_continued(AIFilePicker* filepicker); static void onClickCopyUUID(void* user_data); static void onClickRemove(void* user_data); diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 3d1413c60..96f300cd5 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -75,7 +75,7 @@ #include "llviewercontrol.h" #include "lluictrlfactory.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "hippogridmanager.h" using namespace LLVOAvatarDefines; @@ -1850,14 +1850,20 @@ void LLFloaterCustomize::setCurrentWearableType( EWearableType type ) // reX: new function void LLFloaterCustomize::onBtnImport( void* userdata ) { - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getOpenFile( LLFilePicker::FFLOAD_XML ) ) - { - // User canceled import. - return; - } + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_XML); + filepicker->run(boost::bind(&LLFloaterCustomize::onBtnImport_continued, filepicker)); +} - const std::string filename = file_picker.getFirstFile(); +void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + { + // User canceled import. + return; + } + + const std::string filename = filepicker->getFilename(); FILE* fp = LLFile::fopen(filename, "rb"); @@ -1904,8 +1910,14 @@ void LLFloaterCustomize::onBtnImport( void* userdata ) // reX: new function void LLFloaterCustomize::onBtnExport( void* userdata ) { - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_XML ) ) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open("", FFSAVE_XML); + filepicker->run(boost::bind(&LLFloaterCustomize::onBtnExport_continued, filepicker)); +} + +void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) { // User canceled export. return; @@ -1914,7 +1926,7 @@ void LLFloaterCustomize::onBtnExport( void* userdata ) LLViewerInventoryItem* item; BOOL is_modifiable; - const std::string filename = file_picker.getFirstFile(); + const std::string filename = filepicker->getFilename(); FILE* fp = LLFile::fopen(filename, "wb"); diff --git a/indra/newview/llfloatercustomize.h b/indra/newview/llfloatercustomize.h index 1b4bed74d..1b7b57705 100644 --- a/indra/newview/llfloatercustomize.h +++ b/indra/newview/llfloatercustomize.h @@ -64,6 +64,7 @@ class LLVisualParam; class LLVisualParamReset; class LLWearableSaveAsDialog; class LLPanelEditWearable; +class AIFilePicker; ///////////////////////////////////////////////////////////////////// // LLFloaterCustomize @@ -110,7 +111,9 @@ public: static void onBtnMakeOutfit( void* userdata ); static void onMakeOutfitCommit( LLMakeOutfitDialog* dialog, void* userdata ); static void onBtnImport( void* userdata ); + static void onBtnImport_continued(AIFilePicker* filepicker); static void onBtnExport( void* userdata ); + static void onBtnExport_continued(AIFilePicker* filepicker); static void onTabChanged( void* userdata, bool from_click ); static void onTabPrecommit( void* userdata, bool from_click ); diff --git a/indra/newview/llfloaterfriends.cpp b/indra/newview/llfloaterfriends.cpp index 255547933..c210caa1c 100644 --- a/indra/newview/llfloaterfriends.cpp +++ b/indra/newview/llfloaterfriends.cpp @@ -67,7 +67,7 @@ #include "llvoiceclient.h" #include "llsdserialize.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llviewermenufile.h" #include "llviewermenu.h" @@ -1080,17 +1080,22 @@ void LLPanelFriends::onClickRemove(void* user_data) void LLPanelFriends::onClickExport(void* user_data) { - LLPanelFriends* panelp = (LLPanelFriends*)user_data; std::string agn; gAgent.getName(agn); - std::string filename = agn+".friendlist"; - LLFilePicker& picker = LLFilePicker::instance(); - if(!picker.getSaveFile( LLFilePicker::FFSAVE_ALL, filename ) ) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(agn + ".friendlist", FFSAVE_ALL); + filepicker->run(boost::bind(&LLPanelFriends::onClickExport_continued, user_data, filepicker)); +} + +void LLPanelFriends::onClickExport_continued(void* user_data, AIFilePicker* filepicker) +{ + if(!filepicker->hasFilename()) { // User canceled save. return; } - filename = picker.getFirstFile(); + std::string const filename = filepicker->getFilename(); + LLPanelFriends* panelp = (LLPanelFriends*)user_data; std::vector selected = panelp->mFriendsList->getAllData();//->getAllSelected(); LLSD llsd; @@ -1126,19 +1131,22 @@ void LLPanelFriends::onClickExport(void* user_data) bool LLPanelFriends::merging; void LLPanelFriends::onClickImport(void* user_data) +{ + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(); + filepicker->run(boost::bind(&LLPanelFriends::onClickImport_filepicker_continued, filepicker)); +} + //THIS CODE IS DESIGNED SO THAT EXP/IMP BETWEEN GRIDS WILL FAIL //because assuming someone having the same name on another grid is the same person is generally a bad idea //i might add the option to query the user as to intelligently detecting matching names on a alternative grid // jcool410 +void LLPanelFriends::onClickImport_filepicker_continued(AIFilePicker* filepicker) { - //LLPanelFriends* panelp = (LLPanelFriends*)user_data; - //is_agent_friend( - - const std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_ALL); - - if (filename.empty()) + if (!filepicker->hasFilename()) return; + std::string filename = filepicker->getFilename(); llifstream importer(filename); LLSD data; LLSDSerialize::fromXMLDocument(data, importer); diff --git a/indra/newview/llfloaterfriends.h b/indra/newview/llfloaterfriends.h index 20c996d23..e6223cfb2 100644 --- a/indra/newview/llfloaterfriends.h +++ b/indra/newview/llfloaterfriends.h @@ -45,6 +45,7 @@ class LLFriendObserver; class LLRelationship; class LLScrollListItem; class LLScrollListCtrl; +class AIFilePicker; /** * @class LLPanelFriends @@ -144,7 +145,9 @@ private: static void onClickAddFriend(void* user_data); static void onClickRemove(void* user_data); static void onClickExport(void* user_data); + static void onClickExport_continued(void* user_data, AIFilePicker* filepicker); static void onClickImport(void* user_data); + static void onClickImport_filepicker_continued(AIFilePicker* filepicker); public: static void FriendImportState(LLUUID id, bool accepted); private: diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 03f616af3..994fe3ad3 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -53,7 +53,7 @@ #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llfloaterdaycycle.h" #include "llfloatergodtools.h" // for send_sim_wide_deletes() #include "llfloatertopobjects.h" // added to fix SL-32336 @@ -1324,41 +1324,50 @@ void LLPanelRegionTerrainInfo::onChangeSunHour(LLUICtrl* ctrl, void*) // static void LLPanelRegionTerrainInfo::onClickDownloadRaw(void* data) { - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getSaveFile(LLFilePicker::FFSAVE_RAW, "terrain.raw")) + LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data; + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open("terrain.raw", FFSAVE_RAW); + filepicker->run(boost::bind(&LLPanelRegionTerrainInfo::onClickUploadRaw_continued, self, filepicker)); +} + +void LLPanelRegionTerrainInfo::onClickDownloadRaw_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) { - llwarns << "No file" << llendl; return; } - std::string filepath = picker.getFirstFile(); + std::string filepath = filepicker->getFilename(); gXferManager->expectFileForRequest(filepath); - LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data; strings_t strings; strings.push_back("download filename"); strings.push_back(filepath); LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); + sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); } // static void LLPanelRegionTerrainInfo::onClickUploadRaw(void* data) { - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getOpenFile(LLFilePicker::FFLOAD_RAW)) - { - llwarns << "No file" << llendl; + LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data; + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_RAW); + filepicker->run(boost::bind(&LLPanelRegionTerrainInfo::onClickUploadRaw_continued, self, filepicker)); +} + +void LLPanelRegionTerrainInfo::onClickUploadRaw_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) return; - } - std::string filepath = picker.getFirstFile(); + + std::string filepath = filepicker->getFilename(); gXferManager->expectFileForTransfer(filepath); - LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data; strings_t strings; strings.push_back("upload filename"); strings.push_back(filepath); LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); + sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings); LLNotifications::instance().add("RawUploadStarted"); } diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index fd0d9ce63..5871e3525 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -51,6 +51,7 @@ class LLNameListCtrl; class LLSliderCtrl; class LLSpinCtrl; class LLTextBox; +class AIFilePicker; class LLPanelRegionGeneralInfo; class LLPanelRegionDebugInfo; @@ -242,7 +243,9 @@ protected: static void onChangeSunHour(LLUICtrl* ctrl, void*); static void onClickDownloadRaw(void*); + void onClickDownloadRaw_continued(AIFilePicker* filepicker); static void onClickUploadRaw(void*); + void onClickUploadRaw_continued(AIFilePicker* filepicker); static void onClickBakeTerrain(void*); bool callbackBakeTerrain(const LLSD& notification, const LLSD& response); }; diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 6e524a05f..72720692f 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -76,7 +76,6 @@ #include "llviewerwindow.h" #include "llviewertexturelist.h" #include "llworldmap.h" -#include "llfilepicker.h" #include "llfloateravatarpicker.h" #include "lldir.h" #include "llselectmgr.h" diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 5af0de858..2f9539fd1 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -149,7 +149,7 @@ public: void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f); LLFloaterPostcard* savePostcard(); void saveTexture(); - BOOL saveLocal(); + void saveLocal(); BOOL setThumbnailImageSize() ; void generateThumbnailImage(BOOL force_update = FALSE) ; @@ -1005,20 +1005,14 @@ void LLSnapshotLivePreview::saveTexture() mDataSize = 0; } -BOOL LLSnapshotLivePreview::saveLocal() +void LLSnapshotLivePreview::saveLocal() { - BOOL success = gViewerWindow->saveImageNumbered(mFormattedImage); + gViewerWindow->saveImageNumbered(mFormattedImage); // Relinquish image memory. Save button will be disabled as a side-effect. mFormattedImage = NULL; mDataSize = 0; updateSnapshot(FALSE, FALSE); - - if(success) - { - gViewerWindow->playSnapshotAnimAndSound(); - } - return success; } ///---------------------------------------------------------------------------- @@ -1410,7 +1404,7 @@ void LLFloaterSnapshot::Impl::onClickDiscard(void* data) // static void LLFloaterSnapshot::Impl::onCommitSave(LLUICtrl* ctrl, void* data) { - if (ctrl->getValue().asString() == "save as") + if (ctrl->getValue().asString() == "saveas") { gViewerWindow->resetSnapshotLoc(); } diff --git a/indra/newview/llfloatervfs.cpp b/indra/newview/llfloatervfs.cpp index 2db5b3459..0192e76b9 100644 --- a/indra/newview/llfloatervfs.cpp +++ b/indra/newview/llfloatervfs.cpp @@ -4,7 +4,7 @@ #include "lluictrlfactory.h" #include "llscrolllistctrl.h" #include "llcheckboxctrl.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "lllocalinventory.h" #include "llviewerwindow.h" #include "llassetconverter.h" @@ -229,25 +229,32 @@ void LLFloaterVFS::setEditEnabled(bool enabled) childSetEnabled("reload_btn", enabled); // WORKS! childSetEnabled("remove_btn", enabled); } + // static void LLFloaterVFS::onClickAdd(void* user_data) { - LLFloaterVFS* floaterp = (LLFloaterVFS*)user_data; - if(!floaterp) return; - LLUUID asset_id; - LLAssetType::EType asset_type = LLAssetType::AT_NONE; - asset_id.generate(); - LLFilePicker& file_picker = LLFilePicker::instance(); - if(file_picker.getOpenFile(LLFilePicker::FFLOAD_ALL)) + if(!user_data) return; + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(); + filepicker->run(boost::bind(&LLFloaterVFS::onClickAdd_continued, user_data, filepicker)); +} + +// static +void LLFloaterVFS::onClickAdd_continued(void* user_data, AIFilePicker* filepicker) +{ + LLFloaterVFS* self = (LLFloaterVFS*)user_data; + if (filepicker->hasFilename()) { - std::string file_name = file_picker.getFirstFile(); + std::string file_name = filepicker->getFilename(); std::string temp_filename = file_name + ".tmp"; - asset_type = LLAssetConverter::convert(file_name, temp_filename); + LLAssetType::EType asset_type = LLAssetConverter::convert(file_name, temp_filename); if(asset_type == LLAssetType::AT_NONE) { // todo: show a warning return; } + LLUUID asset_id; + asset_id.generate(); S32 file_size; LLAPRFile fp; fp.open(temp_filename, LL_APR_RB, LLAPRFile::global, &file_size); @@ -302,8 +309,8 @@ void LLFloaterVFS::onClickAdd(void* user_data) file.mID = asset_id; file.mType = asset_type; file.mName = gDirUtilp->getBaseFileName(file_name, true); - floaterp->add(file); - /*if(floaterp->getChild("create_pretend_item")->get()) + self->add(file); + /*if(self->getChild("create_pretend_item")->get()) { LLLocalInventory::addItem(file.mName, (int)file.mType, file.mID, true); }*/ diff --git a/indra/newview/llfloatervfs.h b/indra/newview/llfloatervfs.h index 7218b1090..47d1d8755 100644 --- a/indra/newview/llfloatervfs.h +++ b/indra/newview/llfloatervfs.h @@ -3,6 +3,9 @@ #define LL_LLFLOATERVFS_H #include "llfloater.h" #include "llassettype.h" + +class AIFilePicker; + class LLFloaterVFS : LLFloater { typedef struct @@ -27,6 +30,7 @@ public: void reloadEntry(entry file); void removeEntry(); static void onClickAdd(void* user_data); + static void onClickAdd_continued(void* user_data, AIFilePicker* filepicker); static void onClickClear(void* user_data); static void onClickReloadAll(void* user_data); static void onCommitFileList(LLUICtrl* ctrl, void* user_data); diff --git a/indra/newview/llfloatervfsexplorer.cpp b/indra/newview/llfloatervfsexplorer.cpp index 6f6384a37..99662b9d9 100644 --- a/indra/newview/llfloatervfsexplorer.cpp +++ b/indra/newview/llfloatervfsexplorer.cpp @@ -5,7 +5,6 @@ #include "lluictrlfactory.h" #include "llscrolllistctrl.h" #include "llcheckboxctrl.h" -#include "llfilepicker.h" #include "llvfs.h" #include "lllocalinventory.h" #include "llviewerwindow.h" diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index b770a531d..8b04a1744 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -91,6 +91,7 @@ #include "llinventorybackup.h" //#include "llcheats.h" //#include "llnotecardmagic.h" +#include "statemachine/aifilepicker.h" // const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not) @@ -569,14 +570,19 @@ class LLLoadInvCacheFloater : public inventory_listener_t { LLInventoryModel* model = mPtr->getPanel()->getModel(); if(!model) return false; - LLFilePicker& file_picker = LLFilePicker::instance(); - if(file_picker.getOpenFile( LLFilePicker::FFLOAD_INVGZ )) - { - std::string file_name = file_picker.getFirstFile(); - LLLocalInventory::loadInvCache(file_name); - } + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_INVGZ, "", "invgz"); + filepicker->run(boost::bind(&LLLoadInvCacheFloater::filepicker_callback, this, filepicker)); return true; } + + void filepicker_callback(AIFilePicker* filepicker) + { + if(filepicker->hasFilename()) + { + LLLocalInventory::loadInvCache(filepicker->getFilename()); + } + } }; class LLRefreshInvModel : public inventory_listener_t diff --git a/indra/newview/llinventorybackup.cpp b/indra/newview/llinventorybackup.cpp index a5ce38e59..416c82065 100644 --- a/indra/newview/llinventorybackup.cpp +++ b/indra/newview/llinventorybackup.cpp @@ -4,8 +4,8 @@ #include "llinventorybackup.h" #include "llinventorymodel.h" #include "llviewerinventory.h" -#include "llfilepicker.h" -#include "lldirpicker.h" +#include "statemachine/aifilepicker.h" +#include "statemachine/aidirpicker.h" #include "llviewertexturelist.h" // gTextureList #include "llagent.h" // gAgent #include "llviewerwindow.h" // gViewerWindow @@ -120,36 +120,41 @@ void LLFloaterInventoryBackupSettings::onClickNext(void* userdata) } // Get dir name - LLDirPicker& picker = LLDirPicker::instance(); - std::string filename = "New Folder"; - if (!picker.getDir(&filename)) + AIDirPicker* dirpicker = new AIDirPicker("New Folder"); + dirpicker->run(boost::bind(&LLFloaterInventoryBackupSettings::onClickNext_continued, userdata, dirpicker)); +} + +// static +void LLFloaterInventoryBackupSettings::onClickNext_continued(void* userdata, AIDirPicker* dirpicker) +{ + LLFloaterInventoryBackupSettings* floater = (LLFloaterInventoryBackupSettings*)userdata; + LLInventoryBackupOrder* order = floater->mOrder; + + if (!dirpicker->hasDirname()) { floater->close(); return; } - filename = picker.getDirName(); + std::string dirname = dirpicker->getDirname(); // Make local directory tree - LLFile::mkdir(filename); + LLFile::mkdir(dirname); std::vector::iterator _cat_iter = order->mCats.begin(); std::vector::iterator _cat_end = order->mCats.end(); for( ; _cat_iter != _cat_end; ++_cat_iter) { - std::string path = filename + OS_SEP + LLInventoryBackup::getPath(*_cat_iter, order->mCats); + std::string path = dirname + OS_SEP + LLInventoryBackup::getPath(*_cat_iter, order->mCats); LLFile::mkdir(path); } // Go go backup floater - LLFloaterInventoryBackup* backup_floater = new LLFloaterInventoryBackup(filename, order->mCats, order->mItems); + LLFloaterInventoryBackup* backup_floater = new LLFloaterInventoryBackup(dirname, order->mCats, order->mItems); backup_floater->center(); // Close myself floater->close(); } - - - // static bool LLInventoryBackup::itemIsFolder(LLInventoryItem* item) { @@ -158,64 +163,64 @@ bool LLInventoryBackup::itemIsFolder(LLInventoryItem* item) } // static -LLFilePicker::ESaveFilter LLInventoryBackup::getSaveFilter(LLInventoryItem* item) +ESaveFilter LLInventoryBackup::getSaveFilter(LLInventoryItem* item) { LLAssetType::EType type = item->getType(); EWearableType wear = (EWearableType)(item->getFlags() & 0xFF); switch(type) { case LLAssetType::AT_TEXTURE: - return LLFilePicker::FFSAVE_TGA; + return FFSAVE_TGA; case LLAssetType::AT_SOUND: - return LLFilePicker::FFSAVE_OGG; + return FFSAVE_OGG; case LLAssetType::AT_SCRIPT: case LLAssetType::AT_LSL_TEXT: - return LLFilePicker::FFSAVE_LSL; + return FFSAVE_LSL; case LLAssetType::AT_ANIMATION: - return LLFilePicker::FFSAVE_ANIMATN; + return FFSAVE_ANIMATN; case LLAssetType::AT_GESTURE: - return LLFilePicker::FFSAVE_GESTURE; + return FFSAVE_GESTURE; case LLAssetType::AT_NOTECARD: - return LLFilePicker::FFSAVE_NOTECARD; + return FFSAVE_NOTECARD; case LLAssetType::AT_LANDMARK: - return LLFilePicker::FFSAVE_LANDMARK; + return FFSAVE_LANDMARK; case LLAssetType::AT_BODYPART: case LLAssetType::AT_CLOTHING: switch(wear) { case WT_EYES: - return LLFilePicker::FFSAVE_EYES; + return FFSAVE_EYES; case WT_GLOVES: - return LLFilePicker::FFSAVE_GLOVES; + return FFSAVE_GLOVES; case WT_HAIR: - return LLFilePicker::FFSAVE_HAIR; + return FFSAVE_HAIR; case WT_JACKET: - return LLFilePicker::FFSAVE_JACKET; + return FFSAVE_JACKET; case WT_PANTS: - return LLFilePicker::FFSAVE_PANTS; + return FFSAVE_PANTS; case WT_SHAPE: - return LLFilePicker::FFSAVE_SHAPE; + return FFSAVE_SHAPE; case WT_SHIRT: - return LLFilePicker::FFSAVE_SHIRT; + return FFSAVE_SHIRT; case WT_SHOES: - return LLFilePicker::FFSAVE_SHOES; + return FFSAVE_SHOES; case WT_SKIN: - return LLFilePicker::FFSAVE_SKIN; + return FFSAVE_SKIN; case WT_SKIRT: - return LLFilePicker::FFSAVE_SKIRT; + return FFSAVE_SKIRT; case WT_SOCKS: - return LLFilePicker::FFSAVE_SOCKS; + return FFSAVE_SOCKS; case WT_UNDERPANTS: - return LLFilePicker::FFSAVE_UNDERPANTS; + return FFSAVE_UNDERPANTS; case WT_UNDERSHIRT: - return LLFilePicker::FFSAVE_UNDERSHIRT; + return FFSAVE_UNDERSHIRT; case WT_PHYSICS: - return LLFilePicker::FFSAVE_PHYSICS; + return FFSAVE_PHYSICS; default: - return LLFilePicker::FFSAVE_ALL; + return FFSAVE_ALL; } default: - return LLFilePicker::FFSAVE_ALL; + return FFSAVE_ALL; } } @@ -352,28 +357,9 @@ void LLInventoryBackup::imageCallback(BOOL success, return; } - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( getSaveFilter(item), LLDir::getScrubbedFileName(item->getName())) ) - { - // User canceled or we failed to acquire save file. - return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); - - LLPointer image_tga = new LLImageTGA; - if( !image_tga->encode( src ) ) - { - LLSD args; - args["ERROR_MESSAGE"] = "Couldn't encode file."; - LLNotifications::instance().add("ErrorMessage", args); - } - else if( !image_tga->save( filename ) ) - { - LLSD args; - args["ERROR_MESSAGE"] = "Couldn't write file."; - LLNotifications::instance().add("ErrorMessage", args); - } + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(LLDir::getScrubbedFileName(item->getName()), getSaveFilter(item)); + filepicker->run(boost::bind(&LLInventoryBackup::imageCallback_continued, src, filepicker)); } else { @@ -381,6 +367,28 @@ void LLInventoryBackup::imageCallback(BOOL success, } } +void LLInventoryBackup::imageCallback_continued(LLImageRaw* src, AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + return; + + std::string filename = filepicker->getFilename(); + + LLPointer image_tga = new LLImageTGA; + if( !image_tga->encode( src ) ) + { + LLSD args; + args["ERROR_MESSAGE"] = "Couldn't encode file."; + LLNotifications::instance().add("ErrorMessage", args); + } + else if( !image_tga->save( filename ) ) + { + LLSD args; + args["ERROR_MESSAGE"] = "Couldn't write file."; + LLNotifications::instance().add("ErrorMessage", args); + } +} + // static void LLInventoryBackup::assetCallback(LLVFS *vfs, const LLUUID& asset_uuid, @@ -402,7 +410,7 @@ void LLInventoryBackup::assetCallback(LLVFS *vfs, LLVFile file(vfs, asset_uuid, type, LLVFile::READ); S32 size = file.getSize(); - char* buffer = new char[size]; + char* buffer = new char[size]; // Deleted in assetCallback_continued. if (buffer == NULL) { llerrs << "Memory Allocation Failed" << llendl; @@ -413,18 +421,22 @@ void LLInventoryBackup::assetCallback(LLVFS *vfs, // Write it back out... - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( getSaveFilter(item), LLDir::getScrubbedFileName(item->getName())) ) - { - // User canceled or we failed to acquire save file. - return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(LLDir::getScrubbedFileName(item->getName()), getSaveFilter(item)); + filepicker->run(boost::bind(&LLInventoryBackup::assetCallback_continued, buffer, size, filepicker)); +} - std::ofstream export_file(filename.c_str(), std::ofstream::binary); - export_file.write(buffer, size); - export_file.close(); +// static +void LLInventoryBackup::assetCallback_continued(char* buffer, S32 size, AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) + { + std::string filename = filepicker->getFilename(); + std::ofstream export_file(filename.c_str(), std::ofstream::binary); + export_file.write(buffer, size); + export_file.close(); + } + delete [] buffer; } // static diff --git a/indra/newview/llinventorybackup.h b/indra/newview/llinventorybackup.h index 98664a9a5..2ee0c197c 100644 --- a/indra/newview/llinventorybackup.h +++ b/indra/newview/llinventorybackup.h @@ -11,10 +11,11 @@ #include "llviewerinventory.h" #include "llfolderview.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llviewertexture.h" #include "llfloater.h" +class AIDirPicker; class LLInventoryBackupOrder { @@ -45,6 +46,7 @@ public: LLFloaterInventoryBackupSettings(LLInventoryBackupOrder* order); BOOL postBuild(void); static void onClickNext(void* userdata); + static void onClickNext_continued(void* userdata, AIDirPicker* dirpicker); LLInventoryBackupOrder* mOrder; virtual ~LLFloaterInventoryBackupSettings(); @@ -94,10 +96,12 @@ private: }; +class AIFilePicker; + class LLInventoryBackup { public: - static LLFilePicker::ESaveFilter getSaveFilter(LLInventoryItem* item); + static ESaveFilter getSaveFilter(LLInventoryItem* item); static std::string getExtension(LLInventoryItem* item); static std::string getUniqueFilename(std::string filename, std::string extension); static std::string getUniqueDirname(std::string dirname); @@ -120,10 +124,12 @@ private: S32 discard_level, BOOL final, void* userdata); + static void imageCallback_continued(LLImageRaw* src, AIFilePicker* filepicker); static void assetCallback(LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); + static void assetCallback_continued(char* buffer, S32 size, AIFilePicker* filepicker); static void climb(LLInventoryCategory* cat, std::vector& cats, std::vector& items); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 3455caf19..aa6dc78d5 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -99,6 +99,7 @@ //#include "llcheats.h" #include "dofloaterhex.h" #include "hgfloatertexteditor.h" +#include "statemachine/aifilepicker.h" // // Editing wearables from inventory is an include-hungry feature -.- -SG @@ -1106,30 +1107,26 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, else if("reupload" == action) { LLInventoryItem* item = model->getItem(mUUID); - if(!item) return; - - LLFilePicker& picker = LLFilePicker::instance(); - std::string filename; - - switch(item->getType()) + if (item && item->getType() == LLAssetType::AT_TEXTURE) { - case LLAssetType::AT_TEXTURE: - if(!picker.getOpenFile(LLFilePicker::FFLOAD_IMAGE)) - return; - filename = picker.getFirstFile(); - if(!filename.empty()) - { - LLFloaterImagePreview* floaterp = new LLFloaterImagePreview(filename, item); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_image_preview.xml"); - } - break; - default: - break; + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_IMAGE, "", "image"); + filepicker->run(boost::bind(&LLItemBridge::showFloaterImagePreview, item, filepicker)); } } // } +// static +void LLItemBridge::showFloaterImagePreview(LLInventoryItem* item, AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) + { + LLFloaterImagePreview* floaterp = new LLFloaterImagePreview(filepicker->getFilename(), item); + LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_image_preview.xml"); + } +} + void LLItemBridge::selectItem() { LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem(); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index a3108d653..2a668e684 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -277,6 +277,7 @@ protected: LLInventoryType::EType mInvType; }; +class AIFilePicker; class LLItemBridge : public LLInvFVBridge { @@ -303,7 +304,7 @@ public: virtual BOOL hasChildren() const { return FALSE; } virtual BOOL isUpToDate() const { return TRUE; } - + static void showFloaterImagePreview(LLInventoryItem* item, AIFilePicker* filepicker); // override for LLInvFVBridge virtual void clearDisplayName() { mDisplayName.clear(); } diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index f185fb9b9..bbf2dfa01 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -34,7 +34,7 @@ #define LL_LLMediaCtrl_H #include "llviewermedia.h" - +#include "llviewermediaobserver.h" #include "lluictrl.h" #include "llframetimer.h" #include "lldynamictexture.h" diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 52e812924..9a3add526 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -1213,20 +1213,27 @@ void LLPanelAvatarPicks::onClickNew(void* data) } //Pick import and export - RK +// static void LLPanelAvatarPicks::onClickImport(void* data) { LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; - LLPanelPick* panel_pick = new LLPanelPick(FALSE); - LLTabContainer* tabs = self->getChild("picks tab"); + self->mPanelPick = new LLPanelPick(FALSE); + self->mPanelPick->importNewPick(&LLPanelAvatarPicks::onClickImport_continued, data); +} - bool import = panel_pick->importNewPick(); - if(tabs && import) +// static +void LLPanelAvatarPicks::onClickImport_continued(void* data, bool import) +{ + LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; + LLTabContainer* tabs = self->getChild("picks tab"); + if(tabs && import && self->mPanelPick) { - tabs->addTabPanel(panel_pick, panel_pick->getPickName()); + tabs->addTabPanel(self->mPanelPick, self->mPanelPick->getPickName()); tabs->selectLastTab(); } } +// static void LLPanelAvatarPicks::onClickExport(void* data) { LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 24de55cb5..812da4571 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -57,6 +57,7 @@ class LLViewerObject; class LLMessageSystem; class LLIconCtrl; class LLMediaCtrl; +class LLPanelPick; enum EOnlineStatus { @@ -265,9 +266,13 @@ private: //Pick import and export - RK static void onClickImport(void* data); + static void onClickImport_continued(void* self, bool import); static void onClickExport(void* data); bool callbackDelete(const LLSD& notification, const LLSD& response); + + // Used to pass it from onClickImport to onClickImport_continued. + LLPanelPick* mPanelPick; }; diff --git a/indra/newview/llpanelnetwork.cpp b/indra/newview/llpanelnetwork.cpp index 6e66628eb..6bc34989a 100644 --- a/indra/newview/llpanelnetwork.cpp +++ b/indra/newview/llpanelnetwork.cpp @@ -39,7 +39,7 @@ // project includes #include "llcheckboxctrl.h" #include "llradiogroup.h" -#include "lldirpicker.h" +#include "statemachine/aidirpicker.h" #include "lluictrlfactory.h" #include "llviewercontrol.h" #include "llviewerwindow.h" @@ -151,18 +151,24 @@ void LLPanelNetwork::onClickClearCache(void*) // static void LLPanelNetwork::onClickSetCache(void* user_data) { - LLPanelNetwork* self = (LLPanelNetwork*)user_data; - std::string cur_name(gSavedSettings.getString("CacheLocation")); std::string proposed_name(cur_name); - LLDirPicker& picker = LLDirPicker::instance(); - if (! picker.getDir(&proposed_name ) ) + AIDirPicker* dirpicker = new AIDirPicker(proposed_name, "cachelocation"); + dirpicker->run(boost::bind(&LLPanelNetwork::onClickSetCache_continued, user_data, dirpicker)); +} + +// static +void LLPanelNetwork::onClickSetCache_continued(void* user_data, AIDirPicker* dirpicker) +{ + if (!dirpicker->hasDirname()) { return; //Canceled! } - std::string dir_name = picker.getDirName(); + LLPanelNetwork* self = (LLPanelNetwork*)user_data; + std::string cur_name(gSavedSettings.getString("CacheLocation")); + std::string dir_name = dirpicker->getDirname(); if (!dir_name.empty() && dir_name != cur_name) { self->childSetText("cache_location", dir_name); diff --git a/indra/newview/llpanelnetwork.h b/indra/newview/llpanelnetwork.h index a5e2269a4..30dc471e6 100644 --- a/indra/newview/llpanelnetwork.h +++ b/indra/newview/llpanelnetwork.h @@ -35,6 +35,8 @@ #include "llpanel.h" +class AIDirPicker; + class LLPanelNetwork : public LLPanel { public: @@ -49,6 +51,7 @@ public: private: static void onClickClearCache(void*); static void onClickSetCache(void*); + static void onClickSetCache_continued(void* user_data, AIDirPicker* dirpicker); static void onClickResetCache(void*); static void onCommitPort(LLUICtrl* ctrl, void*); static void onCommitSocks5ProxyEnabled(LLUICtrl* ctrl, void* data); diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp index c7f31f1f9..9af829e9b 100644 --- a/indra/newview/llpanelpick.cpp +++ b/indra/newview/llpanelpick.cpp @@ -66,7 +66,7 @@ //For pick import and export - RK -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llviewernetwork.h" #include "llsdserialize.h" #include "hippogridmanager.h" @@ -201,14 +201,19 @@ void LLPanelPick::initNewPick() } //Imports a new pick from an xml - RK -bool LLPanelPick::importNewPick() +void LLPanelPick::importNewPick(void (*callback)(void*, bool), void* data) { - LLFilePicker& file_picker = LLFilePicker::instance(); + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_XML, "", "export"); + filepicker->run(boost::bind(&LLPanelPick::importNewPick_continued, this, callback, data, filepicker)); +} - if(!file_picker.getOpenFile(LLFilePicker::FFLOAD_XML)) return false;// User canceled load. - else +void LLPanelPick::importNewPick_continued(void (*callback)(void*, bool), void* data, AIFilePicker* filepicker) +{ + bool result = false; + if (filepicker->hasFilename()) { - std::string file = file_picker.getFirstFile(); + std::string file = filepicker->getFilename(); llifstream importer(file); LLSD data; @@ -231,19 +236,25 @@ bool LLPanelPick::importNewPick() mImporting = true; sendPickInfoUpdate(); - return true; + result = true; } + (*callback)(data, result); } //Exports a pick to an XML - RK void LLPanelPick::exportPick() { - LLFilePicker& file_picker = LLFilePicker::instance(); - - if(!file_picker.getSaveFile(LLFilePicker::FFSAVE_XML)) - return;// User canceled save. + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open("", FFSAVE_XML, "", "export"); + filepicker->run(boost::bind(&LLPanelPick::exportPick_continued, this, filepicker)); +} - std::string destination = file_picker.getFirstFile(); +void LLPanelPick::exportPick_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + return; + + std::string destination = filepicker->getFilename(); LLSD datas; diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h index 49b07924c..bfa702251 100644 --- a/indra/newview/llpanelpick.h +++ b/indra/newview/llpanelpick.h @@ -50,6 +50,7 @@ class LLTextEditor; class LLTextureCtrl; class LLUICtrl; class LLMessageSystem; +class AIFilePicker; class LLPanelPick : public LLPanel { @@ -70,8 +71,10 @@ public: void initNewPick(); //Pick import and export - RK - bool importNewPick(); + void importNewPick(void (*callback)(void*, bool), void* data); + void importNewPick_continued(void (*callback)(void*, bool), void* data, AIFilePicker* filepicker); void exportPick(); + void exportPick_continued(AIFilePicker* filepicker); // We need to know the creator id so the database knows which partition // to query for the pick data. diff --git a/indra/newview/llprefsim.cpp b/indra/newview/llprefsim.cpp index 8c1f71b4b..62dc37726 100644 --- a/indra/newview/llprefsim.cpp +++ b/indra/newview/llprefsim.cpp @@ -45,7 +45,7 @@ #include "llviewernetwork.h" #include "lluictrlfactory.h" -#include "lldirpicker.h" +#include "statemachine/aidirpicker.h" #include "hippogridmanager.h" @@ -53,6 +53,8 @@ #include "rlvhandler.h" // [/RLVa:KB] +class AIDirPicker; + class LLPrefsIMImpl : public LLPanel { public: @@ -67,6 +69,7 @@ public: void enableHistory(); static void onClickLogPath(void* user_data); + static void onClickLogPath_continued(void* user_data, AIDirPicker* dirpicker); static void onCommitLogging(LLUICtrl* ctrl, void* user_data); protected: @@ -301,13 +304,20 @@ void LLPrefsIMImpl::onClickLogPath(void* user_data) std::string proposed_name(self->childGetText("log_path_string")); - LLDirPicker& picker = LLDirPicker::instance(); - if (!picker.getDir(&proposed_name ) ) + AIDirPicker* dirpicker = new AIDirPicker(proposed_name); + dirpicker->run(boost::bind(&LLPrefsIMImpl::onClickLogPath_continued, user_data, dirpicker)); +} + +// static +void LLPrefsIMImpl::onClickLogPath_continued(void* user_data, AIDirPicker* dirpicker) +{ + if (!dirpicker->hasDirname()) { return; //Canceled! } - self->childSetText("log_path_string", picker.getDirName()); + LLPrefsIMImpl* self=(LLPrefsIMImpl*)user_data; + self->childSetText("log_path_string", dirpicker->getDirname()); } diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index f9cb5f210..85349883b 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -40,7 +40,7 @@ #include "llvoavatar.h" #include "llagent.h" // gAgent #include "llkeyframemotion.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "lllineeditor.h" #include "lluictrlfactory.h" #include "lluictrlfactory.h" @@ -392,21 +392,22 @@ void LLPreviewAnim::gotAssetForSave(LLVFS *vfs, // Write it back out... - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_ANIMATN, LLDir::getScrubbedFileName(self->getItem()->getName())) ) - { - // User canceled or we failed to acquire save file. - return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(LLDir::getScrubbedFileName(self->getItem()->getName()) + ".animatn", FFSAVE_ANIMATN); + filepicker->run(boost::bind(&LLPreviewAnim::gotAssetForSave_continued, buffer, size, filepicker)); +} - std::ofstream export_file(filename.c_str(), std::ofstream::binary); - export_file.write(buffer, size); - export_file.close(); - +// static +void LLPreviewAnim::gotAssetForSave_continued(char* buffer, S32 size, AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + { + std::string filename = filepicker->getFilename(); + std::ofstream export_file(filename.c_str(), std::ofstream::binary); + export_file.write(buffer, size); + export_file.close(); + } delete[] buffer; - buffer = NULL; } // virtual diff --git a/indra/newview/llpreviewanim.h b/indra/newview/llpreviewanim.h index 115419fb6..3b9c53025 100644 --- a/indra/newview/llpreviewanim.h +++ b/indra/newview/llpreviewanim.h @@ -36,6 +36,8 @@ #include "llpreview.h" #include "llcharacter.h" +class AIFilePicker; + class LLPreviewAnim : public LLPreview { public: @@ -59,6 +61,7 @@ public: const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); + static void gotAssetForSave_continued(char* buffer, S32 size, AIFilePicker* filepicker); static void copyAnimID(void* userdata); // static void endAnimCallback( void *userdata ); diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index c2c3e8869..6acdc32ba 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -61,7 +61,7 @@ #include "lllineeditor.h" #include "lluictrlfactory.h" // -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" // ///---------------------------------------------------------------------------- @@ -717,17 +717,18 @@ void LLPreviewNotecard::saveAs() if(item) { // gAssetStorage->getAssetData(item->getAssetUUID(), LLAssetType::AT_NOTECARD, LLPreviewNotecard::gotAssetForSave, this, TRUE); - default_filename = LLDir::getScrubbedFileName(item->getName()); + default_filename = LLDir::getScrubbedFileName(item->getName()) + ".notecard"; } - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_NOTECARD, default_filename ) ) - { - // User canceled or we failed to acquire save file. + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(default_filename, FFSAVE_NOTECARD); + filepicker->run(boost::bind(&LLPreviewNotecard::saveAs_continued, this, filepicker)); +} + +void LLPreviewNotecard::saveAs_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); LLViewerTextEditor* editor = getChild("Notecard Editor"); @@ -738,8 +739,9 @@ void LLPreviewNotecard::saveAs() return; } - S32 size = buffer.length() + 1; + S32 size = buffer.length(); + std::string filename = filepicker->getFilename(); std::ofstream export_file(filename.c_str(), std::ofstream::binary); export_file.write(buffer.c_str(), size); export_file.close(); diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index c3bf0e2f9..04568bf65 100644 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -46,6 +46,7 @@ class LLTextEditor; class LLViewerTextEditor; class LLButton; +class AIFilePicker; class LLPreviewNotecard : public LLPreview { @@ -128,6 +129,7 @@ protected: // virtual BOOL canSaveAs() const; virtual void saveAs(); + void saveAs_continued(AIFilePicker* filepicker); // }; diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 7b6bab72e..a58f1180e 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -54,6 +54,7 @@ #include "lltextbox.h" #include "lltooldraganddrop.h" #include "llvfile.h" +#include "statemachine/aifilepicker.h" #include "llagent.h" #include "llnotify.h" @@ -1700,23 +1701,23 @@ void LLPreviewLSL::saveAs() const LLInventoryItem *item = getItem(); if(item) { - default_filename = LLDir::getScrubbedFileName(item->getName()); + default_filename = LLDir::getScrubbedFileName(item->getName()) + ".lsl"; } - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_LSL, default_filename ) ) - { - // User canceled or we failed to acquire save file. + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(default_filename, FFSAVE_LSL); + filepicker->run(boost::bind(&LLPreviewLSL::saveAs_continued, this, filepicker)); +} + +void LLPreviewLSL::saveAs_continued(AIFilePicker* filepicker) +{ + if(!filepicker->hasFilename()) return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); std::string utf8text = mScriptEd->mEditor->getText(); - LLFILE* fp = LLFile::fopen(filename, "wb"); + LLFILE* fp = LLFile::fopen(filepicker->getFilename(), "wb"); fputs(utf8text.c_str(), fp); fclose(fp); - fp = NULL; } // /// --------------------------------------------------------------------------- @@ -2654,19 +2655,19 @@ void LLLiveLSLEditor::saveAs() default_filename = LLDir::getScrubbedFileName(item->getName()); } - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_LSL, default_filename ) ) - { - // User canceled or we failed to acquire save file. + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(default_filename, FFSAVE_LSL); + filepicker->run(boost::bind(&LLLiveLSLEditor::saveAs_continued, this, filepicker)); +} + +void LLLiveLSLEditor::saveAs_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); std::string utf8text = mScriptEd->mEditor->getText(); - LLFILE* fp = LLFile::fopen(filename, "wb"); + LLFILE* fp = LLFile::fopen(filepicker->getFilename(), "wb"); fputs(utf8text.c_str(), fp); fclose(fp); - fp = NULL; } // diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 58959e445..aa03a6c2e 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -53,6 +53,7 @@ struct LLEntryAndEdCore; class LLMenuBarGL; class LLFloaterScriptSearch; class LLKeywordToken; +class AIFilePicker; // Inner, implementation class. LLPreviewScript and LLLiveLSLEditor each own one of these. class LLScriptEdCore : public LLPanel, public LLEventTimer @@ -189,6 +190,7 @@ protected: // virtual BOOL canSaveAs() const; virtual void saveAs(); + void saveAs_continued(AIFilePicker* filepicker); // static void onSearchReplace(void* userdata); @@ -261,6 +263,7 @@ protected: // virtual BOOL canSaveAs() const; virtual void saveAs(); + void saveAs_continued(AIFilePicker* filepicker); // static void onSearchReplace(void* userdata); diff --git a/indra/newview/llpreviewsound.cpp b/indra/newview/llpreviewsound.cpp index e40dddbd2..890979578 100644 --- a/indra/newview/llpreviewsound.cpp +++ b/indra/newview/llpreviewsound.cpp @@ -48,7 +48,7 @@ #include "llchat.h" #include "llfloaterchat.h" #include "llviewerwindow.h" // for alert -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" // for ambient play: #include "llviewerregion.h" // @@ -330,18 +330,22 @@ void LLPreviewSound::gotAssetForSave(LLVFS *vfs, // Write it back out... - LLFilePicker& file_picker = LLFilePicker::instance(); - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_OGG, LLDir::getScrubbedFileName(self->getItem()->getName())) ) - { - // User canceled or we failed to acquire save file. - return; - } - // remember the user-approved/edited file name. - std::string filename = file_picker.getFirstFile(); + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(LLDir::getScrubbedFileName(self->getItem()->getName()) + ".ogg", FFSAVE_OGG); + filepicker->run(boost::bind(&LLPreviewSound::gotAssetForSave_continued, buffer, size, filepicker)); +} - std::ofstream export_file(filename.c_str(), std::ofstream::binary); - export_file.write(buffer, size); - export_file.close(); +// static +void LLPreviewSound::gotAssetForSave_continued(char* buffer, S32 size, AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) + { + std::string filename = filepicker->getFilename(); + std::ofstream export_file(filename.c_str(), std::ofstream::binary); + export_file.write(buffer, size); + export_file.close(); + } + delete [] buffer; } // virtual diff --git a/indra/newview/llpreviewsound.h b/indra/newview/llpreviewsound.h index 535b233c9..bd8b9c0f0 100644 --- a/indra/newview/llpreviewsound.h +++ b/indra/newview/llpreviewsound.h @@ -35,6 +35,8 @@ #include "llpreview.h" +class AIFilePicker; + class LLPreviewSound : public LLPreview { public: @@ -59,6 +61,7 @@ public: const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); + static void gotAssetForSave_continued(char* buffer, S32 size, AIFilePicker* filepicker); // protected: diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 8eb803401..2e52f3d47 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -37,7 +37,7 @@ #include "llagent.h" #include "llbutton.h" #include "llcombobox.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llimagetga.h" #include "llinventoryview.h" #include "llinventory.h" @@ -380,15 +380,19 @@ void LLPreviewTexture::saveAs() if( mLoadingFullImage ) return; - LLFilePicker& file_picker = LLFilePicker::instance(); const LLViewerInventoryItem* item = getItem() ; - if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_TGA, item ? LLDir::getScrubbedFileName(item->getName()) : LLStringUtil::null) ) - { - // User canceled or we failed to acquire save file. + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(item ? LLDir::getScrubbedFileName(item->getName()) + ".tga" : LLStringUtil::null, FFSAVE_TGA, "", "image"); + filepicker->run(boost::bind(&LLPreviewTexture::saveAs_continued, this, item, filepicker)); +} + +void LLPreviewTexture::saveAs_continued(LLViewerInventoryItem const* item, AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) return; - } + // remember the user-approved/edited file name. - mSaveFileName = file_picker.getFirstFile(); + mSaveFileName = filepicker->getFilename(); mLoadingFullImage = TRUE; getWindow()->incBusyCount(); mImage->forceToSaveRawImage(0) ;//re-fetch the raw image if the old one is removed. diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h index fb75876fc..ce26d4dd4 100644 --- a/indra/newview/llpreviewtexture.h +++ b/indra/newview/llpreviewtexture.h @@ -40,6 +40,7 @@ class LLComboBox; class LLImageRaw; +class AIFilePicker; class LLPreviewTexture : public LLPreview { @@ -64,6 +65,7 @@ public: virtual BOOL canSaveAs() const; virtual void saveAs(); + void saveAs_continued(LLViewerInventoryItem const* item, AIFilePicker* filepicker); virtual LLUUID getItemID(); virtual std::string getItemCreatorName(); virtual std::string getItemCreationDate(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index e08bc301a..07c8de068 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -54,6 +54,7 @@ #include "hippogridmanager.h" #include "hippolimits.h" #include "floaterao.h" +#include "statemachine/aifilepicker.h" #include "llares.h" #include "llcachename.h" @@ -636,6 +637,12 @@ bool idle_startup() LLStartUp::handleSocksProxy(false); + //------------------------------------------------- + // Load file- and dirpicker {context, default path} map. + //------------------------------------------------- + + AIFilePicker::loadFile("filepicker_contexts.xml"); + //------------------------------------------------- // Init audio, which may be needed for prefs dialog // or audio cues in connection UI. diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 319f1cb57..e92a5185c 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -74,7 +74,6 @@ // tag: vaa emerald local_asset_browser [begin] #include "floaterlocalassetbrowse.h" #include "llscrolllistctrl.h" -#include "llfilepicker.h" #define LOCALLIST_COL_ID 1 // tag: vaa emerald local_asset_browser [end] diff --git a/indra/newview/lluploaddialog.cpp b/indra/newview/lluploaddialog.cpp index 2ba87f01b..a860e5303 100644 --- a/indra/newview/lluploaddialog.cpp +++ b/indra/newview/lluploaddialog.cpp @@ -161,10 +161,6 @@ void LLUploadDialog::setMessage( const std::string& msg) LLUploadDialog::~LLUploadDialog() { gFocusMgr.releaseFocusIfNeeded( this ); - -// LLFilePicker::instance().reset(); - - LLUploadDialog::sDialog = NULL; } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 6ef3d762a..73b108981 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -75,6 +75,7 @@ #include "llnetmap.h" #include "llrender.h" #include "llfloaterchat.h" +#include "statemachine/aistatemachine.h" #include "aithreadsafe.h" #include "llviewerobjectlist.h" #include "lldrawpoolbump.h" @@ -119,6 +120,11 @@ static bool handleTerrainDetailChanged(const LLSD& newvalue) return true; } +bool handleStateMachineMaxTimeChanged(const LLSD& newvalue) +{ + AIStateMachine::updateSettings(); + return true; +} static bool handleSetShaderChanged(const LLSD& newvalue) { @@ -707,6 +713,7 @@ void settings_setup_listeners() gSavedSettings.getControl("AudioLevelMic")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); gSavedSettings.getControl("LipSyncEnabled")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); gSavedSettings.getControl("TranslateChat")->getSignal()->connect(boost::bind(&handleTranslateChatPrefsChanged, _1)); + gSavedSettings.getControl("StateMachineMaxTime")->getSignal()->connect(boost::bind(&handleStateMachineMaxTimeChanged, _1)); gSavedSettings.getControl("CloudsEnabled")->getSignal()->connect(boost::bind(&handleCloudSettingsChanged, _1)); gSavedSettings.getControl("SkyUseClassicClouds")->getSignal()->connect(boost::bind(&handleCloudSettingsChanged, _1)); @@ -803,6 +810,16 @@ template <> eControlType get_control_type(const LLSD& in, LLSD& out) return TYPE_LLSD; } +void onCommitControlSetting_gSavedSettings(LLUICtrl* ctrl, void* name) +{ + gSavedSettings.setValue((const char*)name,ctrl->getValue()); +} + +void onCommitControlSetting_gSavedPerAccountSettings(LLUICtrl* ctrl, void* name) +{ + gSavedPerAccountSettings.setValue((const char*)name,ctrl->getValue()); +} + #if TEST_CACHED_CONTROL #define DECL_LLCC(T, V) static LLCachedControl mySetting_##T("TestCachedControl"#T, V) diff --git a/indra/newview/llviewercontrol.h b/indra/newview/llviewercontrol.h index 8835146ad..f22f96f27 100644 --- a/indra/newview/llviewercontrol.h +++ b/indra/newview/llviewercontrol.h @@ -35,9 +35,10 @@ #include #include "llcontrol.h" -#include "lluictrl.h" #include "aithreadsafe.h" +class LLUICtrl; + // Enabled this definition to compile a 'hacked' viewer that // allows a hacked godmode to be toggled on and off. #define TOGGLE_HACKED_GODLIKE_VIEWER @@ -75,8 +76,8 @@ bool handleCloudSettingsChanged(const LLSD& newvalue); //A template would be a little awkward to use here.. so.. a preprocessor macro. Alas. onCommitControlSetting(gSavedSettings) etc. -inline void onCommitControlSetting_gSavedSettings(LLUICtrl* ctrl, void* name) {gSavedSettings.setValue((const char*)name,ctrl->getValue());} -inline void onCommitControlSetting_gSavedPerAccountSettings(LLUICtrl* ctrl, void* name) {gSavedPerAccountSettings.setValue((const char*)name,ctrl->getValue());} +void onCommitControlSetting_gSavedSettings(LLUICtrl* ctrl, void* name); +void onCommitControlSetting_gSavedPerAccountSettings(LLUICtrl* ctrl, void* name); #define onCommitControlSetting(controlgroup) onCommitControlSetting_##controlgroup //#define TEST_CACHED_CONTROL 1 diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index dbb83b1ee..0beed949a 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -47,84 +47,12 @@ #include "lluuid.h" #include "llkeyboard.h" - // Merov: Temporary definitions while porting the new viewer media code to Snowglobe const int LEFT_BUTTON = 0; const int RIGHT_BUTTON = 1; -// Move this to its own file. - -LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter() -{ - observerListType::iterator iter = mObservers.begin(); - - while( iter != mObservers.end() ) - { - LLViewerMediaObserver *self = *iter; - iter++; - remObserver(self); - } -} - /////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaEventEmitter::addObserver( LLViewerMediaObserver* observer ) -{ - if ( ! observer ) - return false; - - if ( std::find( mObservers.begin(), mObservers.end(), observer ) != mObservers.end() ) - return false; - - mObservers.push_back( observer ); - observer->mEmitters.push_back( this ); - - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer ) -{ - if ( ! observer ) - return false; - - mObservers.remove( observer ); - observer->mEmitters.remove(this); - - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLPluginClassMediaOwner::EMediaEvent event ) -{ - observerListType::iterator iter = mObservers.begin(); - - while( iter != mObservers.end() ) - { - LLViewerMediaObserver *self = *iter; - ++iter; - self->handleMediaEvent( media, event ); - } -} - -// Move this to its own file. -LLViewerMediaObserver::~LLViewerMediaObserver() -{ - std::list::iterator iter = mEmitters.begin(); - - while( iter != mEmitters.end() ) - { - LLViewerMediaEventEmitter *self = *iter; - iter++; - self->remObserver( this ); - } -} - - -// Move this to its own file. -// helper class that tries to download a URL from a web site and calls a method +// Helper class that tries to download a URL from a web site and calls a method // on the Panel Land Media and to discover the MIME type class LLMimeDiscoveryResponder : public LLHTTPClient::Responder { @@ -279,9 +207,10 @@ void LLViewerMedia::updateBrowserUserAgent() for(; iter != end; iter++) { LLViewerMediaImpl* pimpl = *iter; - if(pimpl->mMediaSource && pimpl->mMediaSource->pluginSupportsMediaBrowser()) + LLPluginClassMedia* plugin = pimpl->getMediaPlugin(); + if(plugin && plugin->pluginSupportsMediaBrowser()) { - pimpl->mMediaSource->setBrowserUserAgent(user_agent); + plugin->setBrowserUserAgent(user_agent); } } @@ -366,7 +295,6 @@ LLViewerMediaImpl::LLViewerMediaImpl(const std::string& media_url, U8 media_loop, const std::string& mime_type) : - mMediaSource( NULL ), mMovieImageHasMips(false), mTextureId(texture_id), mMediaWidth(media_width), @@ -399,7 +327,7 @@ LLViewerMediaImpl::~LLViewerMediaImpl() ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) { - if((mMediaSource == NULL) || (mMimeType != mime_type)) + if((mPluginBase == NULL) || (mMimeType != mime_type)) { if(! initializePlugin(mime_type)) { @@ -413,7 +341,7 @@ bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) } // play(); - return (mMediaSource != NULL); + return (mPluginBase != NULL); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -434,14 +362,13 @@ void LLViewerMediaImpl::createMediaSource() void LLViewerMediaImpl::destroyMediaSource() { mNeedsNewTexture = true; - if(! mMediaSource) + if (!mPluginBase) { return; } // Restore the texture updateMovieImage(LLUUID::null, false); - delete mMediaSource; - mMediaSource = NULL; + destroyPlugin(); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -472,10 +399,12 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ if(LLFile::stat(launcher_name, &s)) { LL_WARNS("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL; + llassert(false); // Fail in debugging mode. } else if(LLFile::stat(plugin_name, &s)) { LL_WARNS("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; + llassert(false); // Fail in debugging mode. } else { @@ -514,16 +443,17 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ LLNotifications::instance().add("NoPlugin", args); return NULL; -} +} ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { // Save the previous media source's last set size before destroying it. - mMediaWidth = mMediaSource->getSetWidth(); - mMediaHeight = mMediaSource->getSetHeight(); + mMediaWidth = plugin->getSetWidth(); + mMediaHeight = plugin->getSetHeight(); } // Always delete the old media impl first. @@ -541,7 +471,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) media_source->setAutoScale(mMediaAutoScale); media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent()); - mMediaSource = media_source; + mPluginBase = media_source; return true; } @@ -550,34 +480,38 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) void LLViewerMediaImpl::setSize(int width, int height) { + LLPluginClassMedia* plugin = getMediaPlugin(); mMediaWidth = width; mMediaHeight = height; - if(mMediaSource) + if (plugin) { - mMediaSource->setSize(width, height); + plugin->setSize(width, height); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::play() { + LLPluginClassMedia* plugin = getMediaPlugin(); + // first stop any previously playing media // stop(); - // mMediaSource->addObserver( this ); - if(mMediaSource == NULL) + // plugin->addObserver( this ); + if (!plugin) { if(!initializePlugin(mMimeType)) { // Plugin failed initialization... should assert or something return; } + plugin = getMediaPlugin(); } // updateMovieImage(mTextureId, true); - mMediaSource->loadURI( mMediaURL ); - if(/*mMediaSource->pluginSupportsMediaTime()*/ true) + plugin->loadURI( mMediaURL ); + if(/*plugin->pluginSupportsMediaTime()*/ true) { start(); } @@ -586,9 +520,10 @@ void LLViewerMediaImpl::play() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::stop() { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->stop(); + plugin->stop(); // destroyMediaSource(); } } @@ -596,52 +531,57 @@ void LLViewerMediaImpl::stop() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::pause() { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->pause(); + plugin->pause(); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::start() { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->start(); + plugin->start(); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::seek(F32 time) { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->seek(time); + plugin->seek(time); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::setVolume(F32 volume) { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->setVolume(volume); + plugin->setVolume(volume); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::focus(bool focus) { - if (mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { // call focus just for the hell of it, even though this apopears to be a nop - mMediaSource->focus(focus); + plugin->focus(focus); if (focus) { // spoof a mouse click to *actually* pass focus // Don't do this anymore -- it actually clicks through now. -// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0); -// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0); +// plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0); +// plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0); } } } @@ -649,57 +589,62 @@ void LLViewerMediaImpl::focus(bool focus) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseDown(S32 x, S32 y) { + LLPluginClassMedia* plugin = getMediaPlugin(); scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; - if (mMediaSource) + if (plugin) { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, LEFT_BUTTON, x, y, 0); + plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, LEFT_BUTTON, x, y, 0); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseUp(S32 x, S32 y) { + LLPluginClassMedia* plugin = getMediaPlugin(); scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; - if (mMediaSource) + if (plugin) { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, LEFT_BUTTON, x, y, 0); + plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, LEFT_BUTTON, x, y, 0); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseMove(S32 x, S32 y) { + LLPluginClassMedia* plugin = getMediaPlugin(); scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; - if (mMediaSource) + if (plugin) { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, LEFT_BUTTON, x, y, 0); + plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, LEFT_BUTTON, x, y, 0); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseLeftDoubleClick(S32 x, S32 y) { + LLPluginClassMedia* plugin = getMediaPlugin(); scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; - if (mMediaSource) + if (plugin) { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, LEFT_BUTTON, x, y, 0); + plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, LEFT_BUTTON, x, y, 0); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::onMouseCaptureLost() { - if (mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, LEFT_BUTTON, mLastMouseX, mLastMouseY, 0); + plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, LEFT_BUTTON, mLastMouseX, mLastMouseY, 0); } } @@ -720,15 +665,17 @@ BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::navigateHome() { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->loadURI( mHomeURL ); + plugin->loadURI( mHomeURL ); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type) { + LLPluginClassMedia* plugin = getMediaPlugin(); if(rediscover_type) { @@ -745,7 +692,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi // We use "data" internally for a text/html url for loading the login screen if(initializeMedia("text/html")) { - mMediaSource->loadURI( url ); + plugin->loadURI( url ); } } else @@ -753,17 +700,17 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi // This catches 'rtsp://' urls if(initializeMedia(scheme)) { - mMediaSource->loadURI( url ); + plugin->loadURI( url ); } } } - else if (mMediaSource) + else if (plugin) { - mMediaSource->loadURI( url ); + plugin->loadURI( url ); } - else if(initializeMedia(mime_type) && mMediaSource) + else if(initializeMedia(mime_type) && (plugin = getMediaPlugin())) { - mMediaSource->loadURI( url ); + plugin->loadURI( url ); } else { @@ -777,9 +724,10 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::navigateStop() { - if(mMediaSource) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - mMediaSource->browse_stop(); + plugin->browse_stop(); } } @@ -788,8 +736,9 @@ void LLViewerMediaImpl::navigateStop() bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) { bool result = false; + LLPluginClassMedia* plugin = getMediaPlugin(); - if (mMediaSource) + if (plugin) { // FIXME: THIS IS SO WRONG. // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... @@ -797,19 +746,19 @@ bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) { if( 'C' == key ) { - mMediaSource->copy(); + plugin->copy(); result = true; } else if( 'V' == key ) { - mMediaSource->paste(); + plugin->paste(); result = true; } else if( 'X' == key ) { - mMediaSource->cut(); + plugin->cut(); result = true; } } @@ -819,9 +768,9 @@ bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) LLSD native_key_data = LLSD::emptyMap(); - result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data); + result = plugin->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data); // Since the viewer internal event dispatching doesn't give us key-up events, simulate one here. - (void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data); + (void)plugin->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data); } } @@ -832,8 +781,9 @@ bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) { bool result = false; + LLPluginClassMedia* plugin = getMediaPlugin(); - if (mMediaSource) + if (plugin) { // only accept 'printable' characters, sigh... if (uni_char >= 32 // discard 'control' characters @@ -841,7 +791,7 @@ bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) { LLSD native_key_data = LLSD::emptyMap(); - mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data); + plugin->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data); } } @@ -851,10 +801,11 @@ bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::canNavigateForward() { - BOOL result = FALSE; - if (mMediaSource) + bool result = false; + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - result = mMediaSource->getHistoryForwardAvailable(); + result = plugin->getHistoryForwardAvailable(); } return result; } @@ -862,10 +813,11 @@ bool LLViewerMediaImpl::canNavigateForward() ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::canNavigateBack() { - BOOL result = FALSE; - if (mMediaSource) + bool result = false; + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) { - result = mMediaSource->getHistoryBackAvailable(); + result = plugin->getHistoryBackAvailable(); } return result; } @@ -909,20 +861,21 @@ void LLViewerMediaImpl::updateMovieImage(const LLUUID& uuid, BOOL active) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::update() { - if(mMediaSource == NULL) + LLPluginClassMedia* plugin = getMediaPlugin(); + if (!plugin) { return; } - mMediaSource->idle(); + plugin->idle(); - if(mMediaSource->isPluginExited()) + if (plugin->isPluginExited()) { destroyMediaSource(); return; } - if(!mMediaSource->textureValid()) + if (!plugin->textureValid()) { return; } @@ -937,7 +890,7 @@ void LLViewerMediaImpl::update() if(placeholder_image) { LLRect dirty_rect; - if(mMediaSource->getDirty(&dirty_rect)) + if (plugin->getDirty(&dirty_rect)) { // Constrain the dirty rect to be inside the texture S32 x_pos = llmax(dirty_rect.mLeft, 0); @@ -948,16 +901,16 @@ void LLViewerMediaImpl::update() if(width > 0 && height > 0) { - U8* data = mMediaSource->getBitsData(); + U8* data = plugin->getBitsData(); // Offset the pixels pointer to match x_pos and y_pos - data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); - data += ( y_pos * mMediaSource->getTextureDepth() ); + data += ( x_pos * plugin->getTextureDepth() * plugin->getBitsWidth() ); + data += ( y_pos * plugin->getTextureDepth() ); placeholder_image->setSubImage( data, - mMediaSource->getBitsWidth(), - mMediaSource->getBitsHeight(), + plugin->getBitsWidth(), + plugin->getBitsHeight(), x_pos, y_pos, width, @@ -966,7 +919,7 @@ void LLViewerMediaImpl::update() } - mMediaSource->resetDirty(); + plugin->resetDirty(); } } } @@ -988,24 +941,25 @@ void LLViewerMediaImpl::updateImagesMediaStreams() } LLViewerMediaTexture* placeholder_image = (LLViewerMediaTexture*)LLViewerTextureManager::getFetchedTexture( mTextureId ); - + LLPluginClassMedia* plugin = getMediaPlugin(); + placeholder_image->getLastReferencedTimer()->reset(); if (mNeedsNewTexture || placeholder_image->getUseMipMaps() || ! placeholder_image->mIsMediaTexture - || (placeholder_image->getWidth() != mMediaSource->getTextureWidth()) - || (placeholder_image->getHeight() != mMediaSource->getTextureHeight()) - || (mTextureUsedWidth != mMediaSource->getWidth()) - || (mTextureUsedHeight != mMediaSource->getHeight()) + || (placeholder_image->getWidth() != plugin->getTextureWidth()) + || (placeholder_image->getHeight() != plugin->getTextureHeight()) + || (mTextureUsedWidth != plugin->getWidth()) + || (mTextureUsedHeight != plugin->getHeight()) ) { llinfos << "initializing media placeholder" << llendl; llinfos << "movie image id " << mTextureId << llendl; - int texture_width = mMediaSource->getTextureWidth(); - int texture_height = mMediaSource->getTextureHeight(); - int texture_depth = mMediaSource->getTextureDepth(); + int texture_width = plugin->getTextureWidth(); + int texture_height = plugin->getTextureHeight(); + int texture_depth = plugin->getTextureDepth(); // MEDIAOPT: check to see if size actually changed before doing work placeholder_image->destroyGLTexture(); @@ -1019,10 +973,10 @@ void LLViewerMediaImpl::updateImagesMediaStreams() int discard_level = 0; // ask media source for correct GL image format constants - placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), - mMediaSource->getTextureFormatPrimary(), - mMediaSource->getTextureFormatType(), - mMediaSource->getTextureFormatSwapBytes()); + placeholder_image->setExplicitFormat(plugin->getTextureFormatInternal(), + plugin->getTextureFormatPrimary(), + plugin->getTextureFormatType(), + plugin->getTextureFormatSwapBytes()); placeholder_image->createGLTexture(discard_level, raw); @@ -1035,8 +989,8 @@ void LLViewerMediaImpl::updateImagesMediaStreams() // If the amount of the texture being drawn by the media goes down in either width or height, // recreate the texture to avoid leaving parts of the old image behind. - mTextureUsedWidth = mMediaSource->getWidth(); - mTextureUsedHeight = mMediaSource->getHeight(); + mTextureUsedWidth = plugin->getWidth(); + mTextureUsedHeight = plugin->getHeight(); } return placeholder_image; @@ -1052,24 +1006,25 @@ LLUUID LLViewerMediaImpl::getMediaTextureID() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::setVisible(bool visible) { + LLPluginClassMedia* plugin = getMediaPlugin(); mVisible = visible; if(mVisible) { - if(mMediaSource && mMediaSource->isPluginExited()) + if(plugin && plugin->isPluginExited()) { destroyMediaSource(); } - if(!mMediaSource) + if(!plugin) { createMediaSource(); } } - if(mMediaSource) + if(plugin) { - mMediaSource->setPriority(mVisible?LLPluginClassMedia::PRIORITY_NORMAL:LLPluginClassMedia::PRIORITY_HIDDEN); + plugin->setPriority(mVisible?LLPluginClassBasic::PRIORITY_NORMAL:LLPluginClassBasic::PRIORITY_SLEEP); } } @@ -1082,10 +1037,11 @@ void LLViewerMediaImpl::mouseCapture() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::getTextureSize(S32 *texture_width, S32 *texture_height) { - if(mMediaSource && mMediaSource->textureValid()) + LLPluginClassMedia* plugin = getMediaPlugin(); + if(plugin && plugin->textureValid()) { - S32 real_texture_width = mMediaSource->getBitsWidth(); - S32 real_texture_height = mMediaSource->getBitsHeight(); + S32 real_texture_width = plugin->getBitsWidth(); + S32 real_texture_height = plugin->getBitsHeight(); { // The "texture width" coming back from the plugin may not be a power of two (thanks to webkit). @@ -1126,10 +1082,11 @@ void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y) bool LLViewerMediaImpl::isMediaPlaying() { bool result = false; + LLPluginClassMedia* plugin = getMediaPlugin(); - if(mMediaSource) + if(plugin) { - EMediaStatus status = mMediaSource->getStatus(); + EMediaStatus status = plugin->getStatus(); if(status == MEDIA_PLAYING || status == MEDIA_LOADING) result = true; } @@ -1140,10 +1097,11 @@ bool LLViewerMediaImpl::isMediaPlaying() bool LLViewerMediaImpl::isMediaPaused() { bool result = false; + LLPluginClassMedia* plugin = getMediaPlugin(); - if(mMediaSource) + if(plugin) { - if(mMediaSource->getStatus() == MEDIA_PAUSED) + if(plugin->getStatus() == MEDIA_PAUSED) result = true; } @@ -1154,7 +1112,7 @@ bool LLViewerMediaImpl::isMediaPaused() // bool LLViewerMediaImpl::hasMedia() { - return mMediaSource != NULL; + return mPluginBase != NULL; } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1181,8 +1139,9 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* self, LLPluginClass void LLViewerMediaImpl::cut() { - if (mMediaSource) - mMediaSource->cut(); + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) + plugin->cut(); } //////////////////////////////////////////////////////////////////////////////// @@ -1190,8 +1149,9 @@ LLViewerMediaImpl::cut() BOOL LLViewerMediaImpl::canCut() const { - if (mMediaSource) - return mMediaSource->canCut(); + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) + return plugin->canCut(); else return FALSE; } @@ -1201,8 +1161,9 @@ LLViewerMediaImpl::canCut() const void LLViewerMediaImpl::copy() { - if (mMediaSource) - mMediaSource->copy(); + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) + plugin->copy(); } //////////////////////////////////////////////////////////////////////////////// @@ -1210,8 +1171,9 @@ LLViewerMediaImpl::copy() BOOL LLViewerMediaImpl::canCopy() const { - if (mMediaSource) - return mMediaSource->canCopy(); + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) + return plugin->canCopy(); else return FALSE; } @@ -1221,8 +1183,9 @@ LLViewerMediaImpl::canCopy() const void LLViewerMediaImpl::paste() { - if (mMediaSource) - mMediaSource->paste(); + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) + plugin->paste(); } //////////////////////////////////////////////////////////////////////////////// @@ -1230,8 +1193,9 @@ LLViewerMediaImpl::paste() BOOL LLViewerMediaImpl::canPaste() const { - if (mMediaSource) - return mMediaSource->canPaste(); + LLPluginClassMedia* plugin = getMediaPlugin(); + if (plugin) + return plugin->canPaste(); else return FALSE; } diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 1e9ef6c90..6b8bd2217 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -33,34 +33,17 @@ #ifndef LLVIEWERMEDIA_H #define LLVIEWERMEDIA_H +#include "llviewermediaeventemitter.h" +#include "llviewerpluginmanager.h" #include "llfocusmgr.h" - #include "llpanel.h" -#include "llpluginclassmediaowner.h" - -#include "llviewermediaobserver.h" class LLViewerMediaImpl; class LLUUID; -//class LLViewerMediaTexture; +class LLSD; class LLViewerTexture; typedef LLPointer viewer_media_t; -/////////////////////////////////////////////////////////////////////////////// -// -class LLViewerMediaEventEmitter -{ -public: - virtual ~LLViewerMediaEventEmitter(); - - bool addObserver( LLViewerMediaObserver* subject ); - bool remObserver( LLViewerMediaObserver* subject ); - void emitEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent event); - -private: - typedef std::list< LLViewerMediaObserver* > observerListType; - observerListType mObservers; -}; class LLViewerMedia { @@ -93,7 +76,7 @@ class LLViewerMedia // Implementation functions not exported into header file class LLViewerMediaImpl - : public LLMouseHandler, public LLRefCount, public LLPluginClassMediaOwner, public LLViewerMediaEventEmitter, public LLEditMenuHandler + : public LLViewerPluginManager, public LLMouseHandler, public LLPluginClassMediaOwner, public LLViewerMediaEventEmitter, public LLEditMenuHandler { LOG_CLASS(LLViewerMediaImpl); public: @@ -112,9 +95,12 @@ public: void setMediaType(const std::string& media_type); bool initializeMedia(const std::string& mime_type); bool initializePlugin(const std::string& media_type); - LLPluginClassMedia* getMediaPlugin() { return mMediaSource; } + LLPluginClassMedia* getMediaPlugin() const { return (LLPluginClassMedia*)mPluginBase; } void setSize(int width, int height); + // Inherited from LLViewerPluginManager. + /*virtual*/ void update(); + void play(); void stop(); void pause(); @@ -141,7 +127,6 @@ public: void getTextureSize(S32 *texture_width, S32 *texture_height); void scaleMouse(S32 *mouse_x, S32 *mouse_y); - void update(); void updateMovieImage(const LLUUID& image_id, BOOL active); void updateImagesMediaStreams(); LLUUID getMediaTextureID(); @@ -201,7 +186,6 @@ public: public: // a single media url with some data and an impl. - LLPluginClassMedia* mMediaSource; LLUUID mTextureId; bool mMovieImageHasMips; std::string mMediaURL; @@ -219,7 +203,6 @@ public: bool mSuspendUpdates; bool mVisible; - private: /*LLViewerMediaTexture*/LLViewerTexture *updatePlaceholderImage(); }; diff --git a/indra/newview/llviewermediaeventemitter.cpp b/indra/newview/llviewermediaeventemitter.cpp new file mode 100644 index 000000000..39e0b2b52 --- /dev/null +++ b/indra/newview/llviewermediaeventemitter.cpp @@ -0,0 +1,85 @@ +/** + * @file llviewermediaeventemitter.cpp + * @brief Implementation of LLViewerMediaEventEmitter + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llviewermediaeventemitter.h" +#include "llviewermediaobserver.h" +#include + +LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter() +{ + observerListType::iterator iter = mObservers.begin(); + + while (iter != mObservers.end()) + { + LLViewerMediaObserver* self = *iter; + ++iter; + remObserver(self); + } +} + +bool LLViewerMediaEventEmitter::addObserver(LLViewerMediaObserver* observer) +{ + if (!observer) + return false; + + if (std::find(mObservers.begin(), mObservers.end(), observer) != mObservers.end()) + return false; + + mObservers.push_back(observer); + observer->mEmitters.push_back(this); + + return true; +} + +bool LLViewerMediaEventEmitter::remObserver(LLViewerMediaObserver* observer) +{ + if (!observer) + return false; + + mObservers.remove(observer); + observer->mEmitters.remove(this); + + return true; +} + +void LLViewerMediaEventEmitter::emitEvent(LLPluginClassMedia* media, LLPluginClassMediaOwner::EMediaEvent event) +{ + observerListType::iterator iter = mObservers.begin(); + + while (iter != mObservers.end()) + { + LLViewerMediaObserver* self = *iter; + ++iter; + self->handleMediaEvent(media, event); + } +} diff --git a/indra/newview/llviewermediaeventemitter.h b/indra/newview/llviewermediaeventemitter.h new file mode 100644 index 000000000..17453a9e1 --- /dev/null +++ b/indra/newview/llviewermediaeventemitter.h @@ -0,0 +1,56 @@ +/** + * @file llviewermediaeventemitter.h + * @brief Helper class + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLVIEWERMEDIAEVENTEMITTER_H +#define LLVIEWERMEDIAEVENTEMITTER_H + +#include "llpluginclassmediaowner.h" +#include + +class LLViewerMediaObserver; +class LLPluginClassMedia; + +class LLViewerMediaEventEmitter +{ +public: + virtual ~LLViewerMediaEventEmitter(); + + bool addObserver(LLViewerMediaObserver* subject); + bool remObserver(LLViewerMediaObserver* subject); + void emitEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent event); + +private: + typedef std::list< LLViewerMediaObserver*> observerListType; + observerListType mObservers; +}; + +#endif // LLVIEWERMEDIAEVENTEMITTER_H diff --git a/indra/newview/llviewermediaobserver.cpp b/indra/newview/llviewermediaobserver.cpp new file mode 100644 index 000000000..6bed14311 --- /dev/null +++ b/indra/newview/llviewermediaobserver.cpp @@ -0,0 +1,47 @@ +/** + * @file llviewermediaobserver.cpp + * @brief Implementation of class LLViewerMediaObserver. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llviewermediaeventemitter.h" +#include "llviewermediaobserver.h" + +LLViewerMediaObserver::~LLViewerMediaObserver() +{ + std::list::iterator iter = mEmitters.begin(); + + while (iter != mEmitters.end()) + { + LLViewerMediaEventEmitter* self = *iter; + ++iter; + self->remObserver(this); + } +} diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 9bb01f336..d541a8cb8 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -69,6 +69,7 @@ #include "lltimer.h" #include "llvfile.h" #include "llvolumemgr.h" +#include "statemachine/aifilepicker.h" // newview includes #include "llagent.h" @@ -1223,19 +1224,21 @@ void init_debug_world_menu(LLMenuGL* menu) menu->createJumpKeys(); } - +static void handle_export_menus_to_xml_continued(AIFilePicker* filepicker); void handle_export_menus_to_xml(void*) { + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open("", FFSAVE_XML); + filepicker->run(boost::bind(&handle_export_menus_to_xml_continued, filepicker)); +} - LLFilePicker& picker = LLFilePicker::instance(); - if(!picker.getSaveFile(LLFilePicker::FFSAVE_XML)) +static void handle_export_menus_to_xml_continued(AIFilePicker* filepicker) +{ + if(!filepicker->hasFilename()) { - llwarns << "No file" << llendl; return; } - std::string filename = picker.getFirstFile(); - - llofstream out(filename); + llofstream out(filepicker->getFilename()); LLXMLNodePtr node = gMenuBarView->getXML(); node->writeToOstream(out); out.close(); @@ -8645,6 +8648,7 @@ const LLRect LLViewerMenuHolderGL::getMenuRect() const return LLRect(0, getRect().getHeight() - MENU_BAR_HEIGHT, getRect().getWidth(), STATUS_BAR_HEIGHT); } +static void handle_save_to_xml_continued(LLFloater* frontmost, AIFilePicker* filepicker); void handle_save_to_xml(void*) { LLFloater* frontmost = gFloaterView->getFrontmost(); @@ -8664,20 +8668,33 @@ void handle_save_to_xml(void*) LLStringUtil::replaceChar(default_name, ':', '_'); LLStringUtil::replaceChar(default_name, '"', '_'); - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getSaveFile(LLFilePicker::FFSAVE_XML, default_name)) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(default_name, FFSAVE_XML); + filepicker->run(boost::bind(&handle_save_to_xml_continued, frontmost, filepicker)); +} + +static void handle_save_to_xml_continued(LLFloater* frontmost, AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) { - std::string filename = picker.getFirstFile(); + std::string filename = filepicker->getFilename(); LLUICtrlFactory::getInstance()->saveToXML(frontmost, filename); } } +static void handle_load_from_xml_continued(AIFilePicker* filepicker); void handle_load_from_xml(void*) { - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getOpenFile(LLFilePicker::FFLOAD_XML)) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_XML); + filepicker->run(boost::bind(&handle_load_from_xml_continued, filepicker)); +} + +static void handle_load_from_xml_continued(AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) { - std::string filename = picker.getFirstFile(); + std::string filename = filepicker->getFilename(); LLFloater* floater = new LLFloater("sample_floater"); LLUICtrlFactory::getInstance()->buildFloater(floater, filename); } diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index e9fedf37d..a6d96c08c 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -35,9 +35,6 @@ #include "llmenugl.h" -//newview includes -#include "llfilepicker.h" - class LLUICtrl; class LLView; class LLParcelSelection; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index b4d01d476..0a3254ea0 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -41,7 +41,7 @@ #include "llimagepng.h" #include "llimagebmp.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llfloateranimpreview.h" #include "llfloaterbuycurrency.h" @@ -125,26 +125,26 @@ static std::string SLOBJECT_EXTENSIONS = "slobject"; #endif static std::string ALL_FILE_EXTENSIONS = "*.*"; -std::string build_extensions_string(LLFilePicker::ELoadFilter filter) +std::string build_extensions_string(ELoadFilter filter) { switch(filter) { #if LL_WINDOWS - case LLFilePicker::FFLOAD_IMAGE: + case FFLOAD_IMAGE: return IMAGE_EXTENSIONS; - case LLFilePicker::FFLOAD_WAV: + case FFLOAD_WAV: return SOUND_EXTENSIONS; - case LLFilePicker::FFLOAD_ANIM: + case FFLOAD_ANIM: return ANIM_EXTENSIONS; - case LLFilePicker::FFLOAD_SLOBJECT: + case FFLOAD_SLOBJECT: return SLOBJECT_EXTENSIONS; #ifdef _CORY_TESTING - case LLFilePicker::FFLOAD_GEOMETRY: + case FFLOAD_GEOMETRY: return GEOMETRY_EXTENSIONS; #endif - case LLFilePicker::FFLOAD_XML: + case FFLOAD_XML: return XML_EXTENSIONS; - case LLFilePicker::FFLOAD_ALL: + case FFLOAD_ALL: return ALL_FILE_EXTENSIONS; #endif default: @@ -152,48 +152,51 @@ std::string build_extensions_string(LLFilePicker::ELoadFilter filter) } } -/** - char* upload_pick(void* data) +class AIFileUpload { + protected: + AIFilePicker* mPicker; - If applicable, brings up a file chooser in which the user selects a file - to upload for a particular task. If the file is valid for the given action, - returns the string to the full path filename, else returns NULL. - Data is the load filter for the type of file as defined in LLFilePicker. + public: + AIFileUpload(void) : mPicker(NULL) { } + virtual ~AIFileUpload() { llassert(!mPicker); if (mPicker) { mPicker->abort(); mPicker = NULL; } } - Eventually I'd really like to have a built-in browser that gave you all - valid filetypes, default permissions, "Temp when available", and a single - upload button. Maybe let it show the contents of multiple folders. The main - purpose of this features is to deal with the problem of SL just up and - disconnecting if you take more than like 30 seconds to look for a file. -HgB -**/ -const std::string upload_pick(void* data) + public: + bool is_valid(std::string const& filename, ELoadFilter type); + void filepicker_callback(ELoadFilter type); + void start_filepicker(ELoadFilter type, char const* context); + + protected: + virtual void handle_event(std::string const& filename) = 0; +}; + +void AIFileUpload::start_filepicker(ELoadFilter filter, char const* context) { - if( gAgent.cameraMouselook() ) + if( gAgent.cameraMouselook() ) { gAgent.changeCameraToDefault(); // This doesn't seem necessary. JC // display(); } - LLFilePicker::ELoadFilter type; - if(data) - { - type = (LLFilePicker::ELoadFilter)((intptr_t)data); - } - else - { - type = LLFilePicker::FFLOAD_ALL; - } + llassert(!mPicker); + mPicker = new AIFilePicker; + mPicker->open(filter, "", context); + mPicker->run(boost::bind(&AIFileUpload::filepicker_callback, this, filter)); +} - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getOpenFile(type)) +void AIFileUpload::filepicker_callback(ELoadFilter type) +{ + if (mPicker->hasFilename()) { - llinfos << "Couldn't import objects from file" << llendl; - return std::string(); + std::string filename = mPicker->getFilename(); + if (is_valid(filename, type)) + handle_event(filename); } + mPicker = NULL; +} - - const std::string& filename = picker.getFirstFile(); +bool AIFileUpload::is_valid(std::string const& filename, ELoadFilter type) +{ std::string ext = gDirUtilp->getExtension(filename); //strincmp doesn't like NULL pointers @@ -205,7 +208,7 @@ const std::string upload_pick(void* data) LLSD args; args["FILE"] = short_name; LLNotifications::instance().add("NoFileExtension", args); - return std::string(); + return false; } else { @@ -248,7 +251,7 @@ const std::string upload_pick(void* data) args["EXTENSION"] = ext; args["VALIDS"] = valid_extensions; LLNotifications::instance().add("InvalidFileExtension", args); - return NULL; + return false; } }//end else (non-null extension) @@ -257,7 +260,7 @@ const std::string upload_pick(void* data) //now we check to see //if the file is actually a valid image/sound/etc. //Consider completely disabling this, see how SL handles it. Maybe we can get full song uploads again! -HgB - if (type == LLFilePicker::FFLOAD_WAV) + if (type == FFLOAD_WAV) { // pre-qualify wavs to make sure the format is acceptable std::string error_msg; @@ -267,103 +270,68 @@ const std::string upload_pick(void* data) LLSD args; args["FILE"] = filename; LLNotifications::instance().add( error_msg, args ); - return std::string(); + return false; } }//end if a wave/sound file - return filename; + return true; } -class LLFileUploadImage : public view_listener_t +class LLFileUploadImage : public view_listener_t, public AIFileUpload { + public: bool handleEvent(LLPointer event, const LLSD& userdata) { - std::string filename = upload_pick((void *)LLFilePicker::FFLOAD_IMAGE); - if (!filename.empty()) - { - LLFloaterImagePreview* floaterp = new LLFloaterImagePreview(filename); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_image_preview.xml"); - } - return TRUE; + start_filepicker(FFLOAD_IMAGE, "image"); + return true; + } + + protected: + // Inherited from AIFileUpload. + /*virtual*/ void handle_event(std::string const& filename) + { + LLFloaterImagePreview* floaterp = new LLFloaterImagePreview(filename); + LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_image_preview.xml"); } }; -class LLFileUploadSound : public view_listener_t +class LLFileUploadSound : public view_listener_t, public AIFileUpload { bool handleEvent(LLPointer event, const LLSD& userdata) { - std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_WAV); - if (!filename.empty()) - { - LLFloaterNameDesc* floaterp = new LLFloaterNameDesc(filename); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_sound_preview.xml"); - floaterp->childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", LLGlobalEconomy::Singleton::getInstance()->getPriceUpload() )); - } + start_filepicker(FFLOAD_WAV, "sound"); return true; } + + protected: + // Inherited from AIFileUpload. + /*virtual*/ void handle_event(std::string const& filename) + { + LLFloaterNameDesc* floaterp = new LLFloaterNameDesc(filename); + LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_sound_preview.xml"); + floaterp->childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", LLGlobalEconomy::Singleton::getInstance()->getPriceUpload() )); + } }; -class LLFileUploadAnim : public view_listener_t +class LLFileUploadAnim : public view_listener_t, public AIFileUpload { bool handleEvent(LLPointer event, const LLSD& userdata) { - const std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_ANIM); - if (!filename.empty()) - { - LLFloaterAnimPreview* floaterp = new LLFloaterAnimPreview(filename); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_animation_preview.xml"); - } + start_filepicker(FFLOAD_ANIM, "animations"); return true; } + + protected: + // Inherited from AIFileUpload. + /*virtual*/ void handle_event(std::string const& filename) + { + LLFloaterAnimPreview* floaterp = new LLFloaterAnimPreview(filename); + LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_animation_preview.xml"); + } }; class LLFileUploadBulk : public view_listener_t { - static bool onConfirmBulkUploadTemp(const LLSD& notification, const LLSD& response ) - { - S32 option = LLNotification::getSelectedOption(notification, response); - BOOL enabled; - if(option == 0) // yes - enabled = TRUE; - else if(option == 1) //no - enabled = FALSE; - else //cancel - return false; - - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getMultipleOpenFiles()) - { - //const std::string& filename = picker.getFirstFile(); - std::string filename; - while(!(filename = picker.getNextFile()).empty()) - { - std::string name = gDirUtilp->getBaseFileName(filename, true); - - std::string asset_name = name; - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback = NULL; - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - void *userdata = NULL; - gSavedSettings.setBOOL("TemporaryUpload",enabled); - upload_new_resource(filename, asset_name, asset_name, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), - display_name, - callback, expected_upload_cost, userdata); - - } - } - else - { - llinfos << "Couldn't import objects from file" << llendl; - gSavedSettings.setBOOL("TemporaryUpload",FALSE); - } - return false; - } bool handleEvent(LLPointer event, const LLSD& userdata) { if( gAgent.cameraMouselook() ) @@ -388,45 +356,59 @@ class LLFileUploadBulk : public view_listener_t msg.append(llformat("\nWARNING: Each upload costs L$%d if it's not temporary.",expected_upload_cost)); args["MESSAGE"] = msg; LLNotifications::instance().add("GenericAlertYesNoCancel", args, LLSD(), onConfirmBulkUploadTemp); - /* moved to the callback for the above - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getMultipleOpenFiles()) - { - // - - //const std::string& filename = picker.getFirstFile(); - std::string filename; - while(!(filename = picker.getNextFile()).empty()) - { - // - std::string name = gDirUtilp->getBaseFileName(filename, true); - - std::string asset_name = name; - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback = NULL; - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - void *userdata = NULL; - upload_new_resource(filename, asset_name, asset_name, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), - display_name, - callback, expected_upload_cost, userdata); + return true; + } + + static bool onConfirmBulkUploadTemp(const LLSD& notification, const LLSD& response ) + { + S32 option = LLNotification::getSelectedOption(notification, response); + bool enabled; + if (option == 0) // yes + enabled = true; + else if(option == 1) // no + enabled = false; + else // cancel + return false; + + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_ALL, "", "openfile", true); + filepicker->run(boost::bind(&LLFileUploadBulk::onConfirmBulkUploadTemp_continued, enabled, filepicker)); + return true; + } + + static void onConfirmBulkUploadTemp_continued(bool enabled, AIFilePicker* filepicker) + { + if (filepicker->hasFilename()) + { + std::vector const& file_names(filepicker->getFilenames()); + for (std::vector::const_iterator iter = file_names.begin(); iter != file_names.end(); ++iter) + { + std::string const& filename(*iter); + if (filename.empty()) + continue; + std::string name = gDirUtilp->getBaseFileName(filename, true); + + std::string asset_name = name; + LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); + LLStringUtil::replaceChar(asset_name, '|', '?'); + LLStringUtil::stripNonprintable(asset_name); + LLStringUtil::trim(asset_name); + + std::string display_name = LLStringUtil::null; + LLAssetStorage::LLStoreAssetCallback callback = NULL; + S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); + void *userdata = NULL; + gSavedSettings.setBOOL("TemporaryUpload", enabled); + upload_new_resource(filename, asset_name, asset_name, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), + display_name, callback, expected_upload_cost, userdata); - // *NOTE: Ew, we don't iterate over the file list here, - // we handle the next files in upload_done_callback() - // not anymore! } } else { - llinfos << "Couldn't import objects from file" << llendl; + gSavedSettings.setBOOL("TemporaryUpload", FALSE); } - */ - return true; } }; @@ -438,7 +420,7 @@ void upload_error(const std::string& error_message, const std::string& label, co { lldebugs << "unable to remove temp file" << llendl; } - LLFilePicker::instance().reset(); + //AIFIXME? LLFilePicker::instance().reset(); } class LLFileEnableCloseWindow : public view_listener_t @@ -552,8 +534,6 @@ class LLFileTakeSnapshotToDisk : public view_listener_t 6144, supersample)) { - gViewerWindow->playSnapshotAnimAndSound(); - LLPointer formatted; switch(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat"))) { @@ -603,44 +583,39 @@ class LLFileQuit : public view_listener_t } }; -void handle_upload(void* data) -{ - const std::string filename = upload_pick(data); - if (!filename.empty()) - { - LLFloaterNameDesc* floaterp = new LLFloaterNameDesc(filename); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_name_description.xml"); - floaterp->childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", LLGlobalEconomy::Singleton::getInstance()->getPriceUpload() )); - } -} - +static void handle_compress_image_continued(AIFilePicker* filepicker); void handle_compress_image(void*) { - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_IMAGE, "", "openfile", true); + filepicker->run(boost::bind(&handle_compress_image_continued, filepicker)); +} + +static void handle_compress_image_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + return; + + std::vector const& filenames(filepicker->getFilenames()); + for(std::vector::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { - std::string infile = picker.getFirstFile(); - while (!infile.empty()) + std::string const& infile(*filename); + std::string outfile = infile + ".j2c"; + + llinfos << "Input: " << infile << llendl; + llinfos << "Output: " << outfile << llendl; + + BOOL success; + + success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); + + if (success) { - std::string outfile = infile + ".j2c"; - - llinfos << "Input: " << infile << llendl; - llinfos << "Output: " << outfile << llendl; - - BOOL success; - - success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); - - if (success) - { - llinfos << "Compression complete" << llendl; - } - else - { - llinfos << "Compression failed: " << LLImage::getLastError() << llendl; - } - - infile = picker.getNextFile(); + llinfos << "Compression complete" << llendl; + } + else + { + llinfos << "Compression failed: " << LLImage::getLastError() << llendl; } } } @@ -990,7 +965,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, { lldebugs << "unable to remove temp file" << llendl; } - LLFilePicker::instance().reset(); + //AIFIXME? LLFilePicker::instance().reset(); } } // @@ -1139,32 +1114,6 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt LLUploadDialog::modalUploadFinished(); delete data; - - // *NOTE: This is a pretty big hack. What this does is check the - // file picker if there are any more pending uploads. If so, - // upload that file. - /* Agreed, let's not use it. -HgB - const std::string& next_file = LLFilePicker::instance().getNextFile(); - if(is_balance_sufficient && !next_file.empty()) - { - std::string asset_name = gDirUtilp->getBaseFileName(next_file, true); - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback = NULL; - void *userdata = NULL; - upload_new_resource(next_file, asset_name, asset_name, // file - 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, - PERM_NONE, PERM_NONE, PERM_NONE, - display_name, - callback, - expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost - userdata); - } - */ } void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_type, diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 0e03429e9..c92e82da3 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -78,6 +78,4 @@ void upload_new_resource(const LLTransactionID &tid, S32 expected_upload_cost, void *userdata); -const std::string upload_pick(void* data); - #endif diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 6c66831c9..e99b20306 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -49,7 +49,6 @@ #include "llchat.h" #include "lldbstrings.h" #include "lleconomy.h" -#include "llfilepicker.h" #include "llfocusmgr.h" #include "llfollowcamparams.h" #include "llinstantmessage.h" diff --git a/indra/newview/llviewerobjectbackup.cpp b/indra/newview/llviewerobjectbackup.cpp index c944780af..51d0a4336 100644 --- a/indra/newview/llviewerobjectbackup.cpp +++ b/indra/newview/llviewerobjectbackup.cpp @@ -56,7 +56,7 @@ #include "llagent.h" #include "llappviewer.h" #include "llassetuploadresponders.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llfloateranimpreview.h" #include "llfloaterbuycurrency.h" #include "llfloaterimagepreview.h" @@ -341,14 +341,20 @@ void LLObjectBackup::exportObject() mThisGroup.clear(); // Open the file save dialog - LLFilePicker& file_picker = LLFilePicker::instance(); - if (!file_picker.getSaveFile(LLFilePicker::FFSAVE_XML)) + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open("", FFSAVE_XML); + filepicker->run(boost::bind(&LLObjectBackup::exportObject_continued, this, filepicker)); +} + +void LLObjectBackup::exportObject_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) { // User canceled save. return; } - mFileName = file_picker.getCurFile(); + mFileName = filepicker->getFilename(); mFolder = gDirUtilp->getDirName(mFileName); mNonExportedTextures = TEXTURE_OK; @@ -733,14 +739,19 @@ void LLObjectBackup::importObject(bool upload) mRetexture = upload; // Open the file open dialog - LLFilePicker& file_picker = LLFilePicker::instance(); - if (!file_picker.getOpenFile(LLFilePicker::FFLOAD_XML)) - { - // User canceled save. - return; - } + AIFilePicker* filepicker = new AIFilePicker; + filepicker->open(FFLOAD_XML, "", "import"); + filepicker->run(boost::bind(&LLObjectBackup::importObject_continued, this, filepicker)); - std::string file_name = file_picker.getFirstFile().c_str(); + return; +} + +void LLObjectBackup::importObject_continued(AIFilePicker* filepicker) +{ + if (!filepicker->hasFilename()) + return; + + std::string file_name = filepicker->getFilename(); mFolder = gDirUtilp->getDirName(file_name); llifstream import_file(file_name); LLSDSerialize::fromXML(mLLSD, import_file); @@ -762,7 +773,7 @@ void LLObjectBackup::importObject(bool upload) if (mObjects <= 0) { LLSD args; - args["MESSAGE"] = std::string("Object import failed.\nThe XML file has an incompatble format or does not contain any objects."); + args["MESSAGE"] = std::string("Object import failed.\nThe XML file has an incompatible format or does not contain any objects."); LLNotifications::instance().add("GenericAlert", args); llwarns << "Trying to import illegal XML object file." << llendl; return; diff --git a/indra/newview/llviewerobjectbackup.h b/indra/newview/llviewerobjectbackup.h index 46ca5f916..5ae33c382 100644 --- a/indra/newview/llviewerobjectbackup.h +++ b/indra/newview/llviewerobjectbackup.h @@ -56,9 +56,11 @@ public: // Import entry point void importObject(bool upload=FALSE); + void importObject_continued(AIFilePicker* filepicker); // Export entry point void exportObject(); + void exportObject_continued(AIFilePicker* filepicker); // Update map from texture worker void updateMap(LLUUID uploaded_asset); diff --git a/indra/newview/llviewerparcelmedia.h b/indra/newview/llviewerparcelmedia.h index 7531a0f59..50e7aaa2c 100644 --- a/indra/newview/llviewerparcelmedia.h +++ b/indra/newview/llviewerparcelmedia.h @@ -34,6 +34,7 @@ #define LLVIEWERPARCELMEDIA_H #include "llviewermedia.h" +#include "llviewermediaobserver.h" // For use by other patches so they know that media filtering is implemented. #define MEDIA_FILTERING 1 @@ -42,7 +43,6 @@ class LLMessageSystem; class LLParcel; class LLViewerParcelMediaNavigationObserver; - // This class understands land parcels, network traffic, LSL media // transport commands, and talks to the LLViewerMedia class to actually // do playback. It allows us to remove code from LLViewerParcelMgr. diff --git a/indra/newview/llviewerpluginmanager.cpp b/indra/newview/llviewerpluginmanager.cpp new file mode 100644 index 000000000..fdd48736e --- /dev/null +++ b/indra/newview/llviewerpluginmanager.cpp @@ -0,0 +1,66 @@ +/** + * @file llviewerpluginmanager.cpp + * @brief Client interface to the plugin engine + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llviewerpluginmanager.h" +#include "llnotifications.h" + +void LLViewerPluginManager::destroyPlugin() +{ + delete mPluginBase; + mPluginBase = NULL; +} + +void LLViewerPluginManager::update() +{ + if (!mPluginBase) + { + return; + } + + mPluginBase->idle(); + + if (mPluginBase->isPluginExited()) + { + destroyPlugin(); + return; + } +} + +void LLViewerPluginManager::send_plugin_failure_warning(std::string const& plugin_basename) +{ + LL_WARNS("Plugin") << "plugin intialization failed for plugin: " << plugin_basename << LL_ENDL; + LLSD args; + args["MIME_TYPE"] = plugin_basename; // FIXME: Use different notification. + LLNotifications::instance().add("NoPlugin", args); +} + diff --git a/indra/newview/llviewerpluginmanager.h b/indra/newview/llviewerpluginmanager.h new file mode 100644 index 000000000..6525a5403 --- /dev/null +++ b/indra/newview/llviewerpluginmanager.h @@ -0,0 +1,114 @@ +/** + * @file llviewerpluginmanager.h + * @brief Client interface to the plugin engine + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLVIEWERPLUGINMANAGER_H +#define LLVIEWERPLUGINMANAGER_H + +#include +#include "llmemory.h" +#include "llerror.h" +#include "lldir.h" +#include "llfile.h" +#include "llviewercontrol.h" +#include "llpluginclassbasic.h" + +class LLViewerPluginManager : public LLRefCount +{ + LOG_CLASS(LLViewerPluginManager); + +public: + // Construct an uninitialized LLViewerPluginManager object. + LLViewerPluginManager(void) : mPluginBase(NULL) { } + + // Create a PLUGIN_TYPE (must be derived from LLPluginClassBasic). + // This uses PLUGIN_TYPE::launcher_name() and PLUGIN_TYPE::plugin_basename(). + // If successful, returns the created LLPluginClassBasic, NULL otherwise. + template + LLPluginClassBasic* createPlugin(T* user_data); + + // Delete the plugin. + void destroyPlugin(); + + // Handle plugin messages. + virtual void update(); + + // Return pointer to plugin. + LLPluginClassBasic* getPlugin(void) const { return mPluginBase; } + +private: + // Called from createPlugin. + void send_plugin_failure_warning(std::string const& plugin_basename); + +protected: + LLPluginClassBasic* mPluginBase; //!< Pointer to the base class of the underlaying plugin. +}; + +template +LLPluginClassBasic* LLViewerPluginManager::createPlugin(T* user_data) +{ + // Always delete the old plugin first. + destroyPlugin(); + + std::string plugin_name = gDirUtilp->getLLPluginFilename(PLUGIN_TYPE::plugin_basename()); + + // See if the plugin executable exists. + llstat s; + if (LLFile::stat(PLUGIN_TYPE::launcher_name(), &s)) + { + LL_WARNS("Plugin") << "Couldn't find launcher at " << PLUGIN_TYPE::launcher_name() << LL_ENDL; + } + else if (LLFile::stat(plugin_name, &s)) + { + LL_WARNS("Plugin") << "Couldn't find plugin at " << plugin_name << LL_ENDL; + } + else + { + LLPluginClassBasic* plugin = new PLUGIN_TYPE(user_data); + if (plugin->init(PLUGIN_TYPE::launcher_name(), plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))) + { + mPluginBase = plugin; + } + else + { + LL_WARNS("Plugin") << "Failed to init plugin. Destroying." << LL_ENDL; + delete plugin; + } + } + + if (mPluginBase) + return mPluginBase; + + send_plugin_failure_warning(PLUGIN_TYPE::plugin_basename()); + return NULL; +} + +#endif // LLVIEWERPLUGINMANAGER_H diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 2055f54b2..a2baf176e 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -416,6 +416,7 @@ void LLEmbeddedItems::bindEmbeddedChars( const LLFontGL* font ) const break; case LLAssetType::AT_SOUND: img_name = "inv_item_sound.tga"; break; + case LLAssetType::AT_CALLINGCARD: img_name = "inv_item_callingcard_online.tga"; break; case LLAssetType::AT_LANDMARK: if (item->getFlags() & LLInventoryItemFlags::II_FLAGS_LANDMARK_VISITED) { diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index e818cd514..d1c3a40f2 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -2681,7 +2681,12 @@ void LLViewerFetchedTexture::setCachedRawImage() { --i ; } - + if (mRawImage->getComponents() == 5) + { + llwarns << "IMP-582: Trying to scale an image (" << mID << ") with 5 components!" << llendl; + mIsRawImageValid = 0; + return; + } mRawImage->scale(w >> i, h >> i) ; } if(mCachedRawImage.notNull()) @@ -2716,6 +2721,13 @@ void LLViewerFetchedTexture::saveRawImage() return ; } + // This shouldn't happen, but it did on Snowglobe 1.5. Better safe than sorry? + if (!mRawImage->getData()) + { + llwarns << "mRawImage->getData() returns NULL" << llendl; + return; + } + mSavedRawDiscardLevel = mRawDiscardLevel ; mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()) ; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 61eb5f075..77d1e7f94 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -89,7 +89,7 @@ #include "llmaniptranslate.h" #include "llface.h" #include "llfeaturemanager.h" -#include "llfilepicker.h" +#include "statemachine/aifilepicker.h" #include "llfloater.h" #include "llfloateractivespeakers.h" #include "llfloaterbuildoptions.h" @@ -3988,50 +3988,62 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d } // Saves an image to the harddrive as "SnapshotX" where X >= 1. -BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image) +void LLViewerWindow::saveImageNumbered(LLPointer image) { if (!image) { - return FALSE; + return; } - LLFilePicker::ESaveFilter pick_type; + ESaveFilter pick_type; std::string extension("." + image->getExtension()); if (extension == ".j2c") - pick_type = LLFilePicker::FFSAVE_J2C; + pick_type = FFSAVE_J2C; else if (extension == ".bmp") - pick_type = LLFilePicker::FFSAVE_BMP; + pick_type = FFSAVE_BMP; else if (extension == ".jpg") - pick_type = LLFilePicker::FFSAVE_JPEG; + pick_type = FFSAVE_JPEG; else if (extension == ".png") - pick_type = LLFilePicker::FFSAVE_PNG; + pick_type = FFSAVE_PNG; else if (extension == ".tga") - pick_type = LLFilePicker::FFSAVE_TGA; + pick_type = FFSAVE_TGA; else - pick_type = LLFilePicker::FFSAVE_ALL; // ??? + pick_type = FFSAVE_ALL; // ??? // Get a base file location if needed. if ( ! isSnapshotLocSet()) { std::string proposed_name( sSnapshotBaseName ); - // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in. + // AIFilePicker will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in. // pick a directory in which to save - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getSaveFile(pick_type, proposed_name)) - { - // Clicked cancel - return FALSE; - } + AIFilePicker* filepicker = new AIFilePicker; // Deleted in LLViewerWindow::saveImageNumbered_continued1 + filepicker->open(proposed_name, pick_type, "", "snapshot"); + filepicker->run(boost::bind(&LLViewerWindow::saveImageNumbered_continued1, this, image, extension, filepicker)); + return; + } + // LLViewerWindow::sSnapshotBaseName and LLViewerWindow::sSnapshotDir already known. Go straight to saveImageNumbered_continued2. + saveImageNumbered_continued2(image, extension); +} + +void LLViewerWindow::saveImageNumbered_continued1(LLPointer image, std::string const& extension, AIFilePicker* filepicker) +{ + if (filepicker->hasFilename()) + { // Copy the directory + file name - std::string filepath = picker.getFirstFile(); + std::string filepath = filepicker->getFilename(); LLViewerWindow::sSnapshotBaseName = gDirUtilp->getBaseFileName(filepath, true); LLViewerWindow::sSnapshotDir = gDirUtilp->getDirName(filepath); - } + saveImageNumbered_continued2(image, extension); + } +} + +void LLViewerWindow::saveImageNumbered_continued2(LLPointer image, std::string const& extension) +{ // Look for an unused file name std::string filepath; S32 i = 1; @@ -4051,7 +4063,10 @@ BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image) } while( -1 != err ); // search until the file is not found (i.e., stat() gives an error). - return image->save(filepath); + if (image->save(filepath)) + { + playSnapshotAnimAndSound(); + } } void LLViewerWindow::resetSnapshotLoc() diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 21867f7eb..dec5a177c 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -60,6 +60,7 @@ class LLTextBox; class LLImageRaw; class LLHUDIcon; class LLMouseHandler; +class AIFilePicker; #define PICK_HALF_WIDTH 5 #define PICK_DIAMETER (2 * PICK_HALF_WIDTH + 1) @@ -282,19 +283,21 @@ public: // snapshot functionality. // perhaps some of this should move to llfloatershapshot? -MG - typedef enum e_snapshot_type + enum ESnapshotType { SNAPSHOT_TYPE_COLOR, SNAPSHOT_TYPE_DEPTH, SNAPSHOT_TYPE_OBJECT_ID - } ESnapshotType; + }; BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR); BOOL rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE, F32 supersample = 1.f ); BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) ; BOOL isSnapshotLocSet() const { return ! sSnapshotDir.empty(); } void resetSnapshotLoc() const { sSnapshotDir.clear(); } - BOOL saveImageNumbered(LLImageFormatted *image); + void saveImageNumbered(LLPointer image); + void saveImageNumbered_continued1(LLPointer image, std::string const& extension, AIFilePicker* filepicker); + void saveImageNumbered_continued2(LLPointer image, std::string const& extension); // Reset the directory where snapshots are saved. // Client will open directory picker on next snapshot save. diff --git a/indra/newview/skins/default/xui/en-us/floater_snapshot.xml b/indra/newview/skins/default/xui/en-us/floater_snapshot.xml index 65e7d0fae..5b86ce319 100644 --- a/indra/newview/skins/default/xui/en-us/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en-us/floater_snapshot.xml @@ -32,6 +32,7 @@ list_position="below" mouse_opaque="true" name="save_btn" tool_tip="Save image to a file" width="105"> Save + Save As...