Merge branch 'master' of https://github.com/AlericInglewood/SingularityViewer.git
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
4
indra/cmake/AIStateMachine.cmake
Normal file
4
indra/cmake/AIStateMachine.cmake
Normal file
@@ -0,0 +1,4 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
set(AISTATEMACHINE_INCLUDE_DIRS statemachine)
|
||||
set(AISTATEMACHINE_LIBRARIES statemachine)
|
||||
8
indra/cmake/BasicPluginBase.cmake
Normal file
8
indra/cmake/BasicPluginBase.cmake
Normal file
@@ -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)
|
||||
1
indra/cmake/Cwdebug.cmake
Normal file
1
indra/cmake/Cwdebug.cmake
Normal file
@@ -0,0 +1 @@
|
||||
set(CWDEBUG_LIBRARIES cwdebug)
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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})
|
||||
|
||||
33
indra/cwdebug/CMakeLists.txt
Normal file
33
indra/cwdebug/CMakeLists.txt
Normal file
@@ -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})
|
||||
9
indra/cwdebug/cwdebug.h
Normal file
9
indra/cwdebug/cwdebug.h
Normal file
@@ -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"
|
||||
413
indra/cwdebug/debug.cc
Normal file
413
indra/cwdebug/debug.cc
Normal file
@@ -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 <carlo@alinoe.com>
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef USE_PCH
|
||||
#include "sys.h" // Needed for platform-specific code
|
||||
#endif
|
||||
|
||||
#ifdef CWDEBUG
|
||||
|
||||
#ifndef USE_PCH
|
||||
#include <cctype> // Needed for std::isprint
|
||||
#include <iomanip> // Needed for setfill and setw
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include "debug.h"
|
||||
#ifdef USE_LIBCW
|
||||
#include <libcw/memleak.h> // memleak_filter
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif // USE_PCH
|
||||
|
||||
#define BACKTRACE_AQUIRE_LOCK libcwd::_private_::mutex_tct<libcwd::_private_::backtrace_instance>::lock()
|
||||
#define BACKTRACE_RELEASE_LOCK libcwd::_private_::mutex_tct<libcwd::_private_::backtrace_instance>::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<BackTrace, int, std::less<BackTrace>, 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<backtrace_map_t::iterator, bool> 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<backtrace_map_t::const_iterator> 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<backtrace_map_t::const_iterator>::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<std::string, bool> 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<rcfile_dc_states_type::iterator, bool> 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 (<tt>channel_ct::get_label</tt>) of an
|
||||
* existing debug channel, this function returns \c true when the corresponding debug channel was
|
||||
* <em>on</em> 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<std::pair<std::string, std::string> > hide_list;
|
||||
hide_list.push_back(std::pair<std::string, std::string>("libdl.so.2", "_dlerror_run"));
|
||||
hide_list.push_back(std::pair<std::string, std::string>("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<std::string, std::string>("libc.so.6", "dl_open_worker"));
|
||||
memleak_filter().hide_functions_matching(hide_list);
|
||||
}
|
||||
{
|
||||
std::vector<std::string> 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<BackTrace> __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
|
||||
257
indra/cwdebug/debug.h
Normal file
257
indra/cwdebug/debug.h
Normal file
@@ -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 <carlo@alinoe.com>
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#ifndef CWDEBUG
|
||||
|
||||
#ifndef DOXYGEN // No need to document this. See http://libcwd.sourceforge.net/ for more info.
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib> // 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 <cassert>
|
||||
#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.
|
||||
//
|
||||
// <A HREF="http://libcwd.sourceforge.net/">Libcwd</A> demands that this macro is defined
|
||||
// before <libcwd/debug.h> 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 <libcwd/debug.h>
|
||||
#include <boost/shared_array.hpp>
|
||||
#if CWDEBUG_LOCATION
|
||||
#include <execinfo.h> // 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<void*> 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<void*> const& buffer(void) const { return M_buffer; }
|
||||
};
|
||||
extern std::vector<BackTrace> 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
|
||||
1
indra/cwdebug/debug_ostream_operators.h
Normal file
1
indra/cwdebug/debug_ostream_operators.h
Normal file
@@ -0,0 +1 @@
|
||||
// Empty so far...
|
||||
9
indra/cwdebug/sys.h
Normal file
9
indra/cwdebug/sys.h
Normal file
@@ -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 <libcwd/sys.h>
|
||||
#endif
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -195,4 +195,9 @@ private:
|
||||
static const char* mAssetTypeHumanNames[];
|
||||
};
|
||||
|
||||
#ifdef CWDEBUG
|
||||
#include <iosfwd>
|
||||
inline std::ostream& operator<<(std::ostream& os, LLAssetType::EType type) { return os << LLAssetType::getDesc(type); }
|
||||
#endif
|
||||
|
||||
#endif // LL_LLASSETTYPE
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
# include <unistd.h>
|
||||
#endif // !LL_WINDOWS
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
#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;
|
||||
|
||||
|
||||
@@ -177,6 +177,7 @@ public:
|
||||
FTM_REFRESH,
|
||||
FTM_SORT,
|
||||
FTM_PICK,
|
||||
FTM_STATEMACHINE,
|
||||
|
||||
// Temp
|
||||
FTM_TEMP1,
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
#ifndef LL_LLINDRACONFIGFILE_H
|
||||
#define LL_LLINDRACONFIGFILE_H
|
||||
|
||||
#include <string>
|
||||
#include "linden_common.h"
|
||||
#include <string>
|
||||
|
||||
#include "lllivefile.h"
|
||||
#include "llsd.h"
|
||||
|
||||
@@ -32,7 +32,11 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <apr_file_io.h>
|
||||
#include <apr_thread_proc.h>
|
||||
#include "llprocesslauncher.h"
|
||||
#include "aiaprpool.h"
|
||||
|
||||
#include <iostream>
|
||||
#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<unsigned char*>(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
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <deque>
|
||||
#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<std::pair<int, Data*>, compare_pair<int, Data*> > some_pair_set_t;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -29,13 +29,15 @@
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include "llcrashlogger.h"
|
||||
#include "linden_common.h"
|
||||
#include "llstring.h"
|
||||
#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
|
||||
#include "llerror.h"
|
||||
|
||||
@@ -32,10 +32,10 @@
|
||||
#ifndef LLCRASHLOGGER_H
|
||||
#define LLCRASHLOGGER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "llapp.h"
|
||||
#include "llsd.h"
|
||||
#include "llcontrol.h"
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
*/
|
||||
|
||||
// Precompiled header: almost always required for newview cpp files
|
||||
#include "../llcommon/linden_common.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "linden_common.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "llsaleinfo.h"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// <edit>
|
||||
#include "llnetcanary.h"
|
||||
#include "linden_common.h"
|
||||
#include "llnetcanary.h"
|
||||
#include "llerror.h"
|
||||
#ifdef _MSC_VER
|
||||
#include <winsock2.h>
|
||||
|
||||
@@ -30,13 +30,12 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "net.h"
|
||||
#include "llhost.h"
|
||||
#include "message.h"
|
||||
#include "llsocks5.h"
|
||||
#include <string>
|
||||
|
||||
// Static class variable instances
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
189
indra/llplugin/llpluginclassbasic.cpp
Normal file
189
indra/llplugin/llpluginclassbasic.cpp
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
129
indra/llplugin/llpluginclassbasic.h
Normal file
129
indra/llplugin/llpluginclassbasic.h
Normal file
@@ -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 <string>
|
||||
#include <queue>
|
||||
|
||||
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<LLPluginMessage> 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
|
||||
@@ -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)
|
||||
|
||||
@@ -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 <queue>
|
||||
#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<LLPluginMessage> 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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
#include "llpluginprocessparent.h"
|
||||
#include "llpluginmessagepipe.h"
|
||||
#include "llpluginmessageclasses.h"
|
||||
#if LL_LINUX
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
#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<std::string> tokens = boost::program_options::split_unix(terminal_command, " ");
|
||||
std::vector<std::string>::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")<<msg<<LL_ENDL;
|
||||
break;
|
||||
case LLPluginMessage::LOG_LEVEL_INFO:
|
||||
LL_INFOS("Plugin child")<<msg<<LL_ENDL;
|
||||
break;
|
||||
case LLPluginMessage::LOG_LEVEL_WARN:
|
||||
LL_WARNS("Plugin child")<<msg<<LL_ENDL;
|
||||
break;
|
||||
case LLPluginMessage::LOG_LEVEL_ERR:
|
||||
LL_ERRS("Plugin child")<<msg<<LL_ENDL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("Plugin") << "Unknown internal message from child: " << message_name << LL_ENDL;
|
||||
|
||||
@@ -53,6 +53,7 @@ public:
|
||||
virtual ~LLPluginProcessParentOwner();
|
||||
virtual void receivePluginMessage(const LLPluginMessage &message) = 0;
|
||||
virtual bool receivePluginMessageEarly(const LLPluginMessage &message) {return false;};
|
||||
virtual void receivedShutdown() = 0;
|
||||
// This will only be called when the plugin has died unexpectedly
|
||||
virtual void pluginLaunchFailed() {};
|
||||
virtual void pluginDied() {};
|
||||
@@ -88,6 +89,9 @@ public:
|
||||
// Go to the proper error state
|
||||
void errorState(void);
|
||||
|
||||
// Go to exit state.
|
||||
void exitState(void) { setState(STATE_EXITING); }
|
||||
|
||||
void setSleepTime(F64 sleep_time, bool force_send = false);
|
||||
F64 getSleepTime(void) const { return mSleepTime; };
|
||||
|
||||
@@ -99,6 +103,7 @@ public:
|
||||
/*virtual*/ void receiveMessageRaw(const std::string &message);
|
||||
/*virtual*/ void receiveMessageEarly(const LLPluginMessage &message);
|
||||
/*virtual*/ void setMessagePipe(LLPluginMessagePipe *message_pipe) ;
|
||||
/*virtual*/ apr_status_t socketError(apr_status_t error);
|
||||
|
||||
// This adds a memory segment shared with the client, generating a name for the segment. The name generated is guaranteed to be unique on the host.
|
||||
// The caller must call removeSharedMemory first (and wait until getSharedMemorySize returns 0 for the indicated name) before re-adding a segment with the same name.
|
||||
@@ -140,8 +145,8 @@ private:
|
||||
STATE_RUNNING, //
|
||||
STATE_LAUNCH_FAILURE, // Failure before plugin loaded
|
||||
STATE_ERROR, // generic bailout state
|
||||
STATE_CLEANUP, // clean everything up
|
||||
STATE_EXITING, // Tried to kill process, waiting for it to exit
|
||||
STATE_CLEANUP, // clean everything up
|
||||
STATE_DONE //
|
||||
|
||||
};
|
||||
@@ -178,6 +183,7 @@ private:
|
||||
bool mDebug;
|
||||
bool mBlocked;
|
||||
bool mPolledInput;
|
||||
bool mReceivedShutdown;
|
||||
|
||||
LLProcessLauncher mDebugger;
|
||||
|
||||
|
||||
@@ -183,6 +183,13 @@ int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdL
|
||||
int main(int argc, char **argv)
|
||||
#endif
|
||||
{
|
||||
#ifdef CWDEBUG
|
||||
Debug( libcw_do.margin().assign("SLPlugin ", 9) );
|
||||
Debug(debug::init());
|
||||
// Uncomment this to automatically open a terminal with gdb. Requires SNOW-173.
|
||||
//Debug(attach_gdb());
|
||||
#endif
|
||||
|
||||
// Set up llerror logging
|
||||
{
|
||||
LLError::initForApplication(".");
|
||||
|
||||
@@ -1356,14 +1356,20 @@ LLFloater* LLFloater::getClosableFloaterFromFocus()
|
||||
|
||||
// The focused floater may not be closable,
|
||||
// Find and close a parental floater that is closeable, if any.
|
||||
LLFloater* previous_floater = NULL; // Guard against endless loop, because getParentFloater(x) can return x!
|
||||
for(LLFloater* floater_to_close = focused_floater;
|
||||
NULL != floater_to_close;
|
||||
floater_to_close = gFloaterView->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;
|
||||
|
||||
@@ -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++ )
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
@@ -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 <time.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 <stdio.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#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
|
||||
@@ -1,167 +0,0 @@
|
||||
/**
|
||||
* @file llmediaimplgstreamer_syms.cpp
|
||||
* @brief dynamic GStreamer symbol-grabbing code
|
||||
*
|
||||
* @cond
|
||||
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
#if LL_GSTREAMER010_ENABLED
|
||||
|
||||
#include <string>
|
||||
|
||||
extern "C" {
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "apr_pools.h"
|
||||
#include "apr_dso.h"
|
||||
}
|
||||
|
||||
#include "llmediaimplgstreamertriviallogging.h"
|
||||
|
||||
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL
|
||||
#include "llmediaimplgstreamer_syms_raw.inc"
|
||||
#include "llmediaimplgstreamer_syms_rawv.inc"
|
||||
#undef LL_GST_SYM
|
||||
|
||||
// a couple of stubs for disgusting reasons
|
||||
GstDebugCategory*
|
||||
ll_gst_debug_category_new(gchar *name, guint color, gchar *description)
|
||||
{
|
||||
static GstDebugCategory dummy;
|
||||
return &dummy;
|
||||
}
|
||||
void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname)
|
||||
{
|
||||
}
|
||||
|
||||
static bool sSymsGrabbed = false;
|
||||
static apr_pool_t *sSymGSTDSOMemoryPool = NULL;
|
||||
static apr_dso_handle_t *sSymGSTDSOHandleG = NULL;
|
||||
static apr_dso_handle_t *sSymGSTDSOHandleV = NULL;
|
||||
|
||||
|
||||
bool grab_gst_syms(std::string gst_dso_name,
|
||||
std::string gst_dso_name_vid)
|
||||
{
|
||||
if (sSymsGrabbed)
|
||||
{
|
||||
// already have grabbed good syms
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool sym_error = false;
|
||||
bool rtn = false;
|
||||
apr_status_t rv;
|
||||
apr_dso_handle_t *sSymGSTDSOHandle = NULL;
|
||||
|
||||
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##GSTSYM, sSymGSTDSOHandle, #GSTSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #GSTSYM); if (REQ) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #GSTSYM, (void*)ll##GSTSYM);}while(0)
|
||||
|
||||
//attempt to load the shared libraries
|
||||
apr_pool_create(&sSymGSTDSOMemoryPool, NULL);
|
||||
|
||||
if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle,
|
||||
gst_dso_name.c_str(),
|
||||
sSymGSTDSOMemoryPool) ))
|
||||
{
|
||||
INFOMSG("Found DSO: %s", gst_dso_name.c_str());
|
||||
#include "llmediaimplgstreamer_syms_raw.inc"
|
||||
|
||||
if ( sSymGSTDSOHandle )
|
||||
{
|
||||
sSymGSTDSOHandleG = sSymGSTDSOHandle;
|
||||
sSymGSTDSOHandle = NULL;
|
||||
}
|
||||
|
||||
if ( APR_SUCCESS ==
|
||||
(rv = apr_dso_load(&sSymGSTDSOHandle,
|
||||
gst_dso_name_vid.c_str(),
|
||||
sSymGSTDSOMemoryPool) ))
|
||||
{
|
||||
INFOMSG("Found DSO: %s", gst_dso_name_vid.c_str());
|
||||
#include "llmediaimplgstreamer_syms_rawv.inc"
|
||||
rtn = !sym_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
INFOMSG("Couldn't load DSO: %s", gst_dso_name_vid.c_str());
|
||||
rtn = false; // failure
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
INFOMSG("Couldn't load DSO: %s", gst_dso_name.c_str());
|
||||
rtn = false; // failure
|
||||
}
|
||||
|
||||
if (sym_error)
|
||||
{
|
||||
WARNMSG("Failed to find necessary symbols in GStreamer libraries.");
|
||||
}
|
||||
|
||||
if ( sSymGSTDSOHandle )
|
||||
{
|
||||
sSymGSTDSOHandleV = sSymGSTDSOHandle;
|
||||
sSymGSTDSOHandle = NULL;
|
||||
}
|
||||
#undef LL_GST_SYM
|
||||
|
||||
sSymsGrabbed = !!rtn;
|
||||
return rtn;
|
||||
}
|
||||
|
||||
|
||||
void ungrab_gst_syms()
|
||||
{
|
||||
// should be safe to call regardless of whether we've
|
||||
// actually grabbed syms.
|
||||
|
||||
if ( sSymGSTDSOHandleG )
|
||||
{
|
||||
apr_dso_unload(sSymGSTDSOHandleG);
|
||||
sSymGSTDSOHandleG = NULL;
|
||||
}
|
||||
|
||||
if ( sSymGSTDSOHandleV )
|
||||
{
|
||||
apr_dso_unload(sSymGSTDSOHandleV);
|
||||
sSymGSTDSOHandleV = NULL;
|
||||
}
|
||||
|
||||
if ( sSymGSTDSOMemoryPool )
|
||||
{
|
||||
apr_pool_destroy(sSymGSTDSOMemoryPool);
|
||||
sSymGSTDSOMemoryPool = NULL;
|
||||
}
|
||||
|
||||
// NULL-out all of the symbols we'd grabbed
|
||||
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{ll##GSTSYM = NULL;}while(0)
|
||||
#include "llmediaimplgstreamer_syms_raw.inc"
|
||||
#include "llmediaimplgstreamer_syms_rawv.inc"
|
||||
#undef LL_GST_SYM
|
||||
|
||||
sSymsGrabbed = false;
|
||||
}
|
||||
|
||||
|
||||
#endif // LL_GSTREAMER010_ENABLED
|
||||
@@ -1,74 +0,0 @@
|
||||
/**
|
||||
* @file llmediaimplgstreamer_syms.h
|
||||
* @brief dynamic GStreamer symbol-grabbing code
|
||||
*
|
||||
* @cond
|
||||
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#if LL_GSTREAMER010_ENABLED
|
||||
|
||||
extern "C" {
|
||||
#include <gst/gst.h>
|
||||
}
|
||||
|
||||
bool grab_gst_syms(std::string gst_dso_name,
|
||||
std::string gst_dso_name_vid);
|
||||
void ungrab_gst_syms();
|
||||
|
||||
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) extern RTN (*ll##GSTSYM)(__VA_ARGS__)
|
||||
#include "llmediaimplgstreamer_syms_raw.inc"
|
||||
#include "llmediaimplgstreamer_syms_rawv.inc"
|
||||
#undef LL_GST_SYM
|
||||
|
||||
// regrettable hacks to give us better runtime compatibility with older systems
|
||||
#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0)
|
||||
#define llg_return_val_if_fail(COND,V) do{if (!(COND)) return V;}while(0)
|
||||
|
||||
// regrettable hacks because GStreamer was not designed for runtime loading
|
||||
#undef GST_TYPE_MESSAGE
|
||||
#define GST_TYPE_MESSAGE (llgst_message_get_type())
|
||||
#undef GST_TYPE_OBJECT
|
||||
#define GST_TYPE_OBJECT (llgst_object_get_type())
|
||||
#undef GST_TYPE_PIPELINE
|
||||
#define GST_TYPE_PIPELINE (llgst_pipeline_get_type())
|
||||
#undef GST_TYPE_ELEMENT
|
||||
#define GST_TYPE_ELEMENT (llgst_element_get_type())
|
||||
#undef GST_TYPE_VIDEO_SINK
|
||||
#define GST_TYPE_VIDEO_SINK (llgst_video_sink_get_type())
|
||||
// more regrettable hacks to stub-out these .h-exposed GStreamer internals
|
||||
void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname);
|
||||
#undef _gst_debug_register_funcptr
|
||||
#define _gst_debug_register_funcptr ll_gst_debug_register_funcptr
|
||||
GstDebugCategory* ll_gst_debug_category_new(gchar *name, guint color, gchar *description);
|
||||
#undef _gst_debug_category_new
|
||||
#define _gst_debug_category_new ll_gst_debug_category_new
|
||||
#undef __gst_debug_enabled
|
||||
#define __gst_debug_enabled (0)
|
||||
|
||||
// more hacks
|
||||
#define LLGST_MESSAGE_TYPE_NAME(M) (llgst_message_type_get_name(GST_MESSAGE_TYPE(M)))
|
||||
|
||||
#endif // LL_GSTREAMER010_ENABLED
|
||||
@@ -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);
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
// required symbols to grab
|
||||
LL_GST_SYM(true, gst_video_sink_get_type, GType, void);
|
||||
|
||||
// optional symbols to grab
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* @file llmediaimplgstreamertriviallogging.h
|
||||
* @brief minimal logging utilities.
|
||||
*
|
||||
* @cond
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
#ifndef __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__
|
||||
#define __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
extern "C" {
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Debug/Info/Warning macros.
|
||||
#define MSGMODULEFOO "(media plugin)"
|
||||
#define STDERRMSG(...) do{\
|
||||
fprintf(stderr, " pid:%d: ", (int)getpid());\
|
||||
fprintf(stderr, MSGMODULEFOO " %s:%d: ", __FUNCTION__, __LINE__);\
|
||||
fprintf(stderr, __VA_ARGS__);\
|
||||
fputc('\n',stderr);\
|
||||
}while(0)
|
||||
#define NULLMSG(...) do{}while(0)
|
||||
|
||||
#define DEBUGMSG NULLMSG
|
||||
#define INFOMSG STDERRMSG
|
||||
#define WARNMSG STDERRMSG
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif /* __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ */
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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}
|
||||
|
||||
@@ -42,6 +42,15 @@
|
||||
<array>
|
||||
<string>ShaderLoading</string>
|
||||
<string>Openjpeg</string>
|
||||
<!-- Debug output about messages received from plugins: -->
|
||||
<string>Plugin</string> <!-- Everything except what is listed below -->
|
||||
<string>Plugin child</string> <!-- Plugin log messages from the plugin child process -->
|
||||
<!--<string>PluginRaw</string>--> <!-- The raw LLSD data -->
|
||||
<string>PluginRaw child</string> <!-- The raw LLSD data from the plugin child process -->
|
||||
<!--<string>PluginHeartbeat</string>--> <!-- One second interval CPU usage reports -->
|
||||
<!--<string>PluginUpdated</string>--> <!-- The mouse "updated" message -->
|
||||
<!-- Debug output about messages sent to plugins: -->
|
||||
<!--<string>PluginMouseEvent</string>--> <!-- Mouse event data sent to plugins -->
|
||||
</array>
|
||||
</map>
|
||||
</array>
|
||||
|
||||
@@ -1952,7 +1952,7 @@
|
||||
<key>PluginAttachDebuggerToPlugins</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>TODO: understand what this actually does -.-sg</string>
|
||||
<string>Opens a terminal window with a debugger and attach it, every time a new SLPlugin process is started.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
@@ -11399,6 +11399,17 @@
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>StateMachineMaxTime</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Maximum time per frame spent executing AIStateMachine objects, in miliseconds</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>20</integer>
|
||||
</map>
|
||||
<key>StatsAutoRun</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "ascentkeyword.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llui.h"
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ this feature is still a work in progress.
|
||||
#include <ctime>
|
||||
#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<std::string> const& filenames(filepicker->getFilenames());
|
||||
for(std::vector<std::string>::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 )
|
||||
|
||||
@@ -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<LLScrollListItem*>, S32 column = BITMAPLIST_COL_ID );
|
||||
|
||||
/* UpdateTextureCtrlList was made public cause texturectrl requests it once on spawn
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,9 +53,11 @@ public:
|
||||
|
||||
protected:
|
||||
// Use a list so that the callbacks are ordered in case that matters
|
||||
typedef std::pair<callback_t,void*> callback_pair_t;
|
||||
typedef std::pair<callback_t,void*> 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_pair_t > 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;
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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<LLUUID,LLSD>::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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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<LLScrollListItem*> 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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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<LLCheckBoxCtrl>("create_pretend_item")->get())
|
||||
self->add(file);
|
||||
/*if(self->getChild<LLCheckBoxCtrl>("create_pretend_item")->get())
|
||||
{
|
||||
LLLocalInventory::addItem(file.mName, (int)file.mType, file.mID, true);
|
||||
}*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
#include "llinventorybackup.h"
|
||||
//#include "llcheats.h"
|
||||
//#include "llnotecardmagic.h"
|
||||
#include "statemachine/aifilepicker.h"
|
||||
// </edit>
|
||||
|
||||
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
|
||||
|
||||
@@ -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<LLInventoryCategory*>::iterator _cat_iter = order->mCats.begin();
|
||||
std::vector<LLInventoryCategory*>::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<LLImageTGA> 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<LLImageTGA> 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
|
||||
|
||||
@@ -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<LLInventoryCategory*>& cats,
|
||||
std::vector<LLInventoryItem*>& items);
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
//#include "llcheats.h"
|
||||
#include "dofloaterhex.h"
|
||||
#include "hgfloatertexteditor.h"
|
||||
#include "statemachine/aifilepicker.h"
|
||||
// </edit>
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
// </edit>
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#define LL_LLMediaCtrl_H
|
||||
|
||||
#include "llviewermedia.h"
|
||||
|
||||
#include "llviewermediaobserver.h"
|
||||
#include "lluictrl.h"
|
||||
#include "llframetimer.h"
|
||||
#include "lldynamictexture.h"
|
||||
|
||||
@@ -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<LLTabContainer>("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<LLTabContainer>("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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
// </edit>
|
||||
static void endAnimCallback( void *userdata );
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
#include "lllineeditor.h"
|
||||
#include "lluictrlfactory.h"
|
||||
// <edit>
|
||||
#include "llfilepicker.h"
|
||||
#include "statemachine/aifilepicker.h"
|
||||
// </edit>
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
@@ -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<LLViewerTextEditor>("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();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user