This commit is contained in:
Shyotl
2011-05-14 14:01:58 -05:00
178 changed files with 7497 additions and 3029 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -0,0 +1,4 @@
# -*- cmake -*-
set(AISTATEMACHINE_INCLUDE_DIRS statemachine)
set(AISTATEMACHINE_LIBRARIES statemachine)

View 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)

View File

@@ -0,0 +1 @@
set(CWDEBUG_LIBRARIES cwdebug)

View File

@@ -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
)

View File

@@ -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)

View File

@@ -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")

View File

@@ -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}

View File

@@ -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})

View 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
View 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
View 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
View 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

View File

@@ -0,0 +1 @@
// Empty so far...

9
indra/cwdebug/sys.h Normal file
View 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

View File

@@ -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(

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -177,6 +177,7 @@ public:
FTM_REFRESH,
FTM_SORT,
FTM_PICK,
FTM_STATEMACHINE,
// Temp
FTM_TEMP1,

View File

@@ -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"

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -32,6 +32,7 @@
*/
// Precompiled header: almost always required for newview cpp files
#include "../llcommon/linden_common.h"
#include <list>
#include <map>
#include <algorithm>

View File

@@ -30,8 +30,8 @@
* $/LicenseInfo$
*/
#include <iostream>
#include "linden_common.h"
#include <iostream>
#include "llsaleinfo.h"

View File

@@ -1,6 +1,6 @@
// <edit>
#include "llnetcanary.h"
#include "linden_common.h"
#include "llnetcanary.h"
#include "llerror.h"
#ifdef _MSC_VER
#include <winsock2.h>

View File

@@ -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

View File

@@ -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

View 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);
}
}

View 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

View File

@@ -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)

View File

@@ -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

View File

@@ -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.
*

View File

@@ -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;
};

View File

@@ -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;

View File

@@ -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"

View File

@@ -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))
{

View File

@@ -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);

View File

@@ -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)

View File

@@ -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.

View File

@@ -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;

View File

@@ -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;

View File

@@ -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(".");

View File

@@ -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;

View File

@@ -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++ )
{

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -1,5 +0,0 @@
// required symbols to grab
LL_GST_SYM(true, gst_video_sink_get_type, GType, void);
// optional symbols to grab

View File

@@ -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__ */

View File

@@ -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()
{
}

View File

@@ -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

View File

@@ -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}

View File

@@ -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>

View File

@@ -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>

View File

@@ -33,6 +33,7 @@
#include "ascentkeyword.h"
#include "llviewercontrol.h"
#include "llui.h"
#include <boost/regex.hpp>

View File

@@ -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 )

View File

@@ -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

View File

@@ -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());

View File

@@ -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)

View File

@@ -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,

View File

@@ -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;
}
}
}
}

View File

@@ -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;

View File

@@ -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 },

View File

@@ -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;

View File

@@ -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);

View File

@@ -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");

View File

@@ -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 );

View File

@@ -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);

View File

@@ -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:

View File

@@ -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");
}

View File

@@ -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);
};

View File

@@ -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"

View File

@@ -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();
}

View File

@@ -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);
}*/

View File

@@ -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);

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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();

View File

@@ -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(); }

View File

@@ -34,7 +34,7 @@
#define LL_LLMediaCtrl_H
#include "llviewermedia.h"
#include "llviewermediaobserver.h"
#include "lluictrl.h"
#include "llframetimer.h"
#include "lldynamictexture.h"

View File

@@ -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;

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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.

View File

@@ -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());
}

View File

@@ -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

View File

@@ -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 );

View File

@@ -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