Merge branch 'Moap' of git://github.com/Shyotl/SingularityViewer into VoiceUpdate
Conflicts:
indra/newview/llfloateravatarinfo.cpp - llpanelprofile.cpp update
indra/newview/llfloatergroupinfo.cpp - llgroupactions.cpp update
indra/newview/llfloaterobjectiminfo.cpp - simple merge
indra/newview/llstartup.cpp - Followed Shyotl's directions from 07165961dc
indra/newview/llviewermedia.cpp - includes conflict, simple stuff.
SLURL update:
indra/newview/llavataractions.cpp
indra/newview/llgroupactions.cpp
This commit is contained in:
@@ -718,7 +718,14 @@
|
||||
|
||||
<key>UploadBakedTexture</key>
|
||||
<boolean>true</boolean>
|
||||
</map>
|
||||
|
||||
<key>ObjectMedia</key>
|
||||
<boolean>false</boolean>
|
||||
|
||||
<key>ObjectMediaNavigate</key>
|
||||
<boolean>false</boolean>
|
||||
|
||||
</map>
|
||||
|
||||
<key>messageBans</key>
|
||||
<map>
|
||||
|
||||
@@ -126,7 +126,7 @@ bool LLAudioEngine::init(const S32 num_channels, void* userdata)
|
||||
// Initialize the decode manager
|
||||
gAudioDecodeMgrp = new LLAudioDecodeMgr;
|
||||
|
||||
llinfos << "LLAudioEngine::init() AudioEngine successfully initialized" << llendl;
|
||||
LL_INFOS("AudioEngine") << "LLAudioEngine::init() AudioEngine successfully initialized" << llendl;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -228,6 +228,28 @@ std::string LLAudioEngine::getInternetStreamURL()
|
||||
else return std::string();
|
||||
}
|
||||
|
||||
void LLAudioEngine::checkStates()
|
||||
{
|
||||
#ifdef SHOW_ASSERT
|
||||
for (S32 i = 0; i < MAX_BUFFERS; i++)
|
||||
{
|
||||
if (mBuffers[i])
|
||||
{
|
||||
bool buf_has_ref = false;
|
||||
for (S32 j = 0; j < MAX_CHANNELS; j++)
|
||||
{
|
||||
if (mChannels[j])
|
||||
{
|
||||
if(mChannels[j]->mCurrentBufferp == mBuffers[i])
|
||||
buf_has_ref = true;
|
||||
}
|
||||
}
|
||||
if(buf_has_ref)
|
||||
llassert(mBuffers[i]->mInUse);
|
||||
}
|
||||
}
|
||||
#endif //SHOW_ASSERT
|
||||
}
|
||||
|
||||
void LLAudioEngine::updateChannels()
|
||||
{
|
||||
@@ -239,8 +261,31 @@ void LLAudioEngine::updateChannels()
|
||||
mChannels[i]->updateBuffer();
|
||||
mChannels[i]->update3DPosition();
|
||||
mChannels[i]->updateLoop();
|
||||
#ifdef SHOW_ASSERT
|
||||
if(mChannels[i]->getSource())
|
||||
llassert(mChannels[i]->mCurrentBufferp == mChannels[i]->getSource()->getCurrentBuffer());
|
||||
if(mChannels[i]->mCurrentBufferp)
|
||||
{
|
||||
bool found_buffer = false;
|
||||
for (S32 j = 0; j < MAX_BUFFERS; j++)
|
||||
{
|
||||
if (mBuffers[j])
|
||||
{
|
||||
if(mChannels[i]->mCurrentBufferp == mBuffers[j])
|
||||
found_buffer = true;
|
||||
}
|
||||
}
|
||||
llassert(found_buffer);
|
||||
if(!mChannels[i]->mCurrentBufferp->mInUse)
|
||||
{
|
||||
llassert(!mChannels[i]->isPlaying());
|
||||
llassert(!mChannels[i]->isWaiting());
|
||||
}
|
||||
}
|
||||
#endif //SHOW_ASSERT
|
||||
}
|
||||
}
|
||||
checkStates();
|
||||
}
|
||||
|
||||
static const F32 default_max_decode_time = .002f; // 2 ms
|
||||
@@ -311,9 +356,15 @@ void LLAudioEngine::idle(F32 max_decode_time)
|
||||
LLAudioChannel *channelp = getFreeChannel(max_priority);
|
||||
if (channelp)
|
||||
{
|
||||
//llinfos << "Replacing source in channel due to priority!" << llendl;
|
||||
max_sourcep->setChannel(channelp);
|
||||
LL_DEBUGS("AudioEngine") << "Replacing source in channel due to priority!" << llendl;
|
||||
llassert(max_sourcep->getChannel() == NULL);
|
||||
|
||||
llassert(channelp->mCurrentBufferp == NULL);
|
||||
channelp->setSource(max_sourcep);
|
||||
|
||||
llassert(max_sourcep == channelp->getSource());
|
||||
llassert(channelp->mCurrentBufferp == max_sourcep->getCurrentBuffer());
|
||||
|
||||
if (max_sourcep->isSyncSlave())
|
||||
{
|
||||
// A sync slave, it doesn't start playing until it's synced up with the master.
|
||||
@@ -348,18 +399,22 @@ void LLAudioEngine::idle(F32 max_decode_time)
|
||||
}
|
||||
|
||||
LLAudioChannel *channelp = sourcep->getChannel();
|
||||
if (!channelp)
|
||||
bool is_stopped = channelp && channelp->isPlaying();
|
||||
if (is_stopped || (sourcep->isLoop() && channelp->mLoopedThisFrame))
|
||||
{
|
||||
// This sound isn't playing, so we just process move the queue
|
||||
sourcep->mCurrentDatap = sourcep->mQueuedDatap;
|
||||
sourcep->mQueuedDatap = NULL;
|
||||
|
||||
// Reset the timer so the source doesn't die.
|
||||
sourcep->mAgeTimer.reset();
|
||||
// Make sure we have the buffer set up if we just decoded the data
|
||||
if (sourcep->mCurrentDatap)
|
||||
if(is_stopped)
|
||||
{
|
||||
updateBufferForData(sourcep->mCurrentDatap);
|
||||
// Reset the timer so the source doesn't die.
|
||||
sourcep->mAgeTimer.reset();
|
||||
// Make sure we have the buffer set up if we just decoded the data
|
||||
if (sourcep->mCurrentDatap)
|
||||
{
|
||||
updateBufferForData(sourcep->mCurrentDatap);
|
||||
}
|
||||
}
|
||||
|
||||
// Actually play the associated data.
|
||||
@@ -372,52 +427,6 @@ void LLAudioEngine::idle(F32 max_decode_time)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check to see if the current sound is done playing, or looped.
|
||||
if (!channelp->isPlaying())
|
||||
{
|
||||
sourcep->mCurrentDatap = sourcep->mQueuedDatap;
|
||||
sourcep->mQueuedDatap = NULL;
|
||||
|
||||
// Reset the timer so the source doesn't die.
|
||||
sourcep->mAgeTimer.reset();
|
||||
|
||||
// Make sure we have the buffer set up if we just decoded the data
|
||||
if (sourcep->mCurrentDatap)
|
||||
{
|
||||
updateBufferForData(sourcep->mCurrentDatap);
|
||||
}
|
||||
|
||||
// Actually play the associated data.
|
||||
sourcep->setupChannel();
|
||||
channelp = sourcep->getChannel();
|
||||
if (channelp)
|
||||
{
|
||||
channelp->updateBuffer();
|
||||
channelp->play();
|
||||
}
|
||||
}
|
||||
else if (sourcep->isLoop())
|
||||
{
|
||||
// It's a loop, we need to check and see if we're done with it.
|
||||
if (channelp->mLoopedThisFrame)
|
||||
{
|
||||
sourcep->mCurrentDatap = sourcep->mQueuedDatap;
|
||||
sourcep->mQueuedDatap = NULL;
|
||||
|
||||
// Actually, should do a time sync so if we're a loop master/slave
|
||||
// we don't drift away.
|
||||
sourcep->setupChannel();
|
||||
channelp = sourcep->getChannel();
|
||||
if (channelp)
|
||||
{
|
||||
channelp->updateBuffer();
|
||||
channelp->play();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lame, update the channels AGAIN.
|
||||
@@ -491,7 +500,7 @@ void LLAudioEngine::idle(F32 max_decode_time)
|
||||
{
|
||||
if (!mBuffers[i]->mInUse && mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > 30.f)
|
||||
{
|
||||
//llinfos << "Flushing unused buffer!" << llendl;
|
||||
LL_DEBUGS("AudioEngine") << "Flushing unused buffer!" << llendl;
|
||||
mBuffers[i]->mAudioDatap->mBufferp = NULL;
|
||||
delete mBuffers[i];
|
||||
mBuffers[i] = NULL;
|
||||
@@ -572,6 +581,8 @@ void LLAudioEngine::enableWind(bool enable)
|
||||
|
||||
LLAudioBuffer * LLAudioEngine::getFreeBuffer()
|
||||
{
|
||||
//checkStates(); //Fails
|
||||
|
||||
S32 i;
|
||||
for (i = 0; i < MAX_BUFFERS; i++)
|
||||
{
|
||||
@@ -582,6 +593,7 @@ LLAudioBuffer * LLAudioEngine::getFreeBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
//checkStates(); // Fails
|
||||
|
||||
// Grab the oldest unused buffer
|
||||
F32 max_age = -1.f;
|
||||
@@ -601,10 +613,11 @@ LLAudioBuffer * LLAudioEngine::getFreeBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
//checkStates(); //Fails
|
||||
|
||||
if (buffer_id >= 0)
|
||||
{
|
||||
lldebugs << "Taking over unused buffer " << buffer_id << llendl;
|
||||
//llinfos << "Flushing unused buffer!" << llendl;
|
||||
LL_DEBUGS("AudioEngine") << "Taking over unused buffer! max_age=" << max_age << llendl;
|
||||
mBuffers[buffer_id]->mAudioDatap->mBufferp = NULL;
|
||||
for (U32 i = 0; i < MAX_CHANNELS; i++)
|
||||
{
|
||||
@@ -612,12 +625,15 @@ LLAudioBuffer * LLAudioEngine::getFreeBuffer()
|
||||
if(channelp && channelp->mCurrentBufferp == mBuffers[buffer_id])
|
||||
{
|
||||
channelp->cleanup();
|
||||
llassert(channelp->mCurrentBufferp == NULL);
|
||||
}
|
||||
}
|
||||
delete mBuffers[buffer_id];
|
||||
mBuffers[buffer_id] = createBuffer();
|
||||
return mBuffers[buffer_id];
|
||||
}
|
||||
|
||||
//checkStates(); //Fails
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -638,6 +654,7 @@ LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority)
|
||||
// Channel is allocated but not playing right now, use it.
|
||||
if (!mChannels[i]->isPlaying() && !mChannels[i]->isWaiting())
|
||||
{
|
||||
LL_DEBUGS("AudioEngine") << "Replacing unused channel" << llendl;
|
||||
mChannels[i]->cleanup();
|
||||
if (mChannels[i]->getSource())
|
||||
{
|
||||
@@ -670,9 +687,9 @@ LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LL_DEBUGS("AudioEngine") << "Flushing min channel" << llendl;
|
||||
// Flush the minimum priority channel, and return it.
|
||||
min_channelp->cleanup();
|
||||
min_channelp->getSource()->setChannel(NULL);
|
||||
return min_channelp;
|
||||
}
|
||||
|
||||
@@ -1006,10 +1023,13 @@ LLAudioData * LLAudioEngine::getAudioData(const LLUUID &audio_uuid)
|
||||
if( sourcep && sourcep->getCurrentData() && sourcep->getCurrentData()->getID() == audio_uuid )
|
||||
{
|
||||
LLAudioChannel* chan=sourcep->getChannel();
|
||||
delete sourcep;
|
||||
if(chan)
|
||||
{
|
||||
LL_DEBUGS("AudioEngine") << "removeAudioData" << llendl;
|
||||
chan->cleanup();
|
||||
mAllSources.erase(iter2++);
|
||||
}
|
||||
delete sourcep;
|
||||
mAllSources.erase(iter2++);
|
||||
}
|
||||
else
|
||||
++iter2;
|
||||
@@ -1043,7 +1063,7 @@ void LLAudioEngine::cleanupAudioSource(LLAudioSource *asp)
|
||||
iter = mAllSources.find(asp->getID());
|
||||
if (iter == mAllSources.end())
|
||||
{
|
||||
llwarns << "Cleaning up unknown audio source!" << llendl;
|
||||
LL_WARNS("AudioEngine") << "Cleaning up unknown audio source!" << llendl;
|
||||
return;
|
||||
}
|
||||
delete asp;
|
||||
@@ -1264,7 +1284,7 @@ void LLAudioEngine::startNextTransfer()
|
||||
|
||||
if (asset_id.notNull())
|
||||
{
|
||||
llinfos << "Getting asset data for: " << asset_id << llendl;
|
||||
LL_DEBUGS("AudioEngine") << "Getting asset data for: " << asset_id << llendl;
|
||||
gAudiop->mCurrentTransfer = asset_id;
|
||||
gAudiop->mCurrentTransferTimer.reset();
|
||||
gAssetStorage->getAssetData(asset_id, LLAssetType::AT_SOUND,
|
||||
@@ -1282,7 +1302,7 @@ void LLAudioEngine::assetCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::E
|
||||
{
|
||||
if (result_code)
|
||||
{
|
||||
llinfos << "Boom, error in audio file transfer: " << LLAssetStorage::getErrorString( result_code ) << " (" << result_code << ")" << llendl;
|
||||
LL_INFOS("AudioEngine") << "Boom, error in audio file transfer: " << LLAssetStorage::getErrorString( result_code ) << " (" << result_code << ")" << llendl;
|
||||
// Need to mark data as bad to avoid constant rerequests.
|
||||
LLAudioData *adp = gAudiop->getAudioData(uuid);
|
||||
if (adp)
|
||||
@@ -1299,7 +1319,7 @@ void LLAudioEngine::assetCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::E
|
||||
if (!adp)
|
||||
{
|
||||
// Should never happen
|
||||
llwarns << "Got asset callback without audio data for " << uuid << llendl;
|
||||
LL_WARNS("AudioEngine") << "Got asset callback without audio data for " << uuid << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1360,8 +1380,7 @@ LLAudioSource::~LLAudioSource()
|
||||
if (mChannelp)
|
||||
{
|
||||
// Stop playback of this sound
|
||||
mChannelp->setSource(NULL);
|
||||
setChannel(NULL);
|
||||
mChannelp->cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1404,7 +1423,7 @@ void LLAudioSource::update()
|
||||
}
|
||||
else if (adp->hasCompletedDecode()) // Only mark corrupted after decode is done
|
||||
{
|
||||
llwarns << "Marking LLAudioSource corrupted for " << adp->getID() << llendl;
|
||||
LL_WARNS("AudioEngine") << "Marking LLAudioSource corrupted for " << adp->getID() << llendl;
|
||||
mCorrupted = true ;
|
||||
}
|
||||
}
|
||||
@@ -1463,6 +1482,8 @@ bool LLAudioSource::setupChannel()
|
||||
}
|
||||
|
||||
mChannelp->setSource(this);
|
||||
llassert(this == mChannelp->getSource());
|
||||
llassert(mChannelp->mCurrentBufferp == getCurrentBuffer());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1474,8 +1495,8 @@ bool LLAudioSource::play(const LLUUID &audio_uuid)
|
||||
{
|
||||
if (getChannel())
|
||||
{
|
||||
llassert(this == getChannel()->getSource());
|
||||
getChannel()->setSource(NULL);
|
||||
setChannel(NULL);
|
||||
if (!isMuted())
|
||||
{
|
||||
mCurrentDatap = NULL;
|
||||
@@ -1727,13 +1748,20 @@ LLAudioChannel::LLAudioChannel() :
|
||||
|
||||
LLAudioChannel::~LLAudioChannel()
|
||||
{
|
||||
llassert(mCurrentBufferp == NULL);
|
||||
|
||||
// Need to disconnect any sources which are using this channel.
|
||||
//llinfos << "Cleaning up audio channel" << llendl;
|
||||
if (mCurrentSourcep)
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void LLAudioChannel::cleanup()
|
||||
{
|
||||
if(mCurrentSourcep)
|
||||
mCurrentSourcep->setChannel(NULL);
|
||||
}
|
||||
mCurrentBufferp = NULL;
|
||||
mCurrentSourcep = NULL;
|
||||
mWaiting = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1744,22 +1772,21 @@ void LLAudioChannel::setSource(LLAudioSource *sourcep)
|
||||
if (!sourcep)
|
||||
{
|
||||
// Clearing the source for this channel, don't need to do anything.
|
||||
//llinfos << "Clearing source for channel" << llendl;
|
||||
LL_DEBUGS("AudioEngine") << "Clearing source for channel" << llendl;
|
||||
cleanup();
|
||||
mCurrentSourcep = NULL;
|
||||
mWaiting = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourcep == mCurrentSourcep)
|
||||
{
|
||||
// Don't reallocate the channel, this will make FMOD goofy.
|
||||
//llinfos << "Calling setSource with same source!" << llendl;
|
||||
LL_DEBUGS("AudioEngine") << "Calling setSource with same source!" << llendl;
|
||||
}
|
||||
|
||||
cleanup();
|
||||
mCurrentSourcep = sourcep;
|
||||
|
||||
|
||||
mCurrentSourcep->setChannel(this);
|
||||
|
||||
updateBuffer();
|
||||
update3DPosition();
|
||||
}
|
||||
@@ -1796,7 +1823,12 @@ bool LLAudioChannel::updateBuffer()
|
||||
// The source changed what buffer it's playing. We need to clean up
|
||||
// the existing channel
|
||||
//
|
||||
LLAudioSource* source = mCurrentSourcep;
|
||||
cleanup();
|
||||
mCurrentSourcep = source;
|
||||
mCurrentSourcep->setChannel(this);
|
||||
|
||||
llassert(mCurrentBufferp == NULL);
|
||||
|
||||
mCurrentBufferp = bufferp;
|
||||
if (bufferp)
|
||||
@@ -1856,7 +1888,7 @@ bool LLAudioData::load()
|
||||
if (mBufferp)
|
||||
{
|
||||
// We already have this sound in a buffer, don't do anything.
|
||||
llinfos << "Already have a buffer for this sound, don't bother loading!" << llendl;
|
||||
LL_INFOS("AudioEngine") << "Already have a buffer for this sound, don't bother loading!" << llendl;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1864,7 +1896,7 @@ bool LLAudioData::load()
|
||||
if (!mBufferp)
|
||||
{
|
||||
// No free buffers, abort.
|
||||
lldebugs << "Not able to allocate a new audio buffer, aborting." << llendl;
|
||||
LL_DEBUGS("AudioEngine") << "Not able to allocate a new audio buffer, aborting." << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -189,6 +189,8 @@ public:
|
||||
static void assetCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 result_code, LLExtStat ext_status);
|
||||
|
||||
friend class LLPipeline; // For debugging
|
||||
|
||||
void checkStates();
|
||||
public:
|
||||
F32 mMaxWindGain; // Hack. Public to set before fade in?
|
||||
|
||||
@@ -447,7 +449,7 @@ public:
|
||||
protected:
|
||||
virtual void play() = 0;
|
||||
virtual void playSynced(LLAudioChannel *channelp) = 0;
|
||||
virtual void cleanup() = 0;
|
||||
virtual void cleanup();
|
||||
void setWaiting(bool waiting) { mWaiting = waiting; }
|
||||
|
||||
public:
|
||||
|
||||
@@ -576,6 +576,7 @@ void LLAudioChannelFMOD::updateLoop()
|
||||
|
||||
void LLAudioChannelFMOD::cleanup()
|
||||
{
|
||||
LLAudioChannel::cleanup();
|
||||
if (!mChannelID)
|
||||
{
|
||||
//llinfos << "Aborting cleanup with no channelID." << llendl;
|
||||
@@ -588,7 +589,6 @@ void LLAudioChannelFMOD::cleanup()
|
||||
LL_DEBUGS("FMOD") << "LLAudioChannelFMOD::cleanup error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
|
||||
}
|
||||
|
||||
mCurrentBufferp = NULL;
|
||||
mChannelID = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,12 +70,172 @@ bool attemptDelayLoad()
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool sVerboseDebugging = false;
|
||||
|
||||
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
|
||||
FMOD::ChannelGroup *LLAudioEngine_FMODEX::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0};
|
||||
|
||||
LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler)
|
||||
//This class is designed to keep track of all sound<->channel assocations.
|
||||
//Used to verify validity of sound and channel pointers, as well as catch cases were sounds
|
||||
//are released with active channels still attached.
|
||||
class CFMODSoundChecks
|
||||
{
|
||||
typedef std::map<FMOD::Sound*,std::set<FMOD::Channel*> > active_sounds_t;
|
||||
typedef std::set<FMOD::Sound*> dead_sounds_t;
|
||||
typedef std::map<FMOD::Channel*,FMOD::Sound*> active_channels_t;
|
||||
typedef std::map<FMOD::Channel*,FMOD::Sound*> dead_channels_t;
|
||||
|
||||
active_sounds_t mActiveSounds;
|
||||
dead_sounds_t mDeadSounds;
|
||||
active_channels_t mActiveChannels;
|
||||
dead_channels_t mDeadChannels;
|
||||
public:
|
||||
enum STATUS
|
||||
{
|
||||
ACTIVE,
|
||||
DEAD,
|
||||
UNKNOWN
|
||||
};
|
||||
STATUS getPtrStatus(LLAudioChannelFMODEX* channel)
|
||||
{
|
||||
if(!channel)
|
||||
return UNKNOWN;
|
||||
return getPtrStatus(channel->mChannelp);
|
||||
}
|
||||
STATUS getPtrStatus(LLAudioBufferFMODEX* sound)
|
||||
{
|
||||
if(!sound)
|
||||
return UNKNOWN;
|
||||
return getPtrStatus(sound->mSoundp);
|
||||
}
|
||||
STATUS getPtrStatus(FMOD::Channel* channel)
|
||||
{
|
||||
if(!channel)
|
||||
return UNKNOWN;
|
||||
else if(mActiveChannels.find(channel) != mActiveChannels.end())
|
||||
return ACTIVE;
|
||||
else if(mDeadChannels.find(channel) != mDeadChannels.end())
|
||||
return DEAD;
|
||||
return UNKNOWN;
|
||||
}
|
||||
STATUS getPtrStatus(FMOD::Sound* sound)
|
||||
{
|
||||
if(!sound)
|
||||
return UNKNOWN;
|
||||
if(mActiveSounds.find(sound) != mActiveSounds.end())
|
||||
return ACTIVE;
|
||||
else if(mDeadSounds.find(sound) != mDeadSounds.end())
|
||||
return DEAD;
|
||||
return UNKNOWN;
|
||||
}
|
||||
void addNewSound(FMOD::Sound* sound)
|
||||
{
|
||||
llassert(getPtrStatus(sound) != ACTIVE);
|
||||
|
||||
mDeadSounds.erase(sound);
|
||||
mActiveSounds.insert(std::make_pair(sound,std::set<FMOD::Channel*>()));
|
||||
}
|
||||
void removeSound(FMOD::Sound* sound)
|
||||
{
|
||||
#ifdef SHOW_ASSERT
|
||||
STATUS status = getPtrStatus(sound);
|
||||
llassert(status != DEAD);
|
||||
llassert(status != UNKNOWN);
|
||||
#endif
|
||||
|
||||
active_sounds_t::const_iterator it = mActiveSounds.find(sound);
|
||||
llassert(it != mActiveSounds.end());
|
||||
if(it != mActiveSounds.end())
|
||||
{
|
||||
if(!it->second.empty())
|
||||
{
|
||||
#ifdef LL_RELEASE_FOR_DOWNLOAD
|
||||
LL_WARNS("AudioImpl") << "Removing sound " << sound << " with attached channels: \n";
|
||||
#else
|
||||
LL_ERRS("AudioImpl") << "Removing sound " << sound << " with attached channels: \n";
|
||||
#endif
|
||||
for(std::set<FMOD::Channel*>::iterator it2 = it->second.begin(); it2 != it->second.end();++it2)
|
||||
{
|
||||
switch(getPtrStatus(*it2))
|
||||
{
|
||||
case ACTIVE:
|
||||
llcont << " Channel " << *it2 << " ACTIVE\n";
|
||||
break;
|
||||
case DEAD:
|
||||
llcont << " Channel " << *it2 << " DEAD\n";
|
||||
break;
|
||||
default:
|
||||
llcont << " Channel " << *it2 << " UNKNOWN\n";
|
||||
}
|
||||
}
|
||||
llcont << llendl;
|
||||
}
|
||||
mDeadSounds.insert(sound);
|
||||
mActiveSounds.erase(sound);
|
||||
}
|
||||
}
|
||||
void addNewChannelToSound(FMOD::Sound* sound,FMOD::Channel* channel)
|
||||
{
|
||||
STATUS status = getPtrStatus(sound);
|
||||
llassert(status != DEAD);
|
||||
llassert(status != UNKNOWN);
|
||||
status = getPtrStatus(channel);
|
||||
llassert(status != ACTIVE);
|
||||
|
||||
mActiveSounds[sound].insert(channel);
|
||||
mActiveChannels.insert(std::make_pair(channel,sound));
|
||||
}
|
||||
void removeChannel(FMOD::Channel* channel)
|
||||
{
|
||||
#ifdef SHOW_ASSERT
|
||||
STATUS status = getPtrStatus(channel);
|
||||
llassert(status != DEAD);
|
||||
llassert(status != UNKNOWN);
|
||||
#endif
|
||||
|
||||
active_channels_t::const_iterator it = mActiveChannels.find(channel);
|
||||
llassert(it != mActiveChannels.end());
|
||||
if(it != mActiveChannels.end())
|
||||
{
|
||||
#ifdef SHOW_ASSERT
|
||||
STATUS status = getPtrStatus(it->second);
|
||||
llassert(status != DEAD);
|
||||
llassert(status != UNKNOWN);
|
||||
#endif
|
||||
|
||||
active_sounds_t::iterator it2 = mActiveSounds.find(it->second);
|
||||
llassert(it2 != mActiveSounds.end());
|
||||
if(it2 != mActiveSounds.end())
|
||||
{
|
||||
it2->second.erase(channel);
|
||||
}
|
||||
mDeadChannels.insert(*it);
|
||||
mActiveChannels.erase(channel);
|
||||
}
|
||||
}
|
||||
} gSoundCheck;
|
||||
|
||||
bool isActive(LLAudioChannel* channel)
|
||||
{
|
||||
return gSoundCheck.getPtrStatus(dynamic_cast<LLAudioChannelFMODEX*>(channel)) == CFMODSoundChecks::ACTIVE;
|
||||
}
|
||||
bool isActive(LLAudioBuffer* sound)
|
||||
{
|
||||
return gSoundCheck.getPtrStatus(dynamic_cast<LLAudioBufferFMODEX*>(sound)) == CFMODSoundChecks::ACTIVE;
|
||||
}
|
||||
|
||||
#define CHECK_PTR(ptr) \
|
||||
if(sVerboseDebugging){\
|
||||
CFMODSoundChecks::STATUS chan = gSoundCheck.getPtrStatus(ptr); \
|
||||
if(chan == CFMODSoundChecks::DEAD) \
|
||||
LL_DEBUGS("AudioImpl") << __FUNCTION__ << ": Using dead " << typeid(ptr).name() << " " << ptr << llendl; \
|
||||
else if(chan == CFMODSoundChecks::UNKNOWN) \
|
||||
LL_DEBUGS("AudioImpl") << __FUNCTION__ << ": Using unknown " << typeid(ptr).name() << " " << ptr << llendl;} \
|
||||
|
||||
LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler, bool verbose_debugging)
|
||||
{
|
||||
sVerboseDebugging = verbose_debugging;
|
||||
mInited = false;
|
||||
mWindGen = NULL;
|
||||
mWindDSP = NULL;
|
||||
@@ -93,7 +253,7 @@ inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
|
||||
{
|
||||
if(result == FMOD_OK)
|
||||
return false;
|
||||
llwarns << string << " Error: " << FMOD_ErrorString(result) << llendl;
|
||||
LL_WARNS("AudioImpl") << string << " Error: " << FMOD_ErrorString(result) << llendl;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -101,11 +261,11 @@ void* F_STDCALL decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const cha
|
||||
{
|
||||
if(type & FMOD_MEMORY_STREAM_DECODE)
|
||||
{
|
||||
llinfos << "Decode buffer size: " << size << llendl;
|
||||
LL_INFOS("AudioImpl") << "Decode buffer size: " << size << llendl;
|
||||
}
|
||||
else if(type & FMOD_MEMORY_STREAM_FILE)
|
||||
{
|
||||
llinfos << "Strean buffer size: " << size << llendl;
|
||||
LL_INFOS("AudioImpl") << "Stream buffer size: " << size << llendl;
|
||||
}
|
||||
return new char[size];
|
||||
}
|
||||
@@ -344,7 +504,7 @@ void LLAudioEngine_FMODEX::allocateListener(void)
|
||||
mListenerp = (LLListener *) new LLListener_FMODEX(mSystem);
|
||||
if (!mListenerp)
|
||||
{
|
||||
llwarns << "Listener creation failed" << llendl;
|
||||
LL_WARNS("AudioImpl") << "Listener creation failed" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,13 +513,16 @@ void LLAudioEngine_FMODEX::shutdown()
|
||||
{
|
||||
stopInternetStream();
|
||||
|
||||
llinfos << "About to LLAudioEngine::shutdown()" << llendl;
|
||||
LL_INFOS("AudioImpl") << "About to LLAudioEngine::shutdown()" << llendl;
|
||||
LLAudioEngine::shutdown();
|
||||
|
||||
llinfos << "LLAudioEngine_FMODEX::shutdown() closing FMOD Ex" << llendl;
|
||||
LL_INFOS("AudioImpl") << "LLAudioEngine_FMODEX::shutdown() closing FMOD Ex" << llendl;
|
||||
if ( mSystem ) // speculative fix for MAINT-2657
|
||||
{
|
||||
mSystem->close();
|
||||
mSystem->release();
|
||||
llinfos << "LLAudioEngine_FMODEX::shutdown() done closing FMOD Ex" << llendl;
|
||||
}
|
||||
LL_INFOS("AudioImpl") << "LLAudioEngine_FMODEX::shutdown() done closing FMOD Ex" << llendl;
|
||||
|
||||
delete mListenerp;
|
||||
mListenerp = NULL;
|
||||
@@ -490,6 +653,34 @@ LLAudioChannelFMODEX::LLAudioChannelFMODEX(FMOD::System *system) : LLAudioChanne
|
||||
|
||||
LLAudioChannelFMODEX::~LLAudioChannelFMODEX()
|
||||
{
|
||||
if(sVerboseDebugging)
|
||||
LL_DEBUGS("AudioImpl") << "Destructing Audio Channel. mChannelp = " << mChannelp << llendl;
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
static FMOD_RESULT F_CALLBACK channel_callback(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *commanddata1, void *commanddata2)
|
||||
{
|
||||
if(type == FMOD_CHANNEL_CALLBACKTYPE_END)
|
||||
{
|
||||
FMOD::Channel* chan = reinterpret_cast<FMOD::Channel*>(channel);
|
||||
LLAudioChannelFMODEX* audio_channel = NULL;
|
||||
chan->getUserData((void**)&audio_channel);
|
||||
if(audio_channel)
|
||||
{
|
||||
audio_channel->onRelease();
|
||||
}
|
||||
}
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
void LLAudioChannelFMODEX::onRelease()
|
||||
{
|
||||
llassert(mChannelp);
|
||||
if(sVerboseDebugging)
|
||||
LL_DEBUGS("AudioImpl") << "Fmod signaled channel release for channel " << mChannelp << llendl;
|
||||
gSoundCheck.removeChannel(mChannelp);
|
||||
mChannelp = NULL; //Null out channel here so cleanup doesn't try to redundantly stop it.
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@@ -502,13 +693,16 @@ bool LLAudioChannelFMODEX::updateBuffer()
|
||||
|
||||
LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentSourcep->getCurrentBuffer();
|
||||
|
||||
llassert(mCurrentBufferp != NULL);
|
||||
llassert(mCurrentBufferp == bufferp);
|
||||
|
||||
// Grab the FMOD sample associated with the buffer
|
||||
FMOD::Sound *soundp = bufferp->getSound();
|
||||
if (!soundp)
|
||||
{
|
||||
// This is bad, there should ALWAYS be a sound associated with a legit
|
||||
// buffer.
|
||||
llerrs << "No FMOD sound!" << llendl;
|
||||
LL_ERRS("AudioImpl") << "No FMOD sound!" << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -517,11 +711,21 @@ bool LLAudioChannelFMODEX::updateBuffer()
|
||||
// setup.
|
||||
if(!mChannelp)
|
||||
{
|
||||
llassert(!isActive(this));
|
||||
|
||||
FMOD_RESULT result = getSystem()->playSound(FMOD_CHANNEL_FREE, soundp, true, &mChannelp);
|
||||
Check_FMOD_Error(result, "FMOD::System::playSound");
|
||||
}
|
||||
if(result == FMOD_OK)
|
||||
{
|
||||
if(sVerboseDebugging)
|
||||
LL_DEBUGS("AudioImpl") << "Created channel " << mChannelp << " for sound " << soundp << llendl;
|
||||
|
||||
//llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl;
|
||||
gSoundCheck.addNewChannelToSound(soundp,mChannelp);
|
||||
mChannelp->setCallback(&channel_callback);
|
||||
mChannelp->setUserData(this);
|
||||
llassert(isActive(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a source for the channel, we need to update its gain.
|
||||
@@ -530,18 +734,12 @@ bool LLAudioChannelFMODEX::updateBuffer()
|
||||
// SJB: warnings can spam and hurt framerate, disabling
|
||||
FMOD_RESULT result;
|
||||
|
||||
CHECK_PTR(mChannelp);
|
||||
|
||||
result = mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain());
|
||||
Check_FMOD_Error(result, "FMOD::Channel::setVolume");
|
||||
result = mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
|
||||
Check_FMOD_Error(result, "FMOD::Channel::setMode");
|
||||
/*if(Check_FMOD_Error(result, "FMOD::Channel::setMode"))
|
||||
{
|
||||
S32 index;
|
||||
mChannelp->getIndex(&index);
|
||||
llwarns << "Channel " << index << "Source ID: " << mCurrentSourcep->getID()
|
||||
<< " at " << mCurrentSourcep->getPositionGlobal() << llendl;
|
||||
}*/
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -564,6 +762,8 @@ void LLAudioChannelFMODEX::update3DPosition()
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK_PTR(mChannelp);
|
||||
|
||||
if (mCurrentSourcep->isAmbient())
|
||||
{
|
||||
// Ambient sound, don't need to do any positional updates.
|
||||
@@ -590,6 +790,8 @@ void LLAudioChannelFMODEX::updateLoop()
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK_PTR(mChannelp);
|
||||
|
||||
//
|
||||
// Hack: We keep track of whether we looped or not by seeing when the
|
||||
// sample position looks like it's going backwards. Not reliable; may
|
||||
@@ -608,17 +810,30 @@ void LLAudioChannelFMODEX::updateLoop()
|
||||
|
||||
void LLAudioChannelFMODEX::cleanup()
|
||||
{
|
||||
LLAudioChannel::cleanup();
|
||||
|
||||
if (!mChannelp)
|
||||
{
|
||||
llassert(!isActive(this));
|
||||
llassert(mCurrentBufferp == NULL);
|
||||
//llinfos << "Aborting cleanup with no channel handle." << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
//llinfos << "Cleaning up channel: " << mChannelID << llendl;
|
||||
Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop");
|
||||
CHECK_PTR(mChannelp);
|
||||
|
||||
if(sVerboseDebugging)
|
||||
LL_DEBUGS("AudioImpl") << "Stopping channel " << mChannelp << llendl;
|
||||
|
||||
mChannelp->setCallback(NULL);
|
||||
if(!Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop"))
|
||||
{
|
||||
gSoundCheck.removeChannel(mChannelp);
|
||||
}
|
||||
|
||||
mCurrentBufferp = NULL;
|
||||
mChannelp = NULL;
|
||||
llassert(!isActive(this));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -626,12 +841,19 @@ void LLAudioChannelFMODEX::play()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
llwarns << "Playing without a channel handle, aborting" << llendl;
|
||||
LL_WARNS("AudioImpl") << "Playing without a channel handle, aborting" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
llassert(isActive(this));
|
||||
|
||||
CHECK_PTR(mChannelp);
|
||||
|
||||
Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::setPaused");
|
||||
|
||||
if(sVerboseDebugging)
|
||||
LL_DEBUGS("AudioImpl") << "Playing channel " << mChannelp << llendl;
|
||||
|
||||
getSource()->setPlayedOnce(true);
|
||||
|
||||
if(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()])
|
||||
@@ -648,6 +870,8 @@ void LLAudioChannelFMODEX::playSynced(LLAudioChannel *channelp)
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK_PTR(mChannelp);
|
||||
|
||||
U32 cur_pos;
|
||||
if(Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position"))
|
||||
return;
|
||||
@@ -669,6 +893,8 @@ bool LLAudioChannelFMODEX::isPlaying()
|
||||
return false;
|
||||
}
|
||||
|
||||
CHECK_PTR(mChannelp);
|
||||
|
||||
bool paused, playing;
|
||||
Check_FMOD_Error(mChannelp->getPaused(&paused),"FMOD::Channel::getPaused");
|
||||
Check_FMOD_Error(mChannelp->isPlaying(&playing),"FMOD::Channel::isPlaying");
|
||||
@@ -690,7 +916,12 @@ LLAudioBufferFMODEX::~LLAudioBufferFMODEX()
|
||||
{
|
||||
if(mSoundp)
|
||||
{
|
||||
if(sVerboseDebugging)
|
||||
LL_DEBUGS("AudioImpl") << "Release sound " << mSoundp << llendl;
|
||||
|
||||
CHECK_PTR(mSoundp);
|
||||
Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::Release");
|
||||
gSoundCheck.removeSound(mSoundp);
|
||||
mSoundp = NULL;
|
||||
}
|
||||
}
|
||||
@@ -714,8 +945,10 @@ bool LLAudioBufferFMODEX::loadWAV(const std::string& filename)
|
||||
|
||||
if (mSoundp)
|
||||
{
|
||||
CHECK_PTR(mSoundp);
|
||||
// If there's already something loaded in this buffer, clean it up.
|
||||
Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::release");
|
||||
gSoundCheck.removeSound(mSoundp);
|
||||
mSoundp = NULL;
|
||||
}
|
||||
|
||||
@@ -734,7 +967,7 @@ bool LLAudioBufferFMODEX::loadWAV(const std::string& filename)
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
// We failed to load the file for some reason.
|
||||
llwarns << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << llendl;
|
||||
LL_WARNS("AudioImpl") << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << llendl;
|
||||
|
||||
//
|
||||
// If we EVER want to load wav files provided by end users, we need
|
||||
@@ -745,6 +978,8 @@ bool LLAudioBufferFMODEX::loadWAV(const std::string& filename)
|
||||
return false;
|
||||
}
|
||||
|
||||
gSoundCheck.addNewSound(mSoundp);
|
||||
|
||||
// Everything went well, return true
|
||||
return true;
|
||||
}
|
||||
@@ -757,6 +992,7 @@ U32 LLAudioBufferFMODEX::getLength()
|
||||
return 0;
|
||||
}
|
||||
|
||||
CHECK_PTR(mSoundp);
|
||||
U32 length;
|
||||
Check_FMOD_Error(mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES),"FMOD::Sound::getLength");
|
||||
return length;
|
||||
@@ -765,6 +1001,8 @@ U32 LLAudioBufferFMODEX::getLength()
|
||||
|
||||
void LLAudioChannelFMODEX::set3DMode(bool use3d)
|
||||
{
|
||||
CHECK_PTR(mChannelp);
|
||||
|
||||
FMOD_MODE current_mode;
|
||||
if(Check_FMOD_Error(mChannelp->getMode(¤t_mode),"FMOD::Channel::getMode"))
|
||||
return;
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace FMOD
|
||||
class LLAudioEngine_FMODEX : public LLAudioEngine
|
||||
{
|
||||
public:
|
||||
LLAudioEngine_FMODEX(bool enable_profiler);
|
||||
LLAudioEngine_FMODEX(bool enable_profiler, bool verbose_debugging);
|
||||
virtual ~LLAudioEngine_FMODEX();
|
||||
|
||||
// initialization/startup/shutdown
|
||||
@@ -95,7 +95,7 @@ class LLAudioChannelFMODEX : public LLAudioChannel
|
||||
public:
|
||||
LLAudioChannelFMODEX(FMOD::System *audioengine);
|
||||
virtual ~LLAudioChannelFMODEX();
|
||||
|
||||
void onRelease();
|
||||
protected:
|
||||
/*virtual*/ void play();
|
||||
/*virtual*/ void playSynced(LLAudioChannel *channelp);
|
||||
@@ -112,6 +112,8 @@ protected:
|
||||
FMOD::System *mSystemp;
|
||||
FMOD::Channel *mChannelp;
|
||||
S32 mLastSamplePos;
|
||||
|
||||
friend class CFMODSoundChecks;
|
||||
};
|
||||
|
||||
|
||||
@@ -129,6 +131,8 @@ protected:
|
||||
FMOD::System *mSystemp;
|
||||
FMOD::Sound *getSound() const{ return mSoundp; }
|
||||
FMOD::Sound *mSoundp;
|
||||
|
||||
friend class CFMODSoundChecks;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -186,10 +186,9 @@ LLAudioChannelOpenAL::~LLAudioChannelOpenAL()
|
||||
|
||||
void LLAudioChannelOpenAL::cleanup()
|
||||
{
|
||||
LLAudioChannel::cleanup();
|
||||
alSourceStop(mALSource);
|
||||
alSourcei(mALSource, AL_BUFFER, AL_NONE);
|
||||
|
||||
mCurrentBufferp = NULL;
|
||||
}
|
||||
|
||||
void LLAudioChannelOpenAL::play()
|
||||
|
||||
@@ -76,6 +76,7 @@ set(llcommon_SOURCE_FILES
|
||||
llrun.cpp
|
||||
llscopedvolatileaprpool.h
|
||||
llsd.cpp
|
||||
llsdparam.cpp
|
||||
llsdserialize.cpp
|
||||
llsdserialize_xml.cpp
|
||||
llsdutil.cpp
|
||||
@@ -204,10 +205,11 @@ set(llcommon_HEADER_FILES
|
||||
llqueuedthread.h
|
||||
llrand.h
|
||||
llrefcount.h
|
||||
llrefcount.h
|
||||
llregistry.h
|
||||
llrun.h
|
||||
llsafehandle.h
|
||||
llsd.h
|
||||
llsdparam.h
|
||||
llsdserialize.h
|
||||
llsdserialize_xml.h
|
||||
llsdutil.h
|
||||
|
||||
358
indra/llcommon/llregistry.h
Normal file
358
indra/llcommon/llregistry.h
Normal file
@@ -0,0 +1,358 @@
|
||||
/**
|
||||
* @file llregistry.h
|
||||
* @brief template classes for registering name, value pairs in nested scopes, statically, etc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLREGISTRY_H
|
||||
#define LL_LLREGISTRY_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include <boost/type_traits.hpp>
|
||||
#include "llsingleton.h"
|
||||
#include "llstl.h"
|
||||
|
||||
template <typename T>
|
||||
struct LLRegistryDefaultComparator
|
||||
{
|
||||
bool operator()(const T& lhs, const T& rhs) const
|
||||
{
|
||||
using std::less;
|
||||
return less<T>()(lhs, rhs);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename KEY, typename VALUE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> >
|
||||
class LLRegistry
|
||||
{
|
||||
public:
|
||||
typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t;
|
||||
typedef typename boost::add_reference<typename boost::add_const<KEY>::type>::type ref_const_key_t;
|
||||
typedef typename boost::add_reference<typename boost::add_const<VALUE>::type>::type ref_const_value_t;
|
||||
typedef typename boost::add_reference<VALUE>::type ref_value_t;
|
||||
typedef typename boost::add_pointer<typename boost::add_const<VALUE>::type>::type ptr_const_value_t;
|
||||
typedef typename boost::add_pointer<VALUE>::type ptr_value_t;
|
||||
|
||||
class Registrar
|
||||
{
|
||||
friend class LLRegistry<KEY, VALUE, COMPARATOR>;
|
||||
public:
|
||||
typedef std::map<KEY, VALUE, COMPARATOR> registry_map_t;
|
||||
|
||||
bool add(ref_const_key_t key, ref_const_value_t value)
|
||||
{
|
||||
if (mMap.insert(std::make_pair(key, value)).second == false)
|
||||
{
|
||||
llwarns << "Tried to register " << key << " but it was already registered!" << llendl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void remove(ref_const_key_t key)
|
||||
{
|
||||
mMap.erase(key);
|
||||
}
|
||||
|
||||
void replace(ref_const_key_t key, ref_const_value_t value)
|
||||
{
|
||||
mMap[key] = value;
|
||||
}
|
||||
|
||||
typename registry_map_t::const_iterator beginItems() const
|
||||
{
|
||||
return mMap.begin();
|
||||
}
|
||||
|
||||
typename registry_map_t::const_iterator endItems() const
|
||||
{
|
||||
return mMap.end();
|
||||
}
|
||||
|
||||
protected:
|
||||
ptr_value_t getValue(ref_const_key_t key)
|
||||
{
|
||||
typename registry_map_t::iterator found_it = mMap.find(key);
|
||||
if (found_it != mMap.end())
|
||||
{
|
||||
return &(found_it->second);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr_const_value_t getValue(ref_const_key_t key) const
|
||||
{
|
||||
typename registry_map_t::const_iterator found_it = mMap.find(key);
|
||||
if (found_it != mMap.end())
|
||||
{
|
||||
return &(found_it->second);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// if the registry is used to store pointers, and null values are valid entries
|
||||
// then use this function to check the existence of an entry
|
||||
bool exists(ref_const_key_t key) const
|
||||
{
|
||||
return mMap.find(key) != mMap.end();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return mMap.empty();
|
||||
}
|
||||
|
||||
protected:
|
||||
// use currentRegistrar() or defaultRegistrar()
|
||||
Registrar() {}
|
||||
~Registrar() {}
|
||||
|
||||
private:
|
||||
registry_map_t mMap;
|
||||
};
|
||||
|
||||
typedef typename std::list<Registrar*> scope_list_t;
|
||||
typedef typename std::list<Registrar*>::iterator scope_list_iterator_t;
|
||||
typedef typename std::list<Registrar*>::const_iterator scope_list_const_iterator_t;
|
||||
|
||||
LLRegistry()
|
||||
{}
|
||||
|
||||
~LLRegistry() {}
|
||||
|
||||
ptr_value_t getValue(ref_const_key_t key)
|
||||
{
|
||||
for(scope_list_iterator_t it = mActiveScopes.begin();
|
||||
it != mActiveScopes.end();
|
||||
++it)
|
||||
{
|
||||
ptr_value_t valuep = (*it)->getValue(key);
|
||||
if (valuep != NULL) return valuep;
|
||||
}
|
||||
return mDefaultRegistrar.getValue(key);
|
||||
}
|
||||
|
||||
ptr_const_value_t getValue(ref_const_key_t key) const
|
||||
{
|
||||
for(scope_list_const_iterator_t it = mActiveScopes.begin();
|
||||
it != mActiveScopes.end();
|
||||
++it)
|
||||
{
|
||||
ptr_value_t valuep = (*it)->getValue(key);
|
||||
if (valuep != NULL) return valuep;
|
||||
}
|
||||
return mDefaultRegistrar.getValue(key);
|
||||
}
|
||||
|
||||
bool exists(ref_const_key_t key) const
|
||||
{
|
||||
for(scope_list_const_iterator_t it = mActiveScopes.begin();
|
||||
it != mActiveScopes.end();
|
||||
++it)
|
||||
{
|
||||
if ((*it)->exists(key)) return true;
|
||||
}
|
||||
|
||||
return mDefaultRegistrar.exists(key);
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
for(scope_list_const_iterator_t it = mActiveScopes.begin();
|
||||
it != mActiveScopes.end();
|
||||
++it)
|
||||
{
|
||||
if (!(*it)->empty()) return false;
|
||||
}
|
||||
|
||||
return mDefaultRegistrar.empty();
|
||||
}
|
||||
|
||||
|
||||
Registrar& defaultRegistrar()
|
||||
{
|
||||
return mDefaultRegistrar;
|
||||
}
|
||||
|
||||
const Registrar& defaultRegistrar() const
|
||||
{
|
||||
return mDefaultRegistrar;
|
||||
}
|
||||
|
||||
|
||||
Registrar& currentRegistrar()
|
||||
{
|
||||
if (!mActiveScopes.empty())
|
||||
{
|
||||
return *mActiveScopes.front();
|
||||
}
|
||||
|
||||
return mDefaultRegistrar;
|
||||
}
|
||||
|
||||
const Registrar& currentRegistrar() const
|
||||
{
|
||||
if (!mActiveScopes.empty())
|
||||
{
|
||||
return *mActiveScopes.front();
|
||||
}
|
||||
|
||||
return mDefaultRegistrar;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
void addScope(Registrar* scope)
|
||||
{
|
||||
// newer scopes go up front
|
||||
mActiveScopes.insert(mActiveScopes.begin(), scope);
|
||||
}
|
||||
|
||||
void removeScope(Registrar* scope)
|
||||
{
|
||||
// O(N) but should be near the beggining and N should be small and this is safer than storing iterators
|
||||
scope_list_iterator_t iter = std::find(mActiveScopes.begin(), mActiveScopes.end(), scope);
|
||||
if (iter != mActiveScopes.end())
|
||||
{
|
||||
mActiveScopes.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
scope_list_t mActiveScopes;
|
||||
Registrar mDefaultRegistrar;
|
||||
};
|
||||
|
||||
template <typename KEY, typename VALUE, typename DERIVED_TYPE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> >
|
||||
class LLRegistrySingleton
|
||||
: public LLRegistry<KEY, VALUE, COMPARATOR>,
|
||||
public LLSingleton<DERIVED_TYPE>
|
||||
{
|
||||
friend class LLSingleton<DERIVED_TYPE>;
|
||||
public:
|
||||
typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t;
|
||||
typedef const KEY& ref_const_key_t;
|
||||
typedef const VALUE& ref_const_value_t;
|
||||
typedef VALUE* ptr_value_t;
|
||||
typedef const VALUE* ptr_const_value_t;
|
||||
typedef LLSingleton<DERIVED_TYPE> singleton_t;
|
||||
|
||||
class ScopedRegistrar : public registry_t::Registrar
|
||||
{
|
||||
public:
|
||||
ScopedRegistrar(bool push_scope = true)
|
||||
{
|
||||
if (push_scope)
|
||||
{
|
||||
pushScope();
|
||||
}
|
||||
}
|
||||
|
||||
~ScopedRegistrar()
|
||||
{
|
||||
if (!singleton_t::destroyed())
|
||||
{
|
||||
popScope();
|
||||
}
|
||||
}
|
||||
|
||||
void pushScope()
|
||||
{
|
||||
singleton_t::instance().addScope(this);
|
||||
}
|
||||
|
||||
void popScope()
|
||||
{
|
||||
singleton_t::instance().removeScope(this);
|
||||
}
|
||||
|
||||
ptr_value_t getValueFromScope(ref_const_key_t key)
|
||||
{
|
||||
return getValue(key);
|
||||
}
|
||||
|
||||
ptr_const_value_t getValueFromScope(ref_const_key_t key) const
|
||||
{
|
||||
return getValue(key);
|
||||
}
|
||||
|
||||
private:
|
||||
typename std::list<typename registry_t::Registrar*>::iterator mListIt;
|
||||
};
|
||||
|
||||
class StaticRegistrar : public registry_t::Registrar
|
||||
{
|
||||
public:
|
||||
virtual ~StaticRegistrar() {}
|
||||
StaticRegistrar(ref_const_key_t key, ref_const_value_t value)
|
||||
{
|
||||
if(!singleton_t::instance().mStaticScope)
|
||||
mStaticScope = new ScopedRegistrar();
|
||||
singleton_t::instance().mStaticScope->add(key, value);
|
||||
}
|
||||
};
|
||||
|
||||
// convenience functions
|
||||
typedef typename LLRegistry<KEY, VALUE, COMPARATOR>::Registrar& ref_registrar_t;
|
||||
static ref_registrar_t currentRegistrar()
|
||||
{
|
||||
return singleton_t::instance().registry_t::currentRegistrar();
|
||||
}
|
||||
|
||||
static ref_registrar_t defaultRegistrar()
|
||||
{
|
||||
return singleton_t::instance().registry_t::defaultRegistrar();
|
||||
}
|
||||
|
||||
static ptr_value_t getValue(ref_const_key_t key)
|
||||
{
|
||||
return singleton_t::instance().registry_t::getValue(key);
|
||||
}
|
||||
|
||||
protected:
|
||||
// DERIVED_TYPE needs to derive from LLRegistrySingleton
|
||||
LLRegistrySingleton()
|
||||
: mStaticScope(NULL)
|
||||
{}
|
||||
|
||||
virtual void initSingleton()
|
||||
{
|
||||
//mStaticScope = new ScopedRegistrar();
|
||||
}
|
||||
|
||||
virtual ~LLRegistrySingleton()
|
||||
{
|
||||
delete mStaticScope;
|
||||
}
|
||||
|
||||
private:
|
||||
ScopedRegistrar* mStaticScope;
|
||||
};
|
||||
|
||||
// helper macro for doing static registration
|
||||
#define GLUED_TOKEN(x, y) x ## y
|
||||
#define GLUE_TOKENS(x, y) GLUED_TOKEN(x, y)
|
||||
#define LLREGISTER_STATIC(REGISTRY, KEY, VALUE) static REGISTRY::StaticRegistrar GLUE_TOKENS(reg, __LINE__)(KEY, VALUE);
|
||||
|
||||
#endif
|
||||
342
indra/llcommon/llsdparam.cpp
Normal file
342
indra/llcommon/llsdparam.cpp
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* @file llsdparam.cpp
|
||||
* @brief parameter block abstraction for creating complex objects and
|
||||
* parsing construction parameters from xml and LLSD
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
// Project includes
|
||||
#include "llsdparam.h"
|
||||
#include "llsdutil.h"
|
||||
|
||||
static LLInitParam::Parser::parser_read_func_map_t sReadFuncs;
|
||||
static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs;
|
||||
static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs;
|
||||
static const LLSD NO_VALUE_MARKER;
|
||||
|
||||
LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion");
|
||||
|
||||
//
|
||||
// LLParamSDParser
|
||||
//
|
||||
LLParamSDParser::LLParamSDParser()
|
||||
: Parser(sReadFuncs, sWriteFuncs, sInspectFuncs)
|
||||
{
|
||||
using boost::bind;
|
||||
|
||||
if (sReadFuncs.empty())
|
||||
{
|
||||
registerParserFuncs<LLInitParam::Flag>(readFlag, &LLParamSDParser::writeFlag);
|
||||
registerParserFuncs<S32>(readS32, &LLParamSDParser::writeTypedValue<S32>);
|
||||
registerParserFuncs<U32>(readU32, &LLParamSDParser::writeU32Param);
|
||||
registerParserFuncs<F32>(readF32, &LLParamSDParser::writeTypedValue<F32>);
|
||||
registerParserFuncs<F64>(readF64, &LLParamSDParser::writeTypedValue<F64>);
|
||||
registerParserFuncs<bool>(readBool, &LLParamSDParser::writeTypedValue<bool>);
|
||||
registerParserFuncs<std::string>(readString, &LLParamSDParser::writeTypedValue<std::string>);
|
||||
registerParserFuncs<LLUUID>(readUUID, &LLParamSDParser::writeTypedValue<LLUUID>);
|
||||
registerParserFuncs<LLDate>(readDate, &LLParamSDParser::writeTypedValue<LLDate>);
|
||||
registerParserFuncs<LLURI>(readURI, &LLParamSDParser::writeTypedValue<LLURI>);
|
||||
registerParserFuncs<LLSD>(readSD, &LLParamSDParser::writeTypedValue<LLSD>);
|
||||
}
|
||||
}
|
||||
|
||||
// special case handling of U32 due to ambiguous LLSD::assign overload
|
||||
bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack)
|
||||
{
|
||||
LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser);
|
||||
if (!sdparser.mWriteRootSD) return false;
|
||||
|
||||
parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end());
|
||||
LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range);
|
||||
sd_to_write.assign((S32)*((const U32*)val_ptr));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::writeFlag(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack)
|
||||
{
|
||||
LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser);
|
||||
if (!sdparser.mWriteRootSD) return false;
|
||||
|
||||
parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end());
|
||||
LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLParamSDParser::submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack)
|
||||
{
|
||||
mCurReadSD = &sd;
|
||||
block.submitValue(name_stack, *this);
|
||||
}
|
||||
|
||||
void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent)
|
||||
{
|
||||
mCurReadSD = NULL;
|
||||
mNameStack.clear();
|
||||
setParseSilently(silent);
|
||||
|
||||
LLParamSDParserUtilities::readSDValues(boost::bind(&LLParamSDParser::submit, this, boost::ref(block), _1, _2), sd, mNameStack);
|
||||
//readSDValues(sd, block);
|
||||
}
|
||||
|
||||
void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block)
|
||||
{
|
||||
mNameStack.clear();
|
||||
mWriteRootSD = &sd;
|
||||
|
||||
name_stack_t name_stack;
|
||||
block.serializeBlock(*this, name_stack);
|
||||
}
|
||||
|
||||
/*virtual*/ std::string LLParamSDParser::getCurrentElementName()
|
||||
{
|
||||
std::string full_name = "sd";
|
||||
for (name_stack_t::iterator it = mNameStack.begin();
|
||||
it != mNameStack.end();
|
||||
++it)
|
||||
{
|
||||
full_name += llformat("[%s]", it->first.c_str());
|
||||
}
|
||||
|
||||
return full_name;
|
||||
}
|
||||
|
||||
|
||||
bool LLParamSDParser::readFlag(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
return self.mCurReadSD == &NO_VALUE_MARKER;
|
||||
}
|
||||
|
||||
|
||||
bool LLParamSDParser::readS32(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((S32*)val_ptr) = self.mCurReadSD->asInteger();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readU32(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((U32*)val_ptr) = self.mCurReadSD->asInteger();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readF32(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((F32*)val_ptr) = self.mCurReadSD->asReal();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readF64(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((F64*)val_ptr) = self.mCurReadSD->asReal();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readBool(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((bool*)val_ptr) = self.mCurReadSD->asBoolean();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readString(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((std::string*)val_ptr) = self.mCurReadSD->asString();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readUUID(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((LLUUID*)val_ptr) = self.mCurReadSD->asUUID();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readDate(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((LLDate*)val_ptr) = self.mCurReadSD->asDate();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readURI(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((LLURI*)val_ptr) = self.mCurReadSD->asURI();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readSD(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((LLSD*)val_ptr) = *self.mCurReadSD;
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range)
|
||||
{
|
||||
LLSD* sd_to_write = &input;
|
||||
|
||||
for (LLInitParam::Parser::name_stack_t::iterator it = name_stack_range.first;
|
||||
it != name_stack_range.second;
|
||||
++it)
|
||||
{
|
||||
bool new_traversal = it->second;
|
||||
|
||||
LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first];
|
||||
|
||||
if (child_sd->isArray())
|
||||
{
|
||||
if (new_traversal)
|
||||
{
|
||||
// write to new element at end
|
||||
sd_to_write = &(*child_sd)[child_sd->size()];
|
||||
}
|
||||
else
|
||||
{
|
||||
// write to last of existing elements, or first element if empty
|
||||
sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (new_traversal
|
||||
&& child_sd->isDefined()
|
||||
&& !child_sd->isArray())
|
||||
{
|
||||
// copy child contents into first element of an array
|
||||
LLSD new_array = LLSD::emptyArray();
|
||||
new_array.append(*child_sd);
|
||||
// assign array to slot that previously held the single value
|
||||
*child_sd = new_array;
|
||||
// return next element in that array
|
||||
sd_to_write = &((*child_sd)[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sd_to_write = child_sd;
|
||||
}
|
||||
}
|
||||
it->second = false;
|
||||
}
|
||||
|
||||
return *sd_to_write;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack)
|
||||
{
|
||||
if (sd.isMap())
|
||||
{
|
||||
for (LLSD::map_const_iterator it = sd.beginMap();
|
||||
it != sd.endMap();
|
||||
++it)
|
||||
{
|
||||
stack.push_back(make_pair(it->first, true));
|
||||
readSDValues(cb, it->second, stack);
|
||||
stack.pop_back();
|
||||
}
|
||||
}
|
||||
else if (sd.isArray())
|
||||
{
|
||||
for (LLSD::array_const_iterator it = sd.beginArray();
|
||||
it != sd.endArray();
|
||||
++it)
|
||||
{
|
||||
stack.back().second = true;
|
||||
readSDValues(cb, *it, stack);
|
||||
}
|
||||
}
|
||||
else if (sd.isUndefined())
|
||||
{
|
||||
if (!cb.empty())
|
||||
{
|
||||
cb(NO_VALUE_MARKER, stack);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!cb.empty())
|
||||
{
|
||||
cb(sd, stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd)
|
||||
{
|
||||
LLInitParam::Parser::name_stack_t stack = LLInitParam::Parser::name_stack_t();
|
||||
readSDValues(cb, sd, stack);
|
||||
}
|
||||
namespace LLInitParam
|
||||
{
|
||||
// LLSD specialization
|
||||
// block param interface
|
||||
bool ParamValue<LLSD, TypeValues<LLSD>, false>::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name)
|
||||
{
|
||||
LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack);
|
||||
|
||||
LLSD::String string;
|
||||
|
||||
if (p.readValue<LLSD::String>(string))
|
||||
{
|
||||
sd = string;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//static
|
||||
void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack)
|
||||
{
|
||||
p.writeValue<LLSD::String>(sd.asString(), name_stack);
|
||||
}
|
||||
|
||||
void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const
|
||||
{
|
||||
// read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc)
|
||||
Parser::name_stack_t stack;
|
||||
LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack);
|
||||
}
|
||||
}
|
||||
126
indra/llcommon/llsdparam.h
Normal file
126
indra/llcommon/llsdparam.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* @file llsdparam.h
|
||||
* @brief parameter block abstraction for creating complex objects and
|
||||
* parsing construction parameters from xml and LLSD
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLSDPARAM_H
|
||||
#define LL_LLSDPARAM_H
|
||||
|
||||
#include "llinitparam.h"
|
||||
#include "boost/function.hpp"
|
||||
|
||||
struct LL_COMMON_API LLParamSDParserUtilities
|
||||
{
|
||||
static LLSD& getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range);
|
||||
|
||||
typedef boost::function<void (const LLSD&, LLInitParam::Parser::name_stack_t&)> read_sd_cb_t;
|
||||
static void readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack);
|
||||
static void readSDValues(read_sd_cb_t cb, const LLSD& sd);
|
||||
};
|
||||
|
||||
class LL_COMMON_API LLParamSDParser
|
||||
: public LLInitParam::Parser
|
||||
{
|
||||
LOG_CLASS(LLParamSDParser);
|
||||
|
||||
typedef LLInitParam::Parser parser_t;
|
||||
|
||||
public:
|
||||
LLParamSDParser();
|
||||
void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false);
|
||||
void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block);
|
||||
|
||||
/*virtual*/ std::string getCurrentElementName();
|
||||
|
||||
private:
|
||||
void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack);
|
||||
|
||||
template<typename T>
|
||||
static bool writeTypedValue(Parser& parser, const void* val_ptr, parser_t::name_stack_t& name_stack)
|
||||
{
|
||||
LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser);
|
||||
if (!sdparser.mWriteRootSD) return false;
|
||||
|
||||
LLInitParam::Parser::name_stack_range_t range(name_stack.begin(), name_stack.end());
|
||||
LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range);
|
||||
|
||||
sd_to_write.assign(*((const T*)val_ptr));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool writeU32Param(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack);
|
||||
static bool writeFlag(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack);
|
||||
|
||||
static bool readFlag(Parser& parser, void* val_ptr);
|
||||
static bool readS32(Parser& parser, void* val_ptr);
|
||||
static bool readU32(Parser& parser, void* val_ptr);
|
||||
static bool readF32(Parser& parser, void* val_ptr);
|
||||
static bool readF64(Parser& parser, void* val_ptr);
|
||||
static bool readBool(Parser& parser, void* val_ptr);
|
||||
static bool readString(Parser& parser, void* val_ptr);
|
||||
static bool readUUID(Parser& parser, void* val_ptr);
|
||||
static bool readDate(Parser& parser, void* val_ptr);
|
||||
static bool readURI(Parser& parser, void* val_ptr);
|
||||
static bool readSD(Parser& parser, void* val_ptr);
|
||||
|
||||
Parser::name_stack_t mNameStack;
|
||||
const LLSD* mCurReadSD;
|
||||
LLSD* mWriteRootSD;
|
||||
LLSD* mCurWriteSD;
|
||||
};
|
||||
|
||||
|
||||
extern LL_COMMON_API LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR;
|
||||
template<typename T>
|
||||
class LLSDParamAdapter : public T
|
||||
{
|
||||
public:
|
||||
LLSDParamAdapter() {}
|
||||
LLSDParamAdapter(const LLSD& sd)
|
||||
{
|
||||
LLFastTimer _(FTM_SD_PARAM_ADAPTOR);
|
||||
LLParamSDParser parser;
|
||||
// don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it
|
||||
bool parse_silently = true;
|
||||
parser.readSD(sd, *this, parse_silently);
|
||||
}
|
||||
|
||||
operator LLSD() const
|
||||
{
|
||||
LLParamSDParser parser;
|
||||
LLSD sd;
|
||||
parser.writeSD(sd, *this);
|
||||
return sd;
|
||||
}
|
||||
|
||||
LLSDParamAdapter(const T& val)
|
||||
: T(val)
|
||||
{
|
||||
T::operator=(val);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // LL_LLSDPARAM_H
|
||||
|
||||
@@ -45,44 +45,49 @@ const std::string AUCTION_URL (
|
||||
const std::string EVENTS_URL (
|
||||
"http://secondlife.com/events/");
|
||||
|
||||
/*
|
||||
const std::string TIER_UP_URL (
|
||||
"http://secondlife.com/app/landtier");
|
||||
|
||||
const std::string LAND_URL (
|
||||
"http://secondlife.com/app/landtier");
|
||||
|
||||
const std::string UPGRADE_TO_PREMIUM_URL (
|
||||
"http://secondlife.com/app/upgrade/");
|
||||
"http://secondlife.com/app/landtier"); // *TODO: NOT USED
|
||||
*/
|
||||
|
||||
const std::string DIRECTX_9_URL (
|
||||
"http://secondlife.com/support/");
|
||||
"http://secondlife.com/support/"); // *TODO: NOT USED
|
||||
/*
|
||||
const std::string LAND_URL (
|
||||
"http://secondlife.com/app/landtier"); // *TODO: NOT USED
|
||||
|
||||
const std::string UPGRADE_TO_PREMIUM_URL (
|
||||
"http://secondlife.com/app/upgrade/"); // *TODO: NOT USED
|
||||
|
||||
const std::string AMD_AGP_URL (
|
||||
"http://secondlife.com/support/");
|
||||
"http://secondlife.com/support/"); // *TODO: NOT USED
|
||||
|
||||
const std::string VIA_URL (
|
||||
"http://secondlife.com/support/");
|
||||
"http://secondlife.com/support/"); // *TODO: NOT USED
|
||||
|
||||
const std::string SUPPORT_URL (
|
||||
"http://secondlife.com/support/");
|
||||
|
||||
const std::string INTEL_CHIPSET_URL (
|
||||
"http://secondlife.com/support/");
|
||||
"http://secondlife.com/support/"); // *TODO: NOT USED
|
||||
|
||||
const std::string SIS_CHIPSET_URL (
|
||||
"http://secondlife.com/support/");
|
||||
"http://secondlife.com/support/"); // *TODO: NOT USED
|
||||
|
||||
const std::string BLOGS_URL (
|
||||
"http://blog.secondlife.com/");
|
||||
"http://blog.secondlife.com/"); // *TODO: NOT USED
|
||||
*/
|
||||
|
||||
const std::string BUY_CURRENCY_URL (
|
||||
"http://secondlife.com/app/currency/");
|
||||
|
||||
/*
|
||||
const std::string LSL_DOC_URL (
|
||||
"http://secondlife.com/app/lsldoc/");
|
||||
"http://secondlife.com/app/lsldoc/"); // *TODO: NOT USED
|
||||
|
||||
const std::string SL_KB_URL (
|
||||
"http://secondlife.com/knowledgebase/");
|
||||
"http://secondlife.com/knowledgebase/"); // *TODO: NOT USED
|
||||
|
||||
const std::string RELEASE_NOTES_BASE_URL (
|
||||
"http://ascent.balseraph.org/?");
|
||||
"http://secondlife.com/app/releasenotes/");
|
||||
*/
|
||||
|
||||
@@ -43,18 +43,22 @@ LL_COMMON_API extern const std::string AUCTION_URL;
|
||||
|
||||
LL_COMMON_API extern const std::string EVENTS_URL;
|
||||
|
||||
/*
|
||||
// Tier up to a new land level.
|
||||
LL_COMMON_API extern const std::string TIER_UP_URL;
|
||||
|
||||
// Tier up to a new land level.
|
||||
LL_COMMON_API extern const std::string LAND_URL;
|
||||
|
||||
// Upgrade from basic membership to premium membership
|
||||
LL_COMMON_API extern const std::string UPGRADE_TO_PREMIUM_URL;
|
||||
*/
|
||||
|
||||
// How to get DirectX 9
|
||||
LL_COMMON_API extern const std::string DIRECTX_9_URL;
|
||||
|
||||
/*
|
||||
// Upgrade from basic membership to premium membership
|
||||
LL_COMMON_API extern const std::string UPGRADE_TO_PREMIUM_URL;
|
||||
|
||||
|
||||
// Out of date VIA chipset
|
||||
LL_COMMON_API extern const std::string VIA_URL;
|
||||
|
||||
@@ -63,10 +67,12 @@ LL_COMMON_API extern const std::string SUPPORT_URL;
|
||||
|
||||
// Linden Blogs page
|
||||
LL_COMMON_API extern const std::string BLOGS_URL;
|
||||
*/
|
||||
|
||||
// Currency page
|
||||
LL_COMMON_API extern const std::string BUY_CURRENCY_URL;
|
||||
|
||||
/*
|
||||
// LSL script wiki
|
||||
LL_COMMON_API extern const std::string LSL_DOC_URL;
|
||||
|
||||
@@ -75,5 +81,5 @@ LL_COMMON_API extern const std::string SL_KB_URL;
|
||||
|
||||
// Release Notes Redirect URL for Server and Viewer
|
||||
LL_COMMON_API extern const std::string RELEASE_NOTES_BASE_URL;
|
||||
|
||||
*/
|
||||
#endif
|
||||
|
||||
@@ -917,6 +917,7 @@ P(MPImportGetResponder);
|
||||
P(MPImportPostResponder);
|
||||
P(mapLayerResponder);
|
||||
P2(maturityPreferences, transfer_30s);
|
||||
P(mediaDataClientResponder);
|
||||
P(mediaTypeResponder);
|
||||
P(meshDecompositionResponder);
|
||||
P(meshHeaderResponder);
|
||||
|
||||
@@ -56,6 +56,7 @@ bool LLPluginClassMedia::init_impl(void)
|
||||
{
|
||||
// Queue up the media init message -- it will be sent after all the currently queued messages.
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
|
||||
message.setValue("target", mTarget);
|
||||
sendMessage(message);
|
||||
|
||||
return true;
|
||||
@@ -127,7 +128,7 @@ void LLPluginClassMedia::reset_impl(void)
|
||||
|
||||
void LLPluginClassMedia::idle_impl(void)
|
||||
{
|
||||
if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()))
|
||||
if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))
|
||||
{
|
||||
// Can't process a size change at this time
|
||||
}
|
||||
@@ -246,16 +247,18 @@ unsigned char* LLPluginClassMedia::getBitsData()
|
||||
|
||||
void LLPluginClassMedia::setSize(int width, int height)
|
||||
{
|
||||
if (width <= 0 || height <= 0)
|
||||
{
|
||||
width = height = -1;
|
||||
}
|
||||
if (mSetMediaWidth != width || mSetMediaHeight != height)
|
||||
if((width > 0) && (height > 0))
|
||||
{
|
||||
mSetMediaWidth = width;
|
||||
mSetMediaHeight = height;
|
||||
setSizeInternal();
|
||||
}
|
||||
else
|
||||
{
|
||||
mSetMediaWidth = -1;
|
||||
mSetMediaHeight = -1;
|
||||
}
|
||||
|
||||
setSizeInternal();
|
||||
}
|
||||
|
||||
void LLPluginClassMedia::setSizeInternal(void)
|
||||
|
||||
@@ -34,7 +34,9 @@
|
||||
#include "llrect.h"
|
||||
#include "v4color.h"
|
||||
|
||||
class LLPluginClassMedia : public LLPluginClassBasic
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::trackable
|
||||
{
|
||||
LOG_CLASS(LLPluginClassMedia);
|
||||
|
||||
|
||||
@@ -26,13 +26,30 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lluuid.h"
|
||||
#include "llmediaentry.h"
|
||||
#include "lltextureentry.h"
|
||||
#include "llsdutil_math.h"
|
||||
#include "v4color.h"
|
||||
|
||||
const U8 DEFAULT_BUMP_CODE = 0; // no bump or shininess
|
||||
|
||||
const LLTextureEntry LLTextureEntry::null;
|
||||
|
||||
// Some LLSD keys. Do not change these!
|
||||
#define OBJECT_ID_KEY_STR "object_id"
|
||||
#define TEXTURE_INDEX_KEY_STR "texture_index"
|
||||
#define OBJECT_MEDIA_VERSION_KEY_STR "object_media_version"
|
||||
#define OBJECT_MEDIA_DATA_KEY_STR "object_media_data"
|
||||
#define TEXTURE_MEDIA_DATA_KEY_STR "media_data"
|
||||
|
||||
/*static*/ const char* LLTextureEntry::OBJECT_ID_KEY = OBJECT_ID_KEY_STR;
|
||||
/*static*/ const char* LLTextureEntry::OBJECT_MEDIA_DATA_KEY = OBJECT_MEDIA_DATA_KEY_STR;
|
||||
/*static*/ const char* LLTextureEntry::MEDIA_VERSION_KEY = OBJECT_MEDIA_VERSION_KEY_STR;
|
||||
/*static*/ const char* LLTextureEntry::TEXTURE_INDEX_KEY = TEXTURE_INDEX_KEY_STR;
|
||||
/*static*/ const char* LLTextureEntry::TEXTURE_MEDIA_DATA_KEY = TEXTURE_MEDIA_DATA_KEY_STR;
|
||||
|
||||
static const std::string MEDIA_VERSION_STRING_PREFIX = "x-mv:";
|
||||
|
||||
// static
|
||||
LLTextureEntry* LLTextureEntry::newTextureEntry()
|
||||
@@ -42,16 +59,19 @@ LLTextureEntry* LLTextureEntry::newTextureEntry()
|
||||
|
||||
//===============================================================
|
||||
LLTextureEntry::LLTextureEntry()
|
||||
: mMediaEntry(NULL)
|
||||
{
|
||||
init(LLUUID::null,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);
|
||||
}
|
||||
|
||||
LLTextureEntry::LLTextureEntry(const LLUUID& tex_id)
|
||||
: mMediaEntry(NULL)
|
||||
{
|
||||
init(tex_id,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);
|
||||
}
|
||||
|
||||
LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs)
|
||||
: mMediaEntry(NULL)
|
||||
{
|
||||
mID = rhs.mID;
|
||||
mScaleS = rhs.mScaleS;
|
||||
@@ -63,6 +83,10 @@ LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs)
|
||||
mBump = rhs.mBump;
|
||||
mMediaFlags = rhs.mMediaFlags;
|
||||
mGlow = rhs.mGlow;
|
||||
if (rhs.mMediaEntry != NULL) {
|
||||
// Make a copy
|
||||
mMediaEntry = new LLMediaEntry(*rhs.mMediaEntry);
|
||||
}
|
||||
}
|
||||
|
||||
LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs)
|
||||
@@ -79,6 +103,16 @@ LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs)
|
||||
mBump = rhs.mBump;
|
||||
mMediaFlags = rhs.mMediaFlags;
|
||||
mGlow = rhs.mGlow;
|
||||
if (mMediaEntry != NULL) {
|
||||
delete mMediaEntry;
|
||||
}
|
||||
if (rhs.mMediaEntry != NULL) {
|
||||
// Make a copy
|
||||
mMediaEntry = new LLMediaEntry(*rhs.mMediaEntry);
|
||||
}
|
||||
else {
|
||||
mMediaEntry = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
@@ -98,10 +132,19 @@ void LLTextureEntry::init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 of
|
||||
mGlow = 0;
|
||||
|
||||
setColor(LLColor4(1.f, 1.f, 1.f, 1.f));
|
||||
if (mMediaEntry != NULL) {
|
||||
delete mMediaEntry;
|
||||
}
|
||||
mMediaEntry = NULL;
|
||||
}
|
||||
|
||||
LLTextureEntry::~LLTextureEntry()
|
||||
{
|
||||
if(mMediaEntry)
|
||||
{
|
||||
delete mMediaEntry;
|
||||
mMediaEntry = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool LLTextureEntry::operator!=(const LLTextureEntry &rhs) const
|
||||
@@ -153,6 +196,13 @@ void LLTextureEntry::asLLSD(LLSD& sd) const
|
||||
sd["bump"] = getBumpShiny();
|
||||
sd["fullbright"] = getFullbright();
|
||||
sd["media_flags"] = mMediaFlags;
|
||||
if (hasMedia()) {
|
||||
LLSD mediaData;
|
||||
if (NULL != getMediaData()) {
|
||||
getMediaData()->asLLSD(mediaData);
|
||||
}
|
||||
sd[TEXTURE_MEDIA_DATA_KEY] = mediaData;
|
||||
}
|
||||
sd["glow"] = mGlow;
|
||||
}
|
||||
|
||||
@@ -201,6 +251,17 @@ bool LLTextureEntry::fromLLSD(const LLSD& sd)
|
||||
{
|
||||
setMediaTexGen( sd[w].asInteger() );
|
||||
} else goto fail;
|
||||
// If the "has media" flag doesn't match the fact that
|
||||
// media data exists, updateMediaData will "fix" it
|
||||
// by either clearing or setting the flag
|
||||
w = TEXTURE_MEDIA_DATA_KEY;
|
||||
if (hasMedia() != sd.has(w))
|
||||
{
|
||||
llwarns << "LLTextureEntry::fromLLSD: media_flags (" << hasMedia() <<
|
||||
") does not match presence of media_data (" << sd.has(w) << "). Fixing." << llendl;
|
||||
}
|
||||
updateMediaData(sd[w]);
|
||||
|
||||
w = "glow";
|
||||
if (sd.has(w))
|
||||
{
|
||||
@@ -362,12 +423,10 @@ S32 LLTextureEntry::setBumpShinyFullbright(U8 bump)
|
||||
|
||||
S32 LLTextureEntry::setMediaTexGen(U8 media)
|
||||
{
|
||||
if (mMediaFlags != media)
|
||||
{
|
||||
mMediaFlags = media;
|
||||
return TEM_CHANGE_MEDIA;
|
||||
}
|
||||
return TEM_CHANGE_NONE;
|
||||
S32 result = TEM_CHANGE_NONE;
|
||||
result |= setTexGen(media & TEM_TEX_GEN_MASK);
|
||||
result |= setMediaFlags(media & TEM_MEDIA_MASK);
|
||||
return result;
|
||||
}
|
||||
|
||||
S32 LLTextureEntry::setBumpmap(U8 bump)
|
||||
@@ -425,6 +484,18 @@ S32 LLTextureEntry::setMediaFlags(U8 media_flags)
|
||||
{
|
||||
mMediaFlags &= ~TEM_MEDIA_MASK;
|
||||
mMediaFlags |= media_flags;
|
||||
|
||||
// Special code for media handling
|
||||
if( hasMedia() && mMediaEntry == NULL)
|
||||
{
|
||||
mMediaEntry = new LLMediaEntry;
|
||||
}
|
||||
else if ( ! hasMedia() && mMediaEntry != NULL)
|
||||
{
|
||||
delete mMediaEntry;
|
||||
mMediaEntry = NULL;
|
||||
}
|
||||
|
||||
return TEM_CHANGE_MEDIA;
|
||||
}
|
||||
return TEM_CHANGE_NONE;
|
||||
@@ -452,4 +523,112 @@ S32 LLTextureEntry::setGlow(F32 glow)
|
||||
return TEM_CHANGE_NONE;
|
||||
}
|
||||
|
||||
void LLTextureEntry::setMediaData(const LLMediaEntry &media_entry)
|
||||
{
|
||||
mMediaFlags |= MF_HAS_MEDIA;
|
||||
if (NULL != mMediaEntry)
|
||||
{
|
||||
delete mMediaEntry;
|
||||
}
|
||||
mMediaEntry = new LLMediaEntry(media_entry);
|
||||
}
|
||||
|
||||
bool LLTextureEntry::updateMediaData(const LLSD& media_data)
|
||||
{
|
||||
if (media_data.isUndefined())
|
||||
{
|
||||
// clear the media data
|
||||
clearMediaData();
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
mMediaFlags |= MF_HAS_MEDIA;
|
||||
if (mMediaEntry == NULL)
|
||||
{
|
||||
mMediaEntry = new LLMediaEntry;
|
||||
}
|
||||
// *NOTE: this will *clobber* all of the fields in mMediaEntry
|
||||
// with whatever fields are present (or not present) in media_data!
|
||||
mMediaEntry->fromLLSD(media_data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void LLTextureEntry::clearMediaData()
|
||||
{
|
||||
mMediaFlags &= ~MF_HAS_MEDIA;
|
||||
if (mMediaEntry != NULL) {
|
||||
delete mMediaEntry;
|
||||
}
|
||||
mMediaEntry = NULL;
|
||||
}
|
||||
|
||||
void LLTextureEntry::mergeIntoMediaData(const LLSD& media_fields)
|
||||
{
|
||||
mMediaFlags |= MF_HAS_MEDIA;
|
||||
if (mMediaEntry == NULL)
|
||||
{
|
||||
mMediaEntry = new LLMediaEntry;
|
||||
}
|
||||
// *NOTE: this will *merge* the data in media_fields
|
||||
// with the data in our media entry
|
||||
mMediaEntry->mergeFromLLSD(media_fields);
|
||||
}
|
||||
|
||||
//static
|
||||
std::string LLTextureEntry::touchMediaVersionString(const std::string &in_version, const LLUUID &agent_id)
|
||||
{
|
||||
// XXX TODO: make media version string binary (base64-encoded?)
|
||||
// Media "URL" is a representation of a version and the last-touched agent
|
||||
// x-mv:nnnnn/agent-id
|
||||
// where "nnnnn" is version number
|
||||
// *NOTE: not the most efficient code in the world...
|
||||
U32 current_version = getVersionFromMediaVersionString(in_version) + 1;
|
||||
const size_t MAX_VERSION_LEN = 10; // 2^32 fits in 10 decimal digits
|
||||
char buf[MAX_VERSION_LEN+1];
|
||||
snprintf(buf, (int)MAX_VERSION_LEN+1, "%0*u", (int)MAX_VERSION_LEN, current_version); // added int cast to fix warning/breakage on mac.
|
||||
return MEDIA_VERSION_STRING_PREFIX + buf + "/" + agent_id.asString();
|
||||
}
|
||||
|
||||
//static
|
||||
U32 LLTextureEntry::getVersionFromMediaVersionString(const std::string &version_string)
|
||||
{
|
||||
U32 version = 0;
|
||||
if (!version_string.empty())
|
||||
{
|
||||
size_t found = version_string.find(MEDIA_VERSION_STRING_PREFIX);
|
||||
if (found != std::string::npos)
|
||||
{
|
||||
found = version_string.find_first_of("/", found);
|
||||
std::string v = version_string.substr(MEDIA_VERSION_STRING_PREFIX.length(), found);
|
||||
version = strtoul(v.c_str(),NULL,10);
|
||||
}
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
//static
|
||||
LLUUID LLTextureEntry::getAgentIDFromMediaVersionString(const std::string &version_string)
|
||||
{
|
||||
LLUUID id;
|
||||
if (!version_string.empty())
|
||||
{
|
||||
size_t found = version_string.find(MEDIA_VERSION_STRING_PREFIX);
|
||||
if (found != std::string::npos)
|
||||
{
|
||||
found = version_string.find_first_of("/", found);
|
||||
if (found != std::string::npos)
|
||||
{
|
||||
std::string v = version_string.substr(found + 1);
|
||||
id.set(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
//static
|
||||
bool LLTextureEntry::isMediaVersionString(const std::string &version_string)
|
||||
{
|
||||
return std::string::npos != version_string.find(MEDIA_VERSION_STRING_PREFIX);
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ const S32 TEM_MEDIA_MASK = 0x01;
|
||||
const S32 TEM_TEX_GEN_MASK = 0x06;
|
||||
const S32 TEM_TEX_GEN_SHIFT = 1;
|
||||
|
||||
// forward declarations
|
||||
class LLMediaEntry;
|
||||
|
||||
class LLTextureEntry
|
||||
{
|
||||
@@ -137,6 +139,34 @@ public:
|
||||
U8 getTexGen() const { return mMediaFlags & TEM_TEX_GEN_MASK; }
|
||||
U8 getMediaTexGen() const { return mMediaFlags; }
|
||||
F32 getGlow() const { return mGlow; }
|
||||
|
||||
// *NOTE: it is possible for hasMedia() to return true, but getMediaData() to return NULL.
|
||||
// CONVERSELY, it is also possible for hasMedia() to return false, but getMediaData()
|
||||
// to NOT return NULL.
|
||||
bool hasMedia() const { return (bool)(mMediaFlags & MF_HAS_MEDIA); }
|
||||
LLMediaEntry* getMediaData() const { return mMediaEntry; }
|
||||
|
||||
// Completely change the media data on this texture entry.
|
||||
void setMediaData(const LLMediaEntry &media_entry);
|
||||
// Returns true if media data was updated, false if it was cleared
|
||||
bool updateMediaData(const LLSD& media_data);
|
||||
// Clears media data, and sets the media flags bit to 0
|
||||
void clearMediaData();
|
||||
// Merges the given LLSD of media fields with this media entry.
|
||||
// Only those fields that are set that match the keys in
|
||||
// LLMediaEntry will be affected. If no fields are set or if
|
||||
// the LLSD is undefined, this is a no-op.
|
||||
void mergeIntoMediaData(const LLSD& media_fields);
|
||||
|
||||
// Takes a media version string (an empty string or a previously-returned string)
|
||||
// and returns a "touched" string, touched by agent_id
|
||||
static std::string touchMediaVersionString(const std::string &in_version, const LLUUID &agent_id);
|
||||
// Given a media version string, return the version
|
||||
static U32 getVersionFromMediaVersionString(const std::string &version_string);
|
||||
// Given a media version string, return the UUID of the agent
|
||||
static LLUUID getAgentIDFromMediaVersionString(const std::string &version_string);
|
||||
// Return whether or not the given string is actually a media version
|
||||
static bool isMediaVersionString(const std::string &version_string);
|
||||
|
||||
// Media flags
|
||||
enum { MF_NONE = 0x0, MF_HAS_MEDIA = 0x1 };
|
||||
@@ -149,6 +179,14 @@ public:
|
||||
F32 mRotation; // anti-clockwise rotation in rad about the bottom left corner
|
||||
|
||||
static const LLTextureEntry null;
|
||||
|
||||
// LLSD key defines
|
||||
static const char* OBJECT_ID_KEY;
|
||||
static const char* OBJECT_MEDIA_DATA_KEY;
|
||||
static const char* MEDIA_VERSION_KEY;
|
||||
static const char* TEXTURE_INDEX_KEY;
|
||||
static const char* TEXTURE_MEDIA_DATA_KEY;
|
||||
|
||||
protected:
|
||||
LLUUID mID; // Texture GUID
|
||||
LLColor4 mColor;
|
||||
@@ -156,6 +194,9 @@ protected:
|
||||
U8 mMediaFlags; // replace with web page, movie, etc.
|
||||
F32 mGlow;
|
||||
|
||||
// Note the media data is not sent via the same message structure as the rest of the TE
|
||||
LLMediaEntry* mMediaEntry; // The media data for the face
|
||||
|
||||
// NOTE: when adding new data to this class, in addition to adding it to the serializers asLLSD/fromLLSD and the
|
||||
// message packers (e.g. LLPrimitive::packTEMessage) you must also implement its copy in LLPrimitive::copyTEs()
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ set(llui_SOURCE_FILES
|
||||
llfunctorregistry.cpp
|
||||
lliconctrl.cpp
|
||||
llkeywords.cpp
|
||||
lllayoutstack.cpp
|
||||
lllineeditor.cpp
|
||||
lllocalcliprect.cpp
|
||||
llmenugl.cpp
|
||||
@@ -78,6 +79,10 @@ set(llui_SOURCE_FILES
|
||||
lluictrlfactory.cpp
|
||||
lluistring.cpp
|
||||
llundo.cpp
|
||||
llurlaction.cpp
|
||||
llurlentry.cpp
|
||||
llurlmatch.cpp
|
||||
llurlregistry.cpp
|
||||
llview.cpp
|
||||
llviewborder.cpp
|
||||
llviewmodel.cpp
|
||||
@@ -105,6 +110,7 @@ set(llui_HEADER_FILES
|
||||
llhtmlhelp.h
|
||||
lliconctrl.h
|
||||
llkeywords.h
|
||||
lllayoutstack.h
|
||||
lllineeditor.h
|
||||
lllocalcliprect.h
|
||||
llmemberlistener.h
|
||||
@@ -150,6 +156,10 @@ set(llui_HEADER_FILES
|
||||
lluistring.h
|
||||
lluixmltags.h
|
||||
llundo.h
|
||||
llurlaction.h
|
||||
llurlentry.h
|
||||
llurlmatch.h
|
||||
llurlregistry.h
|
||||
llview.h
|
||||
llviewborder.h
|
||||
llviewmodel.h
|
||||
|
||||
@@ -520,7 +520,7 @@ void LLAlertDialog::onButtonPressed( LLUICtrl* ctrl, const std::string url )
|
||||
// If we declared a URL and chose the URL option, go to the url
|
||||
if (!url.empty() && sURLLoader != NULL)
|
||||
{
|
||||
sURLLoader->load(url);
|
||||
sURLLoader->load(url, false);
|
||||
}
|
||||
|
||||
mNote->respond(response); // new notification reponse
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
class URLLoader
|
||||
{
|
||||
public:
|
||||
virtual void load(const std::string& url) = 0;
|
||||
virtual void load(const std::string& url, bool force_open_externally) = 0;
|
||||
virtual ~URLLoader() {}
|
||||
};
|
||||
|
||||
|
||||
@@ -2488,8 +2488,13 @@ LLView* LLFloater::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
|
||||
|
||||
if (filename.empty())
|
||||
{
|
||||
// for local registry callbacks; define in constructor, referenced in XUI or postBuild
|
||||
floaterp->getCommitCallbackRegistrar().pushScope();
|
||||
floaterp->getEnableCallbackRegistrar().pushScope();
|
||||
// Load from node
|
||||
floaterp->initFloaterXML(node, parent, factory);
|
||||
floaterp->getCommitCallbackRegistrar().popScope();
|
||||
floaterp->getEnableCallbackRegistrar().popScope();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
682
indra/llui/lllayoutstack.cpp
Normal file
682
indra/llui/lllayoutstack.cpp
Normal file
@@ -0,0 +1,682 @@
|
||||
/**
|
||||
* @file lllayoutstack.cpp
|
||||
* @brief LLLayout class - dynamic stacking of UI elements
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Opaque view with a background and a border. Can contain LLUICtrls.
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lllayoutstack.h"
|
||||
|
||||
#include "lllocalcliprect.h"
|
||||
#include "llpanel.h"
|
||||
#include "llresizebar.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llcriticaldamp.h"
|
||||
#include "boost/foreach.hpp"
|
||||
|
||||
static const F32 MIN_FRACTIONAL_SIZE = 0.0f;
|
||||
static const F32 MAX_FRACTIONAL_SIZE = 1.f;
|
||||
static const S32 RESIZE_BAR_OVERLAP = 1;
|
||||
static const S32 RESIZE_BAR_HEIGHT = 3;
|
||||
|
||||
//
|
||||
// LLLayoutPanel
|
||||
//
|
||||
LLLayoutPanel::LLLayoutPanel(LLPanel* panelp, LLLayoutStack::eLayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize) :
|
||||
mPanel(panelp),
|
||||
mMinWidth(min_width),
|
||||
mMinHeight(min_height),
|
||||
mAutoResize(auto_resize),
|
||||
mUserResize(user_resize),
|
||||
mCollapsed(FALSE),
|
||||
mCollapseAmt(0.f),
|
||||
mVisibleAmt(1.f), // default to fully visible
|
||||
mResizeBar(NULL),
|
||||
mOrientation(orientation)
|
||||
{
|
||||
LLResizeBar::Side side = (orientation == LLLayoutStack::HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
|
||||
|
||||
S32 min_dim;
|
||||
if (orientation == LLLayoutStack::HORIZONTAL)
|
||||
{
|
||||
min_dim = mMinHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
min_dim = mMinWidth;
|
||||
}
|
||||
LLResizeBar::Params p;
|
||||
p.name = "resizer";
|
||||
p.resizing_view = mPanel;
|
||||
p.min_size = min_dim;
|
||||
p.max_size = S32_MAX;
|
||||
p.side = side;
|
||||
mResizeBar = LLUICtrlFactory::create<LLResizeBar>(p);
|
||||
mResizeBar->setEnableSnapping(FALSE);
|
||||
// panels initialized as hidden should not start out partially visible
|
||||
if (!mPanel->getVisible())
|
||||
{
|
||||
mVisibleAmt = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
LLLayoutPanel::~LLLayoutPanel()
|
||||
{
|
||||
// probably not necessary, but...
|
||||
delete mResizeBar;
|
||||
mResizeBar = NULL;
|
||||
}
|
||||
|
||||
F32 LLLayoutPanel::getCollapseFactor()
|
||||
{
|
||||
if (mOrientation == LLLayoutStack::HORIZONTAL)
|
||||
{
|
||||
F32 collapse_amt =
|
||||
clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinWidth / (F32)llmax(1, mPanel->getRect().getWidth()));
|
||||
return mVisibleAmt * collapse_amt;
|
||||
}
|
||||
else
|
||||
{
|
||||
F32 collapse_amt =
|
||||
clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinHeight / (F32)llmax(1, mPanel->getRect().getHeight())));
|
||||
return mVisibleAmt * collapse_amt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static LLRegisterWidget<LLLayoutStack> r2("layout_stack");
|
||||
|
||||
LLLayoutStack::LLLayoutStack(eLayoutOrientation orientation) :
|
||||
mOrientation(orientation),
|
||||
mMinWidth(0),
|
||||
mMinHeight(0),
|
||||
mPanelSpacing(RESIZE_BAR_HEIGHT)
|
||||
{
|
||||
}
|
||||
|
||||
LLLayoutStack::~LLLayoutStack()
|
||||
{
|
||||
e_panel_list_t panels = mPanels; // copy list of panel pointers
|
||||
mPanels.clear(); // clear so that removeChild() calls don't cause trouble
|
||||
std::for_each(panels.begin(), panels.end(), DeletePointer());
|
||||
}
|
||||
|
||||
void LLLayoutStack::draw()
|
||||
{
|
||||
updateLayout();
|
||||
|
||||
e_panel_list_t::iterator panel_it;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
// clip to layout rectangle, not bounding rectangle
|
||||
LLRect clip_rect = (*panel_it)->mPanel->getRect();
|
||||
// scale clipping rectangle by visible amount
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor());
|
||||
}
|
||||
else
|
||||
{
|
||||
clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor());
|
||||
}
|
||||
|
||||
LLPanel* panelp = (*panel_it)->mPanel;
|
||||
|
||||
LLLocalClipRect clip(clip_rect);
|
||||
// only force drawing invisible children if visible amount is non-zero
|
||||
drawChild(panelp, 0, 0, clip_rect.notEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
void LLLayoutStack::removeChild(LLView* ctrl)
|
||||
{
|
||||
LLView::removeChild(ctrl);
|
||||
LLPanel* panel = dynamic_cast<LLPanel*>(ctrl);
|
||||
if(!panel)
|
||||
return;
|
||||
LLLayoutPanel* embedded_panelp = findEmbeddedPanel(panel);
|
||||
|
||||
if (embedded_panelp)
|
||||
{
|
||||
mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp));
|
||||
delete embedded_panelp;
|
||||
}
|
||||
|
||||
// need to update resizebars
|
||||
|
||||
calcMinExtents();
|
||||
}
|
||||
|
||||
LLXMLNodePtr LLLayoutStack::getXML(bool save_children) const
|
||||
{
|
||||
LLXMLNodePtr node = LLView::getXML();
|
||||
node->setName(LL_LAYOUT_STACK_TAG);
|
||||
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
node->createChild("orientation", TRUE)->setStringValue("horizontal");
|
||||
}
|
||||
else
|
||||
{
|
||||
node->createChild("orientation", TRUE)->setStringValue("vertical");
|
||||
}
|
||||
|
||||
if (save_children)
|
||||
{
|
||||
LLView::child_list_const_reverse_iter_t rit;
|
||||
for (rit = getChildList()->rbegin(); rit != getChildList()->rend(); ++rit)
|
||||
{
|
||||
LLView* childp = *rit;
|
||||
|
||||
if (childp->getSaveToXML())
|
||||
{
|
||||
LLXMLNodePtr xml_node = childp->getXML();
|
||||
|
||||
if (xml_node->hasName(LL_PANEL_TAG))
|
||||
{
|
||||
xml_node->setName(LL_LAYOUT_PANEL_TAG);
|
||||
}
|
||||
|
||||
node->addChild(xml_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
//static
|
||||
LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
|
||||
{
|
||||
std::string orientation_string("vertical");
|
||||
node->getAttributeString("orientation", orientation_string);
|
||||
|
||||
eLayoutOrientation orientation = VERTICAL;
|
||||
|
||||
if (orientation_string == "horizontal")
|
||||
{
|
||||
orientation = HORIZONTAL;
|
||||
}
|
||||
else if (orientation_string == "vertical")
|
||||
{
|
||||
orientation = VERTICAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "Unknown orientation " << orientation_string << ", using vertical" << llendl;
|
||||
}
|
||||
|
||||
LLLayoutStack* layout_stackp = new LLLayoutStack(orientation);
|
||||
|
||||
node->getAttributeS32("border_size", layout_stackp->mPanelSpacing);
|
||||
// don't allow negative spacing values
|
||||
layout_stackp->mPanelSpacing = llmax(layout_stackp->mPanelSpacing, 0);
|
||||
|
||||
std::string name("stack");
|
||||
node->getAttributeString("name", name);
|
||||
|
||||
layout_stackp->setName(name);
|
||||
layout_stackp->initFromXML(node, parent);
|
||||
|
||||
LLXMLNodePtr child;
|
||||
for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
|
||||
{
|
||||
S32 min_width = 0;
|
||||
S32 min_height = 0;
|
||||
BOOL auto_resize = TRUE;
|
||||
|
||||
child->getAttributeS32("min_width", min_width);
|
||||
child->getAttributeS32("min_height", min_height);
|
||||
child->getAttributeBOOL("auto_resize", auto_resize);
|
||||
|
||||
if (child->hasName("layout_panel"))
|
||||
{
|
||||
BOOL user_resize = TRUE;
|
||||
child->getAttributeBOOL("user_resize", user_resize);
|
||||
LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child, layout_stackp, factory);
|
||||
if (panelp)
|
||||
{
|
||||
panelp->setFollowsNone();
|
||||
layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOL user_resize = FALSE;
|
||||
child->getAttributeBOOL("user_resize", user_resize);
|
||||
|
||||
LLPanel* panelp = new LLPanel(std::string("auto_panel"));
|
||||
LLView* new_child = factory->createWidget(panelp, child);
|
||||
if (new_child)
|
||||
{
|
||||
// put child in new embedded panel
|
||||
layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
|
||||
// resize panel to contain widget and move widget to be contained in panel
|
||||
panelp->setRect(new_child->getRect());
|
||||
new_child->setOrigin(0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
panelp->die();
|
||||
}
|
||||
}
|
||||
}
|
||||
layout_stackp->updateLayout();
|
||||
|
||||
return layout_stackp;
|
||||
}
|
||||
|
||||
S32 LLLayoutStack::getDefaultHeight(S32 cur_height)
|
||||
{
|
||||
// if we are spanning our children (crude upward propagation of size)
|
||||
// then don't enforce our size on our children
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
cur_height = llmax(mMinHeight, getRect().getHeight());
|
||||
}
|
||||
|
||||
return cur_height;
|
||||
}
|
||||
|
||||
S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
|
||||
{
|
||||
// if we are spanning our children (crude upward propagation of size)
|
||||
// then don't enforce our size on our children
|
||||
if (mOrientation == VERTICAL)
|
||||
{
|
||||
cur_width = llmax(mMinWidth, getRect().getWidth());
|
||||
}
|
||||
|
||||
return cur_width;
|
||||
}
|
||||
|
||||
void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, EAnimate animate, S32 index)
|
||||
{
|
||||
// panel starts off invisible (collapsed)
|
||||
if (animate == ANIMATE)
|
||||
{
|
||||
panel->setVisible(FALSE);
|
||||
}
|
||||
LLLayoutPanel* embedded_panel = new LLLayoutPanel(panel, mOrientation, min_width, min_height, auto_resize, user_resize);
|
||||
|
||||
mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel);
|
||||
|
||||
addChild(panel);
|
||||
addChild(embedded_panel->mResizeBar);
|
||||
|
||||
// bring all resize bars to the front so that they are clickable even over the panels
|
||||
// with a bit of overlap
|
||||
for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
|
||||
sendChildToFront(resize_barp);
|
||||
}
|
||||
|
||||
// start expanding panel animation
|
||||
if (animate == ANIMATE)
|
||||
{
|
||||
panel->setVisible(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void LLLayoutStack::removePanel(LLPanel* panel)
|
||||
{
|
||||
removeChild(panel);
|
||||
}
|
||||
|
||||
void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
|
||||
{
|
||||
LLLayoutPanel* panel_container = findEmbeddedPanel(panel);
|
||||
if (!panel_container) return;
|
||||
|
||||
panel_container->mCollapsed = collapsed;
|
||||
}
|
||||
|
||||
void LLLayoutStack::updateLayout(BOOL force_resize)
|
||||
{
|
||||
calcMinExtents();
|
||||
|
||||
// calculate current extents
|
||||
S32 total_width = 0;
|
||||
S32 total_height = 0;
|
||||
|
||||
const F32 ANIM_OPEN_TIME = 0.02f;
|
||||
const F32 ANIM_CLOSE_TIME = 0.03f;
|
||||
|
||||
e_panel_list_t::iterator panel_it;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLPanel* panelp = (*panel_it)->mPanel;
|
||||
if (panelp->getVisible())
|
||||
{
|
||||
(*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME));
|
||||
if ((*panel_it)->mVisibleAmt > 0.99f)
|
||||
{
|
||||
(*panel_it)->mVisibleAmt = 1.f;
|
||||
}
|
||||
}
|
||||
else // not visible
|
||||
{
|
||||
(*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
|
||||
if ((*panel_it)->mVisibleAmt < 0.001f)
|
||||
{
|
||||
(*panel_it)->mVisibleAmt = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
if ((*panel_it)->mCollapsed)
|
||||
{
|
||||
(*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
|
||||
}
|
||||
else
|
||||
{
|
||||
(*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
|
||||
}
|
||||
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
// enforce minimize size constraint by default
|
||||
if (panelp->getRect().getWidth() < (*panel_it)->mMinWidth)
|
||||
{
|
||||
panelp->reshape((*panel_it)->mMinWidth, panelp->getRect().getHeight());
|
||||
}
|
||||
total_width += llround(panelp->getRect().getWidth() * (*panel_it)->getCollapseFactor());
|
||||
// want n-1 panel gaps for n panels
|
||||
if (panel_it != mPanels.begin())
|
||||
{
|
||||
total_width += mPanelSpacing;
|
||||
}
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
// enforce minimize size constraint by default
|
||||
if (panelp->getRect().getHeight() < (*panel_it)->mMinHeight)
|
||||
{
|
||||
panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinHeight);
|
||||
}
|
||||
total_height += llround(panelp->getRect().getHeight() * (*panel_it)->getCollapseFactor());
|
||||
if (panel_it != mPanels.begin())
|
||||
{
|
||||
total_height += mPanelSpacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
S32 num_resizable_panels = 0;
|
||||
S32 shrink_headroom_available = 0;
|
||||
S32 shrink_headroom_total = 0;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
// panels that are not fully visible do not count towards shrink headroom
|
||||
if ((*panel_it)->getCollapseFactor() < 1.f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if currently resizing a panel or the panel is flagged as not automatically resizing
|
||||
// only track total available headroom, but don't use it for automatic resize logic
|
||||
if ((*panel_it)->mResizeBar->hasMouseCapture()
|
||||
|| (!(*panel_it)->mAutoResize
|
||||
&& !force_resize))
|
||||
{
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
num_resizable_panels++;
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
shrink_headroom_available += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
|
||||
shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
shrink_headroom_available += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
|
||||
shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculate how many pixels need to be distributed among layout panels
|
||||
// positive means panels need to grow, negative means shrink
|
||||
S32 pixels_to_distribute;
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
pixels_to_distribute = getRect().getWidth() - total_width;
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
pixels_to_distribute = getRect().getHeight() - total_height;
|
||||
}
|
||||
|
||||
// now we distribute the pixels...
|
||||
S32 cur_x = 0;
|
||||
S32 cur_y = getRect().getHeight();
|
||||
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLPanel* panelp = (*panel_it)->mPanel;
|
||||
|
||||
S32 cur_width = panelp->getRect().getWidth();
|
||||
S32 cur_height = panelp->getRect().getHeight();
|
||||
S32 new_width = llmax((*panel_it)->mMinWidth, cur_width);
|
||||
S32 new_height = llmax((*panel_it)->mMinHeight, cur_height);
|
||||
|
||||
S32 delta_size = 0;
|
||||
|
||||
// if panel can automatically resize (not animating, and resize flag set)...
|
||||
if ((*panel_it)->getCollapseFactor() == 1.f
|
||||
&& (force_resize || (*panel_it)->mAutoResize)
|
||||
&& !(*panel_it)->mResizeBar->hasMouseCapture())
|
||||
{
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
// if we're shrinking
|
||||
if (pixels_to_distribute < 0)
|
||||
{
|
||||
// shrink proportionally to amount over minimum
|
||||
// so we can do this in one pass
|
||||
delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_width - (*panel_it)->mMinWidth) / (F32)shrink_headroom_available)) : 0;
|
||||
shrink_headroom_available -= (cur_width - (*panel_it)->mMinWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
// grow all elements equally
|
||||
delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
|
||||
num_resizable_panels--;
|
||||
}
|
||||
pixels_to_distribute -= delta_size;
|
||||
new_width = llmax((*panel_it)->mMinWidth, cur_width + delta_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_width = getDefaultWidth(new_width);
|
||||
}
|
||||
|
||||
if (mOrientation == VERTICAL)
|
||||
{
|
||||
if (pixels_to_distribute < 0)
|
||||
{
|
||||
// shrink proportionally to amount over minimum
|
||||
// so we can do this in one pass
|
||||
delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - (*panel_it)->mMinHeight) / (F32)shrink_headroom_available)) : 0;
|
||||
shrink_headroom_available -= (cur_height - (*panel_it)->mMinHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
|
||||
num_resizable_panels--;
|
||||
}
|
||||
pixels_to_distribute -= delta_size;
|
||||
new_height = llmax((*panel_it)->mMinHeight, cur_height + delta_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_height = getDefaultHeight(new_height);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
new_height = getDefaultHeight(new_height);
|
||||
}
|
||||
else // VERTICAL
|
||||
{
|
||||
new_width = getDefaultWidth(new_width);
|
||||
}
|
||||
}
|
||||
|
||||
// adjust running headroom count based on new sizes
|
||||
shrink_headroom_total += delta_size;
|
||||
|
||||
panelp->reshape(new_width, new_height);
|
||||
panelp->setOrigin(cur_x, cur_y - new_height);
|
||||
|
||||
LLRect panel_rect = panelp->getRect();
|
||||
LLRect resize_bar_rect = panel_rect;
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
resize_bar_rect.mLeft = panel_rect.mRight - RESIZE_BAR_OVERLAP;
|
||||
resize_bar_rect.mRight = panel_rect.mRight + mPanelSpacing + RESIZE_BAR_OVERLAP;
|
||||
}
|
||||
else
|
||||
{
|
||||
resize_bar_rect.mTop = panel_rect.mBottom + RESIZE_BAR_OVERLAP;
|
||||
resize_bar_rect.mBottom = panel_rect.mBottom - mPanelSpacing - RESIZE_BAR_OVERLAP;
|
||||
}
|
||||
(*panel_it)->mResizeBar->setRect(resize_bar_rect);
|
||||
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
cur_x += llround(new_width * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
cur_y -= llround(new_height * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
// update resize bars with new limits
|
||||
LLResizeBar* last_resize_bar = NULL;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLPanel* panelp = (*panel_it)->mPanel;
|
||||
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
(*panel_it)->mResizeBar->setResizeLimits(
|
||||
(*panel_it)->mMinWidth,
|
||||
(*panel_it)->mMinWidth + shrink_headroom_total);
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
(*panel_it)->mResizeBar->setResizeLimits(
|
||||
(*panel_it)->mMinHeight,
|
||||
(*panel_it)->mMinHeight + shrink_headroom_total);
|
||||
}
|
||||
|
||||
// toggle resize bars based on panel visibility, resizability, etc
|
||||
BOOL resize_bar_enabled = panelp->getVisible() && (*panel_it)->mUserResize;
|
||||
(*panel_it)->mResizeBar->setVisible(resize_bar_enabled);
|
||||
|
||||
if (resize_bar_enabled)
|
||||
{
|
||||
last_resize_bar = (*panel_it)->mResizeBar;
|
||||
}
|
||||
}
|
||||
|
||||
// hide last resize bar as there is nothing past it
|
||||
// resize bars need to be in between two resizable panels
|
||||
if (last_resize_bar)
|
||||
{
|
||||
last_resize_bar->setVisible(FALSE);
|
||||
}
|
||||
|
||||
// not enough room to fit existing contents
|
||||
if (force_resize == FALSE
|
||||
// layout did not complete by reaching target position
|
||||
&& ((mOrientation == VERTICAL && cur_y != -mPanelSpacing)
|
||||
|| (mOrientation == HORIZONTAL && cur_x != getRect().getWidth() + mPanelSpacing)))
|
||||
{
|
||||
// do another layout pass with all stacked elements contributing
|
||||
// even those that don't usually resize
|
||||
llassert_always(force_resize == FALSE);
|
||||
updateLayout(TRUE);
|
||||
}
|
||||
} // end LLLayoutStack::updateLayout
|
||||
|
||||
|
||||
LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
|
||||
{
|
||||
e_panel_list_t::const_iterator panel_it;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
if ((*panel_it)->mPanel == panelp)
|
||||
{
|
||||
return *panel_it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LLLayoutStack::calcMinExtents()
|
||||
{
|
||||
mMinWidth = 0;
|
||||
mMinHeight = 0;
|
||||
|
||||
e_panel_list_t::iterator panel_it;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
mMinHeight = llmax( mMinHeight,
|
||||
(*panel_it)->mMinHeight);
|
||||
mMinWidth += (*panel_it)->mMinWidth;
|
||||
if (panel_it != mPanels.begin())
|
||||
{
|
||||
mMinWidth += mPanelSpacing;
|
||||
}
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
mMinWidth = llmax( mMinWidth,
|
||||
(*panel_it)->mMinWidth);
|
||||
mMinHeight += (*panel_it)->mMinHeight;
|
||||
if (panel_it != mPanels.begin())
|
||||
{
|
||||
mMinHeight += mPanelSpacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
113
indra/llui/lllayoutstack.h
Normal file
113
indra/llui/lllayoutstack.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* @file lllayoutstack.h
|
||||
* @author Richard Nelson
|
||||
* @brief LLLayout class - dynamic stacking of UI elements
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Reshasearch, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLLAYOUTSTACK_H
|
||||
#define LL_LLLAYOUTSTACK_H
|
||||
|
||||
#include "llpanel.h"
|
||||
|
||||
|
||||
class LLLayoutPanel;
|
||||
|
||||
|
||||
class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack>
|
||||
{
|
||||
public:
|
||||
typedef enum e_layout_orientation
|
||||
{
|
||||
HORIZONTAL,
|
||||
VERTICAL
|
||||
} eLayoutOrientation;
|
||||
|
||||
LLLayoutStack(eLayoutOrientation orientation);
|
||||
virtual ~LLLayoutStack();
|
||||
|
||||
/*virtual*/ void draw();
|
||||
/*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const;
|
||||
/*virtual*/ void removeChild(LLView* ctrl);
|
||||
|
||||
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
|
||||
|
||||
S32 getMinWidth() const { return mMinWidth; }
|
||||
S32 getMinHeight() const { return mMinHeight; }
|
||||
|
||||
typedef enum e_animate
|
||||
{
|
||||
NO_ANIMATE,
|
||||
ANIMATE
|
||||
} EAnimate;
|
||||
|
||||
void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, EAnimate animate = NO_ANIMATE, S32 index = S32_MAX);
|
||||
void removePanel(LLPanel* panel);
|
||||
void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE);
|
||||
S32 getNumPanels() { return mPanels.size(); }
|
||||
|
||||
void updateLayout(BOOL force_resize = FALSE);
|
||||
|
||||
S32 getPanelSpacing() const { return mPanelSpacing; }
|
||||
private:
|
||||
|
||||
void calcMinExtents();
|
||||
S32 getDefaultHeight(S32 cur_height);
|
||||
S32 getDefaultWidth(S32 cur_width);
|
||||
|
||||
const eLayoutOrientation mOrientation;
|
||||
|
||||
typedef std::vector<LLLayoutPanel*> e_panel_list_t;
|
||||
e_panel_list_t mPanels;
|
||||
LLLayoutPanel* findEmbeddedPanel(LLPanel* panelp) const;
|
||||
|
||||
S32 mMinWidth;
|
||||
S32 mMinHeight;
|
||||
S32 mPanelSpacing;
|
||||
}; // end class LLLayoutStack
|
||||
|
||||
class LLLayoutPanel
|
||||
{
|
||||
friend class LLLayoutStack;
|
||||
friend class LLUICtrlFactory;
|
||||
friend struct DeletePointer;
|
||||
LLLayoutPanel(LLPanel* panelp, LLLayoutStack::eLayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize);
|
||||
|
||||
~LLLayoutPanel();
|
||||
|
||||
F32 getCollapseFactor();
|
||||
LLPanel* mPanel;
|
||||
S32 mMinWidth;
|
||||
S32 mMinHeight;
|
||||
bool mAutoResize;
|
||||
bool mUserResize;
|
||||
bool mCollapsed;
|
||||
|
||||
|
||||
F32 mVisibleAmt;
|
||||
F32 mCollapseAmt;
|
||||
LLLayoutStack::eLayoutOrientation mOrientation;
|
||||
class LLResizeBar* mResizeBar;
|
||||
};
|
||||
|
||||
#endif //LL_LLLAYOUTSTACK_H
|
||||
@@ -1562,4 +1562,3 @@ std::ostream& operator<<(std::ostream& s, const LLNotification& notification)
|
||||
s << notification.summarize();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
#include "llinstancetracker.h"
|
||||
|
||||
// and we need this to manage the notification callbacks
|
||||
#include "llavatarname.h"
|
||||
#include "llevents.h"
|
||||
#include "llfunctorregistry.h"
|
||||
#include "llui.h"
|
||||
@@ -791,7 +792,5 @@ private:
|
||||
|
||||
LLNotificationMap mUniqueNotifications;
|
||||
};
|
||||
|
||||
|
||||
#endif//LL_LLNOTIFICATIONS_H
|
||||
|
||||
|
||||
@@ -62,9 +62,6 @@
|
||||
#include "llresizebar.h"
|
||||
#include "llcriticaldamp.h"
|
||||
|
||||
const S32 RESIZE_BAR_OVERLAP = 1;
|
||||
const S32 RESIZE_BAR_HEIGHT = 3;
|
||||
|
||||
static LLRegisterWidget<LLPanel> r1("panel");
|
||||
|
||||
void LLPanel::init()
|
||||
@@ -84,7 +81,9 @@ void LLPanel::init()
|
||||
}
|
||||
|
||||
LLPanel::LLPanel()
|
||||
: mRectControl()
|
||||
: mRectControl(),
|
||||
mCommitCallbackRegistrar(false),
|
||||
mEnableCallbackRegistrar(false)
|
||||
{
|
||||
init();
|
||||
setName(std::string("panel"));
|
||||
@@ -92,7 +91,9 @@ LLPanel::LLPanel()
|
||||
|
||||
LLPanel::LLPanel(const std::string& name)
|
||||
: LLUICtrl(name),
|
||||
mRectControl()
|
||||
mRectControl(),
|
||||
mCommitCallbackRegistrar(false),
|
||||
mEnableCallbackRegistrar(false)
|
||||
{
|
||||
init();
|
||||
}
|
||||
@@ -100,7 +101,9 @@ LLPanel::LLPanel(const std::string& name)
|
||||
|
||||
LLPanel::LLPanel(const std::string& name, const LLRect& rect, BOOL bordered)
|
||||
: LLUICtrl(name,rect),
|
||||
mRectControl()
|
||||
mRectControl(),
|
||||
mCommitCallbackRegistrar(false),
|
||||
mEnableCallbackRegistrar(false)
|
||||
{
|
||||
init();
|
||||
if (bordered)
|
||||
@@ -112,7 +115,9 @@ LLPanel::LLPanel(const std::string& name, const LLRect& rect, BOOL bordered)
|
||||
|
||||
LLPanel::LLPanel(const std::string& name, const std::string& rect_control, BOOL bordered)
|
||||
: LLUICtrl(name, LLUI::sConfigGroup->getRect(rect_control)),
|
||||
mRectControl( rect_control )
|
||||
mRectControl( rect_control ),
|
||||
mCommitCallbackRegistrar(false),
|
||||
mEnableCallbackRegistrar(false)
|
||||
{
|
||||
init();
|
||||
if (bordered)
|
||||
@@ -459,7 +464,12 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *fac
|
||||
createRect(node, rect, parent, LLRect());
|
||||
// create a new panel without a border, by default
|
||||
panelp = new LLPanel(name, rect, FALSE);
|
||||
// for local registry callbacks; define in constructor, referenced in XUI or postBuild
|
||||
panelp->mCommitCallbackRegistrar.pushScope();
|
||||
panelp->mEnableCallbackRegistrar.pushScope();
|
||||
panelp->initPanelXML(node, parent, factory);
|
||||
panelp->mCommitCallbackRegistrar.popScope();
|
||||
panelp->mEnableCallbackRegistrar.popScope();
|
||||
// preserve panel's width and height, but override the location
|
||||
const LLRect& panelrect = panelp->getRect();
|
||||
S32 w = panelrect.getWidth();
|
||||
@@ -470,7 +480,14 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *fac
|
||||
else
|
||||
{
|
||||
if(!factory->builtPanel(panelp))
|
||||
{
|
||||
// for local registry callbacks; define in constructor, referenced in XUI or postBuild
|
||||
panelp->mCommitCallbackRegistrar.pushScope();
|
||||
panelp->mEnableCallbackRegistrar.pushScope();
|
||||
panelp->initPanelXML(node, parent, factory);
|
||||
panelp->mCommitCallbackRegistrar.popScope();
|
||||
panelp->mEnableCallbackRegistrar.popScope();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLRect new_rect = panelp->getRect();
|
||||
@@ -1026,651 +1043,3 @@ void LLPanel::storeRectControl()
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLLayoutStack
|
||||
//
|
||||
struct LLLayoutStack::LLEmbeddedPanel
|
||||
{
|
||||
LLEmbeddedPanel(LLPanel* panelp, eLayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize) :
|
||||
mPanel(panelp),
|
||||
mMinWidth(min_width),
|
||||
mMinHeight(min_height),
|
||||
mAutoResize(auto_resize),
|
||||
mUserResize(user_resize),
|
||||
mOrientation(orientation),
|
||||
mCollapsed(FALSE),
|
||||
mCollapseAmt(0.f),
|
||||
mVisibleAmt(1.f) // default to fully visible
|
||||
{
|
||||
LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
|
||||
|
||||
S32 min_dim;
|
||||
if (orientation == HORIZONTAL)
|
||||
{
|
||||
min_dim = mMinHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
min_dim = mMinWidth;
|
||||
}
|
||||
LLResizeBar::Params p;
|
||||
p.name = "resizer";
|
||||
p.resizing_view = mPanel;
|
||||
p.min_size = min_dim;
|
||||
p.max_size = S32_MAX;
|
||||
p.side = side;
|
||||
mResizeBar = LLUICtrlFactory::create<LLResizeBar>(p);
|
||||
mResizeBar->setEnableSnapping(FALSE);
|
||||
// panels initialized as hidden should not start out partially visible
|
||||
if (!mPanel->getVisible())
|
||||
{
|
||||
mVisibleAmt = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
~LLEmbeddedPanel()
|
||||
{
|
||||
// probably not necessary, but...
|
||||
delete mResizeBar;
|
||||
mResizeBar = NULL;
|
||||
}
|
||||
|
||||
F32 getCollapseFactor()
|
||||
{
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
F32 collapse_amt =
|
||||
clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinWidth / (F32)llmax(1, mPanel->getRect().getWidth()));
|
||||
return mVisibleAmt * collapse_amt;
|
||||
}
|
||||
else
|
||||
{
|
||||
F32 collapse_amt =
|
||||
clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinHeight / (F32)llmax(1, mPanel->getRect().getHeight())));
|
||||
return mVisibleAmt * collapse_amt;
|
||||
}
|
||||
}
|
||||
|
||||
LLPanel* mPanel;
|
||||
S32 mMinWidth;
|
||||
S32 mMinHeight;
|
||||
BOOL mAutoResize;
|
||||
BOOL mUserResize;
|
||||
BOOL mCollapsed;
|
||||
LLResizeBar* mResizeBar;
|
||||
eLayoutOrientation mOrientation;
|
||||
F32 mVisibleAmt;
|
||||
F32 mCollapseAmt;
|
||||
};
|
||||
|
||||
static LLRegisterWidget<LLLayoutStack> r2("layout_stack");
|
||||
|
||||
LLLayoutStack::LLLayoutStack(eLayoutOrientation orientation) :
|
||||
mOrientation(orientation),
|
||||
mMinWidth(0),
|
||||
mMinHeight(0),
|
||||
mPanelSpacing(RESIZE_BAR_HEIGHT)
|
||||
{
|
||||
}
|
||||
|
||||
LLLayoutStack::~LLLayoutStack()
|
||||
{
|
||||
std::for_each(mPanels.begin(), mPanels.end(), DeletePointer());
|
||||
}
|
||||
|
||||
void LLLayoutStack::draw()
|
||||
{
|
||||
updateLayout();
|
||||
|
||||
e_panel_list_t::iterator panel_it;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
// clip to layout rectangle, not bounding rectangle
|
||||
LLRect clip_rect = (*panel_it)->mPanel->getRect();
|
||||
// scale clipping rectangle by visible amount
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor());
|
||||
}
|
||||
else
|
||||
{
|
||||
clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor());
|
||||
}
|
||||
|
||||
LLPanel* panelp = (*panel_it)->mPanel;
|
||||
|
||||
LLLocalClipRect clip(clip_rect);
|
||||
// only force drawing invisible children if visible amount is non-zero
|
||||
drawChild(panelp, 0, 0, clip_rect.notEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
void LLLayoutStack::removeChild(LLView* ctrl)
|
||||
{
|
||||
LLView::removeChild(ctrl);
|
||||
LLPanel* panel = dynamic_cast<LLPanel*>(ctrl);
|
||||
if(!panel)
|
||||
return;
|
||||
LLEmbeddedPanel* embedded_panelp = findEmbeddedPanel(panel);
|
||||
|
||||
if (embedded_panelp)
|
||||
{
|
||||
mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp));
|
||||
delete embedded_panelp;
|
||||
}
|
||||
|
||||
// need to update resizebars
|
||||
|
||||
calcMinExtents();
|
||||
}
|
||||
|
||||
LLXMLNodePtr LLLayoutStack::getXML(bool save_children) const
|
||||
{
|
||||
LLXMLNodePtr node = LLView::getXML();
|
||||
node->setName(LL_LAYOUT_STACK_TAG);
|
||||
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
node->createChild("orientation", TRUE)->setStringValue("horizontal");
|
||||
}
|
||||
else
|
||||
{
|
||||
node->createChild("orientation", TRUE)->setStringValue("vertical");
|
||||
}
|
||||
|
||||
if (save_children)
|
||||
{
|
||||
LLView::child_list_const_reverse_iter_t rit;
|
||||
for (rit = getChildList()->rbegin(); rit != getChildList()->rend(); ++rit)
|
||||
{
|
||||
LLView* childp = *rit;
|
||||
|
||||
if (childp->getSaveToXML())
|
||||
{
|
||||
LLXMLNodePtr xml_node = childp->getXML();
|
||||
|
||||
if (xml_node->hasName(LL_PANEL_TAG))
|
||||
{
|
||||
xml_node->setName(LL_LAYOUT_PANEL_TAG);
|
||||
}
|
||||
|
||||
node->addChild(xml_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
//static
|
||||
LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
|
||||
{
|
||||
std::string orientation_string("vertical");
|
||||
node->getAttributeString("orientation", orientation_string);
|
||||
|
||||
eLayoutOrientation orientation = VERTICAL;
|
||||
|
||||
if (orientation_string == "horizontal")
|
||||
{
|
||||
orientation = HORIZONTAL;
|
||||
}
|
||||
else if (orientation_string == "vertical")
|
||||
{
|
||||
orientation = VERTICAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "Unknown orientation " << orientation_string << ", using vertical" << llendl;
|
||||
}
|
||||
|
||||
LLLayoutStack* layout_stackp = new LLLayoutStack(orientation);
|
||||
|
||||
node->getAttributeS32("border_size", layout_stackp->mPanelSpacing);
|
||||
// don't allow negative spacing values
|
||||
layout_stackp->mPanelSpacing = llmax(layout_stackp->mPanelSpacing, 0);
|
||||
|
||||
std::string name("stack");
|
||||
node->getAttributeString("name", name);
|
||||
|
||||
layout_stackp->setName(name);
|
||||
layout_stackp->initFromXML(node, parent);
|
||||
|
||||
LLXMLNodePtr child;
|
||||
for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
|
||||
{
|
||||
S32 min_width = 0;
|
||||
S32 min_height = 0;
|
||||
BOOL auto_resize = TRUE;
|
||||
|
||||
child->getAttributeS32("min_width", min_width);
|
||||
child->getAttributeS32("min_height", min_height);
|
||||
child->getAttributeBOOL("auto_resize", auto_resize);
|
||||
|
||||
if (child->hasName("layout_panel"))
|
||||
{
|
||||
BOOL user_resize = TRUE;
|
||||
child->getAttributeBOOL("user_resize", user_resize);
|
||||
LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child, layout_stackp, factory);
|
||||
if (panelp)
|
||||
{
|
||||
panelp->setFollowsNone();
|
||||
layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOL user_resize = FALSE;
|
||||
child->getAttributeBOOL("user_resize", user_resize);
|
||||
|
||||
LLPanel* panelp = new LLPanel(std::string("auto_panel"));
|
||||
LLView* new_child = factory->createWidget(panelp, child);
|
||||
if (new_child)
|
||||
{
|
||||
// put child in new embedded panel
|
||||
layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
|
||||
// resize panel to contain widget and move widget to be contained in panel
|
||||
panelp->setRect(new_child->getRect());
|
||||
new_child->setOrigin(0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
panelp->die();
|
||||
}
|
||||
}
|
||||
}
|
||||
layout_stackp->updateLayout();
|
||||
|
||||
return layout_stackp;
|
||||
}
|
||||
|
||||
S32 LLLayoutStack::getDefaultHeight(S32 cur_height)
|
||||
{
|
||||
// if we are spanning our children (crude upward propagation of size)
|
||||
// then don't enforce our size on our children
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
cur_height = llmax(mMinHeight, getRect().getHeight());
|
||||
}
|
||||
|
||||
return cur_height;
|
||||
}
|
||||
|
||||
S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
|
||||
{
|
||||
// if we are spanning our children (crude upward propagation of size)
|
||||
// then don't enforce our size on our children
|
||||
if (mOrientation == VERTICAL)
|
||||
{
|
||||
cur_width = llmax(mMinWidth, getRect().getWidth());
|
||||
}
|
||||
|
||||
return cur_width;
|
||||
}
|
||||
|
||||
void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, EAnimate animate, S32 index)
|
||||
{
|
||||
// panel starts off invisible (collapsed)
|
||||
if (animate == ANIMATE)
|
||||
{
|
||||
panel->setVisible(FALSE);
|
||||
}
|
||||
LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize, user_resize);
|
||||
|
||||
mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel);
|
||||
|
||||
addChild(panel);
|
||||
addChild(embedded_panel->mResizeBar);
|
||||
|
||||
// bring all resize bars to the front so that they are clickable even over the panels
|
||||
// with a bit of overlap
|
||||
for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
|
||||
sendChildToFront(resize_barp);
|
||||
}
|
||||
|
||||
// start expanding panel animation
|
||||
if (animate == ANIMATE)
|
||||
{
|
||||
panel->setVisible(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void LLLayoutStack::removePanel(LLPanel* panel)
|
||||
{
|
||||
removeChild(panel);
|
||||
}
|
||||
|
||||
void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
|
||||
{
|
||||
LLEmbeddedPanel* panel_container = findEmbeddedPanel(panel);
|
||||
if (!panel_container) return;
|
||||
|
||||
panel_container->mCollapsed = collapsed;
|
||||
}
|
||||
|
||||
void LLLayoutStack::updateLayout(BOOL force_resize)
|
||||
{
|
||||
calcMinExtents();
|
||||
|
||||
// calculate current extents
|
||||
S32 total_width = 0;
|
||||
S32 total_height = 0;
|
||||
|
||||
const F32 ANIM_OPEN_TIME = 0.02f;
|
||||
const F32 ANIM_CLOSE_TIME = 0.03f;
|
||||
|
||||
e_panel_list_t::iterator panel_it;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLPanel* panelp = (*panel_it)->mPanel;
|
||||
if (panelp->getVisible())
|
||||
{
|
||||
(*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME));
|
||||
if ((*panel_it)->mVisibleAmt > 0.99f)
|
||||
{
|
||||
(*panel_it)->mVisibleAmt = 1.f;
|
||||
}
|
||||
}
|
||||
else // not visible
|
||||
{
|
||||
(*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
|
||||
if ((*panel_it)->mVisibleAmt < 0.001f)
|
||||
{
|
||||
(*panel_it)->mVisibleAmt = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
if ((*panel_it)->mCollapsed)
|
||||
{
|
||||
(*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
|
||||
}
|
||||
else
|
||||
{
|
||||
(*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
|
||||
}
|
||||
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
// enforce minimize size constraint by default
|
||||
if (panelp->getRect().getWidth() < (*panel_it)->mMinWidth)
|
||||
{
|
||||
panelp->reshape((*panel_it)->mMinWidth, panelp->getRect().getHeight());
|
||||
}
|
||||
total_width += llround(panelp->getRect().getWidth() * (*panel_it)->getCollapseFactor());
|
||||
// want n-1 panel gaps for n panels
|
||||
if (panel_it != mPanels.begin())
|
||||
{
|
||||
total_width += mPanelSpacing;
|
||||
}
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
// enforce minimize size constraint by default
|
||||
if (panelp->getRect().getHeight() < (*panel_it)->mMinHeight)
|
||||
{
|
||||
panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinHeight);
|
||||
}
|
||||
total_height += llround(panelp->getRect().getHeight() * (*panel_it)->getCollapseFactor());
|
||||
if (panel_it != mPanels.begin())
|
||||
{
|
||||
total_height += mPanelSpacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
S32 num_resizable_panels = 0;
|
||||
S32 shrink_headroom_available = 0;
|
||||
S32 shrink_headroom_total = 0;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
// panels that are not fully visible do not count towards shrink headroom
|
||||
if ((*panel_it)->getCollapseFactor() < 1.f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if currently resizing a panel or the panel is flagged as not automatically resizing
|
||||
// only track total available headroom, but don't use it for automatic resize logic
|
||||
if ((*panel_it)->mResizeBar->hasMouseCapture()
|
||||
|| (!(*panel_it)->mAutoResize
|
||||
&& !force_resize))
|
||||
{
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
num_resizable_panels++;
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
shrink_headroom_available += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
|
||||
shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
shrink_headroom_available += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
|
||||
shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculate how many pixels need to be distributed among layout panels
|
||||
// positive means panels need to grow, negative means shrink
|
||||
S32 pixels_to_distribute;
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
pixels_to_distribute = getRect().getWidth() - total_width;
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
pixels_to_distribute = getRect().getHeight() - total_height;
|
||||
}
|
||||
|
||||
// now we distribute the pixels...
|
||||
S32 cur_x = 0;
|
||||
S32 cur_y = getRect().getHeight();
|
||||
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLPanel* panelp = (*panel_it)->mPanel;
|
||||
|
||||
S32 cur_width = panelp->getRect().getWidth();
|
||||
S32 cur_height = panelp->getRect().getHeight();
|
||||
S32 new_width = llmax((*panel_it)->mMinWidth, cur_width);
|
||||
S32 new_height = llmax((*panel_it)->mMinHeight, cur_height);
|
||||
|
||||
S32 delta_size = 0;
|
||||
|
||||
// if panel can automatically resize (not animating, and resize flag set)...
|
||||
if ((*panel_it)->getCollapseFactor() == 1.f
|
||||
&& (force_resize || (*panel_it)->mAutoResize)
|
||||
&& !(*panel_it)->mResizeBar->hasMouseCapture())
|
||||
{
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
// if we're shrinking
|
||||
if (pixels_to_distribute < 0)
|
||||
{
|
||||
// shrink proportionally to amount over minimum
|
||||
// so we can do this in one pass
|
||||
delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_width - (*panel_it)->mMinWidth) / (F32)shrink_headroom_available)) : 0;
|
||||
shrink_headroom_available -= (cur_width - (*panel_it)->mMinWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
// grow all elements equally
|
||||
delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
|
||||
num_resizable_panels--;
|
||||
}
|
||||
pixels_to_distribute -= delta_size;
|
||||
new_width = llmax((*panel_it)->mMinWidth, cur_width + delta_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_width = getDefaultWidth(new_width);
|
||||
}
|
||||
|
||||
if (mOrientation == VERTICAL)
|
||||
{
|
||||
if (pixels_to_distribute < 0)
|
||||
{
|
||||
// shrink proportionally to amount over minimum
|
||||
// so we can do this in one pass
|
||||
delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - (*panel_it)->mMinHeight) / (F32)shrink_headroom_available)) : 0;
|
||||
shrink_headroom_available -= (cur_height - (*panel_it)->mMinHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
|
||||
num_resizable_panels--;
|
||||
}
|
||||
pixels_to_distribute -= delta_size;
|
||||
new_height = llmax((*panel_it)->mMinHeight, cur_height + delta_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_height = getDefaultHeight(new_height);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
new_height = getDefaultHeight(new_height);
|
||||
}
|
||||
else // VERTICAL
|
||||
{
|
||||
new_width = getDefaultWidth(new_width);
|
||||
}
|
||||
}
|
||||
|
||||
// adjust running headroom count based on new sizes
|
||||
shrink_headroom_total += delta_size;
|
||||
|
||||
panelp->reshape(new_width, new_height);
|
||||
panelp->setOrigin(cur_x, cur_y - new_height);
|
||||
|
||||
LLRect panel_rect = panelp->getRect();
|
||||
LLRect resize_bar_rect = panel_rect;
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
resize_bar_rect.mLeft = panel_rect.mRight - RESIZE_BAR_OVERLAP;
|
||||
resize_bar_rect.mRight = panel_rect.mRight + mPanelSpacing + RESIZE_BAR_OVERLAP;
|
||||
}
|
||||
else
|
||||
{
|
||||
resize_bar_rect.mTop = panel_rect.mBottom + RESIZE_BAR_OVERLAP;
|
||||
resize_bar_rect.mBottom = panel_rect.mBottom - mPanelSpacing - RESIZE_BAR_OVERLAP;
|
||||
}
|
||||
(*panel_it)->mResizeBar->setRect(resize_bar_rect);
|
||||
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
cur_x += llround(new_width * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
cur_y -= llround(new_height * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
// update resize bars with new limits
|
||||
LLResizeBar* last_resize_bar = NULL;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLPanel* panelp = (*panel_it)->mPanel;
|
||||
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
(*panel_it)->mResizeBar->setResizeLimits(
|
||||
(*panel_it)->mMinWidth,
|
||||
(*panel_it)->mMinWidth + shrink_headroom_total);
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
(*panel_it)->mResizeBar->setResizeLimits(
|
||||
(*panel_it)->mMinHeight,
|
||||
(*panel_it)->mMinHeight + shrink_headroom_total);
|
||||
}
|
||||
|
||||
// toggle resize bars based on panel visibility, resizability, etc
|
||||
BOOL resize_bar_enabled = panelp->getVisible() && (*panel_it)->mUserResize;
|
||||
(*panel_it)->mResizeBar->setVisible(resize_bar_enabled);
|
||||
|
||||
if (resize_bar_enabled)
|
||||
{
|
||||
last_resize_bar = (*panel_it)->mResizeBar;
|
||||
}
|
||||
}
|
||||
|
||||
// hide last resize bar as there is nothing past it
|
||||
// resize bars need to be in between two resizable panels
|
||||
if (last_resize_bar)
|
||||
{
|
||||
last_resize_bar->setVisible(FALSE);
|
||||
}
|
||||
|
||||
// not enough room to fit existing contents
|
||||
if (force_resize == FALSE
|
||||
// layout did not complete by reaching target position
|
||||
&& ((mOrientation == VERTICAL && cur_y != -mPanelSpacing)
|
||||
|| (mOrientation == HORIZONTAL && cur_x != getRect().getWidth() + mPanelSpacing)))
|
||||
{
|
||||
// do another layout pass with all stacked elements contributing
|
||||
// even those that don't usually resize
|
||||
llassert_always(force_resize == FALSE);
|
||||
updateLayout(TRUE);
|
||||
}
|
||||
} // end LLLayoutStack::updateLayout
|
||||
|
||||
|
||||
LLLayoutStack::LLEmbeddedPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
|
||||
{
|
||||
e_panel_list_t::const_iterator panel_it;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
if ((*panel_it)->mPanel == panelp)
|
||||
{
|
||||
return *panel_it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LLLayoutStack::calcMinExtents()
|
||||
{
|
||||
mMinWidth = 0;
|
||||
mMinHeight = 0;
|
||||
|
||||
e_panel_list_t::iterator panel_it;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
mMinHeight = llmax( mMinHeight,
|
||||
(*panel_it)->mMinHeight);
|
||||
mMinWidth += (*panel_it)->mMinWidth;
|
||||
if (panel_it != mPanels.begin())
|
||||
{
|
||||
mMinWidth += mPanelSpacing;
|
||||
}
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
mMinWidth = llmax( mMinWidth,
|
||||
(*panel_it)->mMinWidth);
|
||||
mMinHeight += (*panel_it)->mMinHeight;
|
||||
if (panel_it != mPanels.begin())
|
||||
{
|
||||
mMinHeight += mPanelSpacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +140,8 @@ public:
|
||||
|
||||
const LLCallbackMap::map_t& getFactoryMap() const { return mFactoryMap; }
|
||||
|
||||
CommitCallbackRegistry::ScopedRegistrar& getCommitCallbackRegistrar() { return mCommitCallbackRegistrar; }
|
||||
EnableCallbackRegistry::ScopedRegistrar& getEnableCallbackRegistrar() { return mEnableCallbackRegistrar; }
|
||||
BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
|
||||
void initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory);
|
||||
void setPanelParameters(LLXMLNodePtr node, LLView *parentp);
|
||||
@@ -226,6 +228,8 @@ protected:
|
||||
// Override to set not found list
|
||||
LLButton* getDefaultButton() { return mDefaultBtn; }
|
||||
LLCallbackMap::map_t mFactoryMap;
|
||||
CommitCallbackRegistry::ScopedRegistrar mCommitCallbackRegistrar;
|
||||
EnableCallbackRegistry::ScopedRegistrar mEnableCallbackRegistrar;
|
||||
|
||||
commit_signal_t* mVisibleSignal; // Called when visibility changes, passes new visibility as LLSD()
|
||||
private:
|
||||
@@ -254,56 +258,4 @@ private:
|
||||
|
||||
}; // end class LLPanel
|
||||
|
||||
|
||||
class LLLayoutStack : public LLView
|
||||
{
|
||||
public:
|
||||
typedef enum e_layout_orientation
|
||||
{
|
||||
HORIZONTAL,
|
||||
VERTICAL
|
||||
} eLayoutOrientation;
|
||||
|
||||
LLLayoutStack(eLayoutOrientation orientation);
|
||||
virtual ~LLLayoutStack();
|
||||
|
||||
/*virtual*/ void draw();
|
||||
/*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const;
|
||||
/*virtual*/ void removeChild(LLView* ctrl);
|
||||
|
||||
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
|
||||
|
||||
S32 getMinWidth() const { return mMinWidth; }
|
||||
S32 getMinHeight() const { return mMinHeight; }
|
||||
|
||||
typedef enum e_animate
|
||||
{
|
||||
NO_ANIMATE,
|
||||
ANIMATE
|
||||
} EAnimate;
|
||||
|
||||
void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, EAnimate animate = NO_ANIMATE, S32 index = S32_MAX);
|
||||
void removePanel(LLPanel* panel);
|
||||
void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE);
|
||||
S32 getNumPanels() { return mPanels.size(); }
|
||||
|
||||
private:
|
||||
struct LLEmbeddedPanel;
|
||||
|
||||
void updateLayout(BOOL force_resize = FALSE);
|
||||
void calcMinExtents();
|
||||
S32 getDefaultHeight(S32 cur_height);
|
||||
S32 getDefaultWidth(S32 cur_width);
|
||||
|
||||
const eLayoutOrientation mOrientation;
|
||||
|
||||
typedef std::vector<LLEmbeddedPanel*> e_panel_list_t;
|
||||
e_panel_list_t mPanels;
|
||||
LLEmbeddedPanel* findEmbeddedPanel(LLPanel* panelp) const;
|
||||
|
||||
S32 mMinWidth;
|
||||
S32 mMinHeight;
|
||||
S32 mPanelSpacing;
|
||||
}; // end class LLLayoutStack
|
||||
|
||||
#endif
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "llui.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "lluiimage.h"
|
||||
#include "llurlaction.h"
|
||||
#include "llrect.h"
|
||||
#include "llfocusmgr.h"
|
||||
#include "lltimer.h"
|
||||
@@ -96,10 +97,6 @@ const S32 PREEDIT_STANDOUT_THICKNESS = 2;
|
||||
|
||||
|
||||
LLColor4 LLTextEditor::mLinkColor = LLColor4::blue;
|
||||
void (* LLTextEditor::mURLcallback)(const std::string&) = NULL;
|
||||
bool (* LLTextEditor::mSecondlifeURLcallback)(const std::string&) = NULL;
|
||||
bool (* LLTextEditor::mSecondlifeURLcallbackRightClick)(const std::string&) = NULL;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -4350,11 +4347,15 @@ void LLTextEditor::loadKeywords(const std::string& filename,
|
||||
std::string name = utf8str_trim(funcs[i]);
|
||||
mKeywords.addToken(LLKeywordToken::WORD, name, color, tooltips[i] );
|
||||
}
|
||||
segment_list_t segment_list;
|
||||
mKeywords.findSegments(&segment_list, getWText(), mDefaultColor);
|
||||
|
||||
mKeywords.findSegments( &mSegments, mWText, mDefaultColor );
|
||||
|
||||
llassert( mSegments.front()->getStart() == 0 );
|
||||
llassert( mSegments.back()->getEnd() == getLength() );
|
||||
mSegments.clear();
|
||||
segment_list_t::iterator insert_it = mSegments.begin();
|
||||
for (segment_list_t::iterator list_it = segment_list.begin(); list_it != segment_list.end(); ++list_it)
|
||||
{
|
||||
insert_it = mSegments.insert(insert_it, *list_it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4493,11 +4494,7 @@ BOOL LLTextEditor::handleMouseUpOverSegment(S32 x, S32 y, MASK mask)
|
||||
// and launch it if we did.
|
||||
if (mParseHTML && mHTML.length() > 0)
|
||||
{
|
||||
//Special handling for slurls
|
||||
if ( (mSecondlifeURLcallback!=NULL) && !(*mSecondlifeURLcallback)(mHTML) )
|
||||
{
|
||||
if (mURLcallback!=NULL) (*mURLcallback)(mHTML);
|
||||
}
|
||||
LLUrlAction::clickAction(mHTML);
|
||||
mHTML.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,10 +258,6 @@ public:
|
||||
|
||||
// Callbacks
|
||||
static void setLinkColor(LLColor4 color) { mLinkColor = color; }
|
||||
static void setURLCallbacks(void (*callback1) (const std::string& url),
|
||||
bool (*callback2) (const std::string& url),
|
||||
bool (*callback3) (const std::string& url) )
|
||||
{ mURLcallback = callback1; mSecondlifeURLcallback = callback2; mSecondlifeURLcallbackRightClick = callback3;}
|
||||
|
||||
void setOnScrollEndCallback(void (*callback)(void*), void* userdata);
|
||||
|
||||
@@ -509,9 +505,6 @@ private:
|
||||
//
|
||||
LLKeywords mKeywords;
|
||||
static LLColor4 mLinkColor;
|
||||
static void (*mURLcallback) (const std::string& url);
|
||||
static bool (*mSecondlifeURLcallback) (const std::string& url);
|
||||
static bool (*mSecondlifeURLcallbackRightClick) (const std::string& url);
|
||||
|
||||
// Concrete LLTextCmd sub-classes used by the LLTextEditor base class
|
||||
class LLTextCmdInsert;
|
||||
|
||||
@@ -161,19 +161,15 @@ void LLUI::setMousePositionScreen(S32 x, S32 y)
|
||||
screen_x = llround((F32)x * getScaleFactor().mV[VX]);
|
||||
screen_y = llround((F32)y * getScaleFactor().mV[VY]);
|
||||
|
||||
LLCoordWindow window_point;
|
||||
LLView::getWindow()->convertCoords(LLCoordGL(screen_x, screen_y), &window_point);
|
||||
|
||||
LLView::getWindow()->setCursorPosition(window_point);
|
||||
LLView::getWindow()->setCursorPosition(LLCoordGL(screen_x, screen_y).convert());
|
||||
}
|
||||
|
||||
//static
|
||||
void LLUI::getMousePositionScreen(S32 *x, S32 *y)
|
||||
{
|
||||
LLCoordWindow cursor_pos_window;
|
||||
LLView::getWindow()->getCursorPosition(&cursor_pos_window);
|
||||
LLCoordGL cursor_pos_gl;
|
||||
LLView::getWindow()->convertCoords(cursor_pos_window, &cursor_pos_gl);
|
||||
getWindow()->getCursorPosition(&cursor_pos_window);
|
||||
LLCoordGL cursor_pos_gl(cursor_pos_window.convert());
|
||||
*x = llround((F32)cursor_pos_gl.mX / getScaleFactor().mV[VX]);
|
||||
*y = llround((F32)cursor_pos_gl.mY / getScaleFactor().mV[VX]);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "llcontrol.h"
|
||||
#include "llcoord.h"
|
||||
#include "v2math.h"
|
||||
#include "llregistry.h"
|
||||
#include "llrender2dutils.h"
|
||||
#include "llpointer.h"
|
||||
#include "lluiimage.h"
|
||||
@@ -102,6 +103,7 @@ public:
|
||||
static void glRectToScreen(const LLRect& gl, LLRect *screen);
|
||||
// Returns the control group containing the control name, or the default group
|
||||
static LLControlGroup& getControlControlGroup (const std::string& controlname);
|
||||
static LLWindow* getWindow() { return sWindow; }
|
||||
static void setHtmlHelp(LLHtmlHelp* html_help);
|
||||
|
||||
//
|
||||
|
||||
@@ -467,6 +467,37 @@ void LLUICtrl::initFromXML(LLXMLNodePtr node, LLView* parent)
|
||||
|
||||
setTabStop(has_tab_stop);
|
||||
|
||||
std::string str = node->getName()->mString;
|
||||
std::string attrib_str;
|
||||
LLXMLNodePtr child_node;
|
||||
if(node->getChild((str+".commit_callback").c_str(),child_node,false))
|
||||
{
|
||||
if(child_node->getAttributeString("function",attrib_str))
|
||||
{
|
||||
commit_callback_t* func = (CommitCallbackRegistry::getValue(attrib_str));
|
||||
if (func)
|
||||
{
|
||||
if(child_node->getAttributeString("parameter",attrib_str))
|
||||
setCommitCallback(boost::bind((*func), this, LLSD(attrib_str)));
|
||||
else
|
||||
setCommitCallback(commit_signal_t::slot_type(*func));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(node->getChild((str+".validate_callback").c_str(),child_node,false))
|
||||
{
|
||||
if(child_node->getAttributeString("function",attrib_str))
|
||||
{
|
||||
enable_callback_t* func = (EnableCallbackRegistry::getValue(attrib_str));
|
||||
if (func)
|
||||
{
|
||||
if(child_node->getAttributeString("parameter",attrib_str))
|
||||
setValidateCallback(boost::bind((*func), this, LLSD(attrib_str)));
|
||||
else
|
||||
setValidateCallback(enable_signal_t::slot_type(*func));
|
||||
}
|
||||
}
|
||||
}
|
||||
LLView::initFromXML(node, parent);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
#include "llinitparam.h"
|
||||
#include "llviewmodel.h" // *TODO move dependency to .cpp file
|
||||
|
||||
class LLUICtrl
|
||||
@@ -48,6 +49,7 @@ class LLUICtrl
|
||||
public:
|
||||
typedef boost::function<void (LLUICtrl* ctrl, const LLSD& param)> commit_callback_t;
|
||||
typedef boost::signals2::signal<void (LLUICtrl* ctrl, const LLSD& param)> commit_signal_t;
|
||||
typedef boost::function<bool (LLUICtrl* ctrl, const LLSD& param)> enable_callback_t;
|
||||
typedef boost::signals2::signal<bool (LLUICtrl* ctrl, const LLSD& param), boost_boolean_combiner> enable_signal_t;
|
||||
|
||||
typedef void (*LLUICtrlCallback)(LLUICtrl* ctrl, void* userdata);
|
||||
@@ -149,6 +151,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename DERIVED> class CallbackRegistry : public LLRegistrySingleton<std::string, F, DERIVED >
|
||||
{};
|
||||
|
||||
class CommitCallbackRegistry : public CallbackRegistry<commit_callback_t, CommitCallbackRegistry>{};
|
||||
// the enable callback registry is also used for visiblity callbacks
|
||||
class EnableCallbackRegistry : public CallbackRegistry<enable_callback_t, EnableCallbackRegistry>{};
|
||||
|
||||
protected:
|
||||
|
||||
commit_signal_t* mCommitSignal;
|
||||
|
||||
@@ -285,8 +285,12 @@ void LLUICtrlFactory::buildFloaterInternal(LLFloater *floaterp, LLXMLNodePtr &ro
|
||||
mFactoryStack.push_front(factory_map);
|
||||
}
|
||||
|
||||
// for local registry callbacks; define in constructor, referenced in XUI or postBuild
|
||||
floaterp->getCommitCallbackRegistrar().pushScope();
|
||||
floaterp->getEnableCallbackRegistrar().pushScope();
|
||||
floaterp->initFloaterXML(root, NULL, this, open); /* Flawfinder: ignore */
|
||||
|
||||
floaterp->getCommitCallbackRegistrar().popScope();
|
||||
floaterp->getEnableCallbackRegistrar().popScope();
|
||||
if (LLUI::sShowXUINames)
|
||||
{
|
||||
floaterp->setToolTip(filename);
|
||||
@@ -381,8 +385,13 @@ BOOL LLUICtrlFactory::buildPanelInternal(LLPanel* panelp, LLXMLNodePtr &root, co
|
||||
mFactoryStack.push_front(factory_map);
|
||||
}
|
||||
|
||||
// for local registry callbacks; define in constructor, referenced in XUI or postBuild
|
||||
panelp->getCommitCallbackRegistrar().pushScope();
|
||||
panelp->getEnableCallbackRegistrar().pushScope();
|
||||
didPost = panelp->initPanelXML(root, NULL, this);
|
||||
|
||||
panelp->getCommitCallbackRegistrar().popScope();
|
||||
panelp->getEnableCallbackRegistrar().popScope();
|
||||
|
||||
if (LLUI::sShowXUINames)
|
||||
{
|
||||
panelp->setToolTip(filename);
|
||||
|
||||
159
indra/llui/llurlaction.cpp
Normal file
159
indra/llui/llurlaction.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* @file llurlaction.cpp
|
||||
* @author Martin Reddy
|
||||
* @brief A set of actions that can performed on Urls
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llurlaction.h"
|
||||
#include "llview.h"
|
||||
#include "llwindow.h"
|
||||
#include "llurlregistry.h"
|
||||
|
||||
// global state for the callback functions
|
||||
LLUrlAction::url_callback_t LLUrlAction::sOpenURLCallback;
|
||||
LLUrlAction::url_callback_t LLUrlAction::sOpenURLInternalCallback;
|
||||
LLUrlAction::url_callback_t LLUrlAction::sOpenURLExternalCallback;
|
||||
LLUrlAction::execute_url_callback_t LLUrlAction::sExecuteSLURLCallback;
|
||||
|
||||
|
||||
void LLUrlAction::setOpenURLCallback(url_callback_t cb)
|
||||
{
|
||||
sOpenURLCallback = cb;
|
||||
}
|
||||
|
||||
void LLUrlAction::setOpenURLInternalCallback(url_callback_t cb)
|
||||
{
|
||||
sOpenURLInternalCallback = cb;
|
||||
}
|
||||
|
||||
void LLUrlAction::setOpenURLExternalCallback(url_callback_t cb)
|
||||
{
|
||||
sOpenURLExternalCallback = cb;
|
||||
}
|
||||
|
||||
void LLUrlAction::setExecuteSLURLCallback(execute_url_callback_t cb)
|
||||
{
|
||||
sExecuteSLURLCallback = cb;
|
||||
}
|
||||
|
||||
void LLUrlAction::openURL(std::string url)
|
||||
{
|
||||
if (sOpenURLCallback)
|
||||
{
|
||||
sOpenURLCallback(url);
|
||||
}
|
||||
}
|
||||
|
||||
void LLUrlAction::openURLInternal(std::string url)
|
||||
{
|
||||
if (sOpenURLInternalCallback)
|
||||
{
|
||||
sOpenURLInternalCallback(url);
|
||||
}
|
||||
}
|
||||
|
||||
void LLUrlAction::openURLExternal(std::string url)
|
||||
{
|
||||
if (sOpenURLExternalCallback)
|
||||
{
|
||||
sOpenURLExternalCallback(url);
|
||||
}
|
||||
}
|
||||
|
||||
void LLUrlAction::executeSLURL(std::string url)
|
||||
{
|
||||
if (sExecuteSLURLCallback)
|
||||
{
|
||||
sExecuteSLURLCallback(url);
|
||||
}
|
||||
}
|
||||
|
||||
void LLUrlAction::clickAction(std::string url)
|
||||
{
|
||||
// Try to handle as SLURL first, then http Url
|
||||
if ( (sExecuteSLURLCallback) && !sExecuteSLURLCallback(url) )
|
||||
{
|
||||
if (sOpenURLCallback)
|
||||
{
|
||||
sOpenURLCallback(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLUrlAction::teleportToLocation(std::string url)
|
||||
{
|
||||
LLUrlMatch match;
|
||||
if (LLUrlRegistry::instance().findUrl(url, match))
|
||||
{
|
||||
if (! match.getLocation().empty())
|
||||
{
|
||||
executeSLURL("secondlife:///app/teleport/" + match.getLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLUrlAction::showLocationOnMap(std::string url)
|
||||
{
|
||||
LLUrlMatch match;
|
||||
if (LLUrlRegistry::instance().findUrl(url, match))
|
||||
{
|
||||
if (! match.getLocation().empty())
|
||||
{
|
||||
executeSLURL("secondlife:///app/worldmap/" + match.getLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLUrlAction::copyURLToClipboard(std::string url)
|
||||
{
|
||||
LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(url));
|
||||
}
|
||||
|
||||
void LLUrlAction::copyLabelToClipboard(std::string url)
|
||||
{
|
||||
LLUrlMatch match;
|
||||
if (LLUrlRegistry::instance().findUrl(url, match))
|
||||
{
|
||||
LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(match.getLabel()));
|
||||
}
|
||||
}
|
||||
|
||||
void LLUrlAction::showProfile(std::string url)
|
||||
{
|
||||
// Get id from 'secondlife:///app/{cmd}/{id}/{action}'
|
||||
// and show its profile
|
||||
LLURI uri(url);
|
||||
LLSD path_array = uri.pathArray();
|
||||
if (path_array.size() == 4)
|
||||
{
|
||||
std::string id_str = path_array.get(2).asString();
|
||||
if (LLUUID::validate(id_str))
|
||||
{
|
||||
std::string cmd_str = path_array.get(1).asString();
|
||||
executeSLURL("secondlife:///app/" + cmd_str + "/" + id_str + "/about");
|
||||
}
|
||||
}
|
||||
}
|
||||
98
indra/llui/llurlaction.h
Normal file
98
indra/llui/llurlaction.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* @file llurlaction.h
|
||||
* @author Martin Reddy
|
||||
* @brief A set of actions that can performed on Urls
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLURLACTION_H
|
||||
#define LL_LLURLACTION_H
|
||||
|
||||
#include <string>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
///
|
||||
/// The LLUrlAction class provides a number of static functions that
|
||||
/// let you open Urls in web browsers, execute SLURLs, and copy Urls
|
||||
/// to the clipboard. Many of these functions are not available at
|
||||
/// the llui level, and must be supplied via a set of callbacks.
|
||||
///
|
||||
/// N.B. The action functions specifically do not use const ref
|
||||
/// strings so that a url parameter can be used into a boost::bind()
|
||||
/// call under situations when that input string is deallocated before
|
||||
/// the callback is executed.
|
||||
///
|
||||
class LLUrlAction
|
||||
{
|
||||
public:
|
||||
LLUrlAction();
|
||||
|
||||
/// load a Url in the user's preferred web browser
|
||||
static void openURL(std::string url);
|
||||
|
||||
/// load a Url in the internal Second Life web browser
|
||||
static void openURLInternal(std::string url);
|
||||
|
||||
/// load a Url in the operating system's default web browser
|
||||
static void openURLExternal(std::string url);
|
||||
|
||||
/// execute the given secondlife: SLURL
|
||||
static void executeSLURL(std::string url);
|
||||
|
||||
/// if the Url specifies an SL location, teleport there
|
||||
static void teleportToLocation(std::string url);
|
||||
|
||||
/// if the Url specifies an SL location, show it on a map
|
||||
static void showLocationOnMap(std::string url);
|
||||
|
||||
/// perform the appropriate action for left-clicking on a Url
|
||||
static void clickAction(std::string url);
|
||||
|
||||
/// copy the label for a Url to the clipboard
|
||||
static void copyLabelToClipboard(std::string url);
|
||||
|
||||
/// copy a Url to the clipboard
|
||||
static void copyURLToClipboard(std::string url);
|
||||
|
||||
/// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile
|
||||
static void showProfile(std::string url);
|
||||
|
||||
/// specify the callbacks to enable this class's functionality
|
||||
typedef boost::function<void (const std::string&)> url_callback_t;
|
||||
typedef boost::function<bool(const std::string& url)> execute_url_callback_t;
|
||||
|
||||
static void setOpenURLCallback(url_callback_t cb);
|
||||
static void setOpenURLInternalCallback(url_callback_t cb);
|
||||
static void setOpenURLExternalCallback(url_callback_t cb);
|
||||
static void setExecuteSLURLCallback(execute_url_callback_t cb);
|
||||
|
||||
private:
|
||||
// callbacks for operations we can perform on Urls
|
||||
static url_callback_t sOpenURLCallback;
|
||||
static url_callback_t sOpenURLInternalCallback;
|
||||
static url_callback_t sOpenURLExternalCallback;
|
||||
|
||||
static execute_url_callback_t sExecuteSLURLCallback;
|
||||
};
|
||||
|
||||
#endif
|
||||
1188
indra/llui/llurlentry.cpp
Normal file
1188
indra/llui/llurlentry.cpp
Normal file
File diff suppressed because it is too large
Load Diff
429
indra/llui/llurlentry.h
Normal file
429
indra/llui/llurlentry.h
Normal file
@@ -0,0 +1,429 @@
|
||||
/**
|
||||
* @file llurlentry.h
|
||||
* @author Martin Reddy
|
||||
* @brief Describes the Url types that can be registered in LLUrlRegistry
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLURLENTRY_H
|
||||
#define LL_LLURLENTRY_H
|
||||
|
||||
#include "lluuid.h"
|
||||
#include "lluicolor.h"
|
||||
#include "llstyle.h"
|
||||
|
||||
#include "llhost.h" // for resolving parcel name by parcel id
|
||||
|
||||
#include <boost/signals2.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
class LLAvatarName;
|
||||
|
||||
typedef boost::signals2::signal<void (const std::string& url,
|
||||
const std::string& label,
|
||||
const std::string& icon)> LLUrlLabelSignal;
|
||||
typedef LLUrlLabelSignal::slot_type LLUrlLabelCallback;
|
||||
|
||||
///
|
||||
/// LLUrlEntryBase is the base class of all Url types registered in the
|
||||
/// LLUrlRegistry. Each derived classes provides a regular expression
|
||||
/// to match the Url type (e.g., http://... or secondlife://...) along
|
||||
/// with an optional icon to display next to instances of the Url in
|
||||
/// a text display and a XUI file to use for any context menu popup.
|
||||
/// Functions are also provided to compute an appropriate label and
|
||||
/// tooltip/status bar text for the Url.
|
||||
///
|
||||
/// Some derived classes of LLUrlEntryBase may wish to compute an
|
||||
/// appropriate label for a Url by asking the server for information.
|
||||
/// You must therefore provide a callback method, so that you can be
|
||||
/// notified when an updated label has been received from the server.
|
||||
/// This label should then be used to replace any previous label
|
||||
/// that you received from getLabel() for the Url in question.
|
||||
///
|
||||
class LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryBase();
|
||||
virtual ~LLUrlEntryBase();
|
||||
|
||||
/// Return the regex pattern that matches this Url
|
||||
boost::regex getPattern() const { return mPattern; }
|
||||
|
||||
/// Return the url from a string that matched the regex
|
||||
virtual std::string getUrl(const std::string &string) const;
|
||||
|
||||
/// Given a matched Url, return a label for the Url
|
||||
virtual std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) { return url; }
|
||||
|
||||
/// Return an icon that can be displayed next to Urls of this type
|
||||
virtual std::string getIcon(const std::string &url);
|
||||
|
||||
/// Return the style to render the displayed text
|
||||
//virtual LLStyle::Params getStyle() const;
|
||||
|
||||
/// Given a matched Url, return a tooltip string for the hyperlink
|
||||
virtual std::string getTooltip(const std::string &string) const { return mTooltip; }
|
||||
|
||||
/// Return the name of a XUI file containing the context menu items
|
||||
std::string getMenuName() const { return mMenuName; }
|
||||
|
||||
/// Return the name of a SL location described by this Url, if any
|
||||
virtual std::string getLocation(const std::string &url) const { return ""; }
|
||||
|
||||
/// Should this link text be underlined only when mouse is hovered over it?
|
||||
virtual bool underlineOnHoverOnly(const std::string &string) const { return false; }
|
||||
|
||||
virtual LLUUID getID(const std::string &string) const { return LLUUID::null; }
|
||||
|
||||
bool isLinkDisabled() const;
|
||||
|
||||
protected:
|
||||
std::string getIDStringFromUrl(const std::string &url) const;
|
||||
std::string escapeUrl(const std::string &url) const;
|
||||
std::string unescapeUrl(const std::string &url) const;
|
||||
std::string getLabelFromWikiLink(const std::string &url) const;
|
||||
std::string getUrlFromWikiLink(const std::string &string) const;
|
||||
void addObserver(const std::string &id, const std::string &url, const LLUrlLabelCallback &cb);
|
||||
virtual void callObservers(const std::string &id, const std::string &label, const std::string& icon);
|
||||
|
||||
typedef struct {
|
||||
std::string url;
|
||||
LLUrlLabelSignal *signal;
|
||||
} LLUrlEntryObserver;
|
||||
|
||||
boost::regex mPattern;
|
||||
std::string mIcon;
|
||||
std::string mMenuName;
|
||||
std::string mTooltip;
|
||||
std::multimap<std::string, LLUrlEntryObserver> mObservers;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryHTTP Describes generic http: and https: Urls
|
||||
///
|
||||
class LLUrlEntryHTTP : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryHTTP();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryHTTPLabel Describes generic http: and https: Urls with custom labels
|
||||
///
|
||||
class LLUrlEntryHTTPLabel : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryHTTPLabel();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getTooltip(const std::string &string) const;
|
||||
/*virtual*/ std::string getUrl(const std::string &string) const;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryHTTPNoProtocol Describes generic Urls like www.google.com
|
||||
///
|
||||
class LLUrlEntryHTTPNoProtocol : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryHTTPNoProtocol();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getUrl(const std::string &string) const;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntrySLURL Describes http://slurl.com/... Urls
|
||||
///
|
||||
class LLUrlEntrySLURL : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntrySLURL();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getLocation(const std::string &url) const;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryAgent Describes a Second Life agent Url, e.g.,
|
||||
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
|
||||
class LLUrlEntryAgent : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryAgent();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getIcon(const std::string &url);
|
||||
/*virtual*/ std::string getTooltip(const std::string &string) const;
|
||||
//*virtual*/ LLStyle::Params getStyle() const;
|
||||
/*virtual*/ LLUUID getID(const std::string &string) const;
|
||||
/*virtual*/ bool underlineOnHoverOnly(const std::string &string) const;
|
||||
protected:
|
||||
/*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon);
|
||||
private:
|
||||
void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryAgentName Describes a Second Life agent name Url, e.g.,
|
||||
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
|
||||
/// that displays various forms of user name
|
||||
/// This is a base class for the various implementations of name display
|
||||
class LLUrlEntryAgentName : public LLUrlEntryBase, public boost::signals2::trackable
|
||||
{
|
||||
public:
|
||||
LLUrlEntryAgentName();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
//*virtual*/ LLStyle::Params getStyle() const;
|
||||
protected:
|
||||
// override this to pull out relevant name fields
|
||||
virtual std::string getName(const LLAvatarName& avatar_name) = 0;
|
||||
private:
|
||||
void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
/// LLUrlEntryAgentCompleteName Describes a Second Life agent name Url, e.g.,
|
||||
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename
|
||||
/// that displays the full display name + user name for an avatar
|
||||
/// such as "James Linden (james.linden)"
|
||||
class LLUrlEntryAgentCompleteName : public LLUrlEntryAgentName
|
||||
{
|
||||
public:
|
||||
LLUrlEntryAgentCompleteName();
|
||||
private:
|
||||
/*virtual*/ std::string getName(const LLAvatarName& avatar_name);
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryAgentDisplayName Describes a Second Life agent display name Url, e.g.,
|
||||
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname
|
||||
/// that displays the just the display name for an avatar
|
||||
/// such as "James Linden"
|
||||
class LLUrlEntryAgentDisplayName : public LLUrlEntryAgentName
|
||||
{
|
||||
public:
|
||||
LLUrlEntryAgentDisplayName();
|
||||
private:
|
||||
/*virtual*/ std::string getName(const LLAvatarName& avatar_name);
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryAgentUserName Describes a Second Life agent username Url, e.g.,
|
||||
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username
|
||||
/// that displays the just the display name for an avatar
|
||||
/// such as "james.linden"
|
||||
class LLUrlEntryAgentUserName : public LLUrlEntryAgentName
|
||||
{
|
||||
public:
|
||||
LLUrlEntryAgentUserName();
|
||||
private:
|
||||
/*virtual*/ std::string getName(const LLAvatarName& avatar_name);
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryGroup Describes a Second Life group Url, e.g.,
|
||||
/// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about
|
||||
///
|
||||
class LLUrlEntryGroup : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryGroup();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
//*virtual*/ LLStyle::Params getStyle() const;
|
||||
/*virtual*/ LLUUID getID(const std::string &string) const;
|
||||
private:
|
||||
void onGroupNameReceived(const LLUUID& id, const std::string& name, bool is_group);
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryInventory Describes a Second Life inventory Url, e.g.,
|
||||
/// secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select
|
||||
///
|
||||
class LLUrlEntryInventory : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryInventory();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
private:
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryObjectIM Describes a Second Life inspector for the object Url, e.g.,
|
||||
/// secondlife:///app/objectim/7bcd7864-da6b-e43f-4486-91d28a28d95b?name=Object&owner=3de548e1-57be-cfea-2b78-83ae3ad95998&slurl=Danger!%20Danger!/200/200/30/&groupowned=1
|
||||
///
|
||||
class LLUrlEntryObjectIM : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryObjectIM();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getLocation(const std::string &url) const;
|
||||
private:
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryParcel Describes a Second Life parcel Url, e.g.,
|
||||
/// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about
|
||||
///
|
||||
class LLUrlEntryParcel : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
struct LLParcelData
|
||||
{
|
||||
LLUUID parcel_id;
|
||||
std::string name;
|
||||
std::string sim_name;
|
||||
F32 global_x;
|
||||
F32 global_y;
|
||||
F32 global_z;
|
||||
};
|
||||
|
||||
LLUrlEntryParcel();
|
||||
~LLUrlEntryParcel();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
|
||||
// Sends a parcel info request to sim.
|
||||
void sendParcelInfoRequest(const LLUUID& parcel_id);
|
||||
|
||||
// Calls observers of certain parcel id providing them with parcel label.
|
||||
void onParcelInfoReceived(const std::string &id, const std::string &label);
|
||||
|
||||
// Processes parcel label and triggers notifying observers.
|
||||
static void processParcelInfo(const LLParcelData& parcel_data);
|
||||
|
||||
// Next 4 setters are used to update agent and viewer connection information
|
||||
// upon events like user login, viewer disconnect and user changing region host.
|
||||
// These setters are made public to be accessible from newview and should not be
|
||||
// used in other cases.
|
||||
static void setAgentID(const LLUUID& id) { sAgentID = id; }
|
||||
static void setSessionID(const LLUUID& id) { sSessionID = id; }
|
||||
static void setRegionHost(const LLHost& host) { sRegionHost = host; }
|
||||
static void setDisconnected(bool disconnected) { sDisconnected = disconnected; }
|
||||
|
||||
private:
|
||||
static LLUUID sAgentID;
|
||||
static LLUUID sSessionID;
|
||||
static LLHost sRegionHost;
|
||||
static bool sDisconnected;
|
||||
static std::set<LLUrlEntryParcel*> sParcelInfoObservers;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryPlace Describes a Second Life location Url, e.g.,
|
||||
/// secondlife://Ahern/50/50/50
|
||||
///
|
||||
class LLUrlEntryPlace : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryPlace();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getLocation(const std::string &url) const;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryRegion Describes a Second Life location Url, e.g.,
|
||||
/// secondlife:///app/region/Ahern/128/128/0
|
||||
///
|
||||
class LLUrlEntryRegion : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryRegion();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getLocation(const std::string &url) const;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryTeleport Describes a Second Life teleport Url, e.g.,
|
||||
/// secondlife:///app/teleport/Ahern/50/50/50/
|
||||
///
|
||||
class LLUrlEntryTeleport : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryTeleport();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getLocation(const std::string &url) const;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntrySL Describes a generic SLURL, e.g., a Url that starts
|
||||
/// with secondlife:// (used as a catch-all for cases not matched above)
|
||||
///
|
||||
class LLUrlEntrySL : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntrySL();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntrySLLabel Describes a generic SLURL, e.g., a Url that starts
|
||||
/// with secondlife:// with the ability to specify a custom label.
|
||||
///
|
||||
class LLUrlEntrySLLabel : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntrySLLabel();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getUrl(const std::string &string) const;
|
||||
/*virtual*/ std::string getTooltip(const std::string &string) const;
|
||||
/*virtual*/ bool underlineOnHoverOnly(const std::string &string) const;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryWorldMap Describes a Second Life worldmap Url, e.g.,
|
||||
/// secondlife:///app/worldmap/Ahern/50/50/50
|
||||
///
|
||||
class LLUrlEntryWorldMap : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryWorldMap();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getLocation(const std::string &url) const;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryNoLink lets us turn of URL detection with <nolink>...</nolink> tags
|
||||
///
|
||||
class LLUrlEntryNoLink : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryNoLink();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getUrl(const std::string &string) const;
|
||||
//*virtual*/ LLStyle::Params getStyle() const;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryIcon describes an icon with <icon>...</icon> tags
|
||||
///
|
||||
class LLUrlEntryIcon : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryIcon();
|
||||
/*virtual*/ std::string getUrl(const std::string &string) const;
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getIcon(const std::string &url);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
62
indra/llui/llurlmatch.cpp
Normal file
62
indra/llui/llurlmatch.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @file llurlmatch.cpp
|
||||
* @author Martin Reddy
|
||||
* @brief Specifies a matched Url in a string, as returned by LLUrlRegistry
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llurlmatch.h"
|
||||
|
||||
LLUrlMatch::LLUrlMatch() :
|
||||
mStart(0),
|
||||
mEnd(0),
|
||||
mUrl(""),
|
||||
mLabel(""),
|
||||
mTooltip(""),
|
||||
mIcon(""),
|
||||
mMenuName(""),
|
||||
mLocation(""),
|
||||
mUnderlineOnHoverOnly(false)
|
||||
{
|
||||
}
|
||||
|
||||
void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
|
||||
const std::string &label, const std::string &tooltip,
|
||||
const std::string &icon, /*const LLStyle::Params& style,*/
|
||||
const std::string &menu, const std::string &location,
|
||||
const LLUUID& id, bool underline_on_hover_only)
|
||||
{
|
||||
mStart = start;
|
||||
mEnd = end;
|
||||
mUrl = url;
|
||||
mLabel = label;
|
||||
mTooltip = tooltip;
|
||||
mIcon = icon;
|
||||
//mStyle = style;
|
||||
//mStyle.link_href = url;
|
||||
mMenuName = menu;
|
||||
mLocation = location;
|
||||
mID = id;
|
||||
mUnderlineOnHoverOnly = underline_on_hover_only;
|
||||
}
|
||||
105
indra/llui/llurlmatch.h
Normal file
105
indra/llui/llurlmatch.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @file llurlmatch.h
|
||||
* @author Martin Reddy
|
||||
* @brief Specifies a matched Url in a string, as returned by LLUrlRegistry
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLURLMATCH_H
|
||||
#define LL_LLURLMATCH_H
|
||||
|
||||
//#include "linden_common.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "llstyle.h"
|
||||
|
||||
///
|
||||
/// LLUrlMatch describes a single Url that was matched within a string by
|
||||
/// the LLUrlRegistry::findUrl() method. It includes the actual Url that
|
||||
/// was matched along with its first/last character offset in the string.
|
||||
/// An alternate label is also provided for creating a hyperlink, as well
|
||||
/// as tooltip/status text, an icon, and a XUI file for a context menu
|
||||
/// that can be used in a popup for a Url (e.g., Open, Copy URL, etc.)
|
||||
///
|
||||
class LLUrlMatch
|
||||
{
|
||||
public:
|
||||
LLUrlMatch();
|
||||
|
||||
/// return true if this object does not contain a valid Url match yet
|
||||
bool empty() const { return mUrl.empty(); }
|
||||
|
||||
/// return the offset in the string for the first character of the Url
|
||||
U32 getStart() const { return mStart; }
|
||||
|
||||
/// return the offset in the string for the last character of the Url
|
||||
U32 getEnd() const { return mEnd; }
|
||||
|
||||
/// return the Url that has been matched in the input string
|
||||
std::string getUrl() const { return mUrl; }
|
||||
|
||||
/// return a label that can be used for the display of this Url
|
||||
std::string getLabel() const { return mLabel; }
|
||||
|
||||
/// return a message that could be displayed in a tooltip or status bar
|
||||
std::string getTooltip() const { return mTooltip; }
|
||||
|
||||
/// return the filename for an icon that can be displayed next to this Url
|
||||
std::string getIcon() const { return mIcon; }
|
||||
|
||||
/// Return the color to render the displayed text
|
||||
//LLStyle::Params getStyle() const { return mStyle; }
|
||||
|
||||
/// Return the name of a XUI file containing the context menu items
|
||||
std::string getMenuName() const { return mMenuName; }
|
||||
|
||||
/// return the SL location that this Url describes, or "" if none.
|
||||
std::string getLocation() const { return mLocation; }
|
||||
|
||||
/// Should this link text be underlined only when mouse is hovered over it?
|
||||
bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; }
|
||||
|
||||
/// Change the contents of this match object (used by LLUrlRegistry)
|
||||
void setValues(U32 start, U32 end, const std::string &url, const std::string &label,
|
||||
const std::string &tooltip, const std::string &icon,
|
||||
/*const LLStyle::Params& style, */const std::string &menu,
|
||||
const std::string &location, const LLUUID& id,
|
||||
bool underline_on_hover_only = false );
|
||||
|
||||
const LLUUID& getID() const { return mID; }
|
||||
private:
|
||||
U32 mStart;
|
||||
U32 mEnd;
|
||||
std::string mUrl;
|
||||
std::string mLabel;
|
||||
std::string mTooltip;
|
||||
std::string mIcon;
|
||||
std::string mMenuName;
|
||||
std::string mLocation;
|
||||
LLUUID mID;
|
||||
//LLStyle::Params mStyle;
|
||||
bool mUnderlineOnHoverOnly;
|
||||
};
|
||||
|
||||
#endif
|
||||
263
indra/llui/llurlregistry.cpp
Normal file
263
indra/llui/llurlregistry.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
/**
|
||||
* @file llurlregistry.cpp
|
||||
* @author Martin Reddy
|
||||
* @brief Contains a set of Url types that can be matched in a string
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llurlregistry.h"
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
// default dummy callback that ignores any label updates from the server
|
||||
void LLUrlRegistryNullCallback(const std::string &url, const std::string &label, const std::string& icon)
|
||||
{
|
||||
}
|
||||
|
||||
LLUrlRegistry::LLUrlRegistry()
|
||||
{
|
||||
mUrlEntry.reserve(20);
|
||||
|
||||
// Urls are matched in the order that they were registered
|
||||
registerUrl(new LLUrlEntryNoLink());
|
||||
registerUrl(new LLUrlEntryIcon());
|
||||
registerUrl(new LLUrlEntrySLURL());
|
||||
registerUrl(new LLUrlEntryHTTP());
|
||||
registerUrl(new LLUrlEntryHTTPLabel());
|
||||
registerUrl(new LLUrlEntryAgentCompleteName());
|
||||
registerUrl(new LLUrlEntryAgentDisplayName());
|
||||
registerUrl(new LLUrlEntryAgentUserName());
|
||||
// LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since
|
||||
// LLUrlEntryAgent is a less specific (catchall for agent urls)
|
||||
registerUrl(new LLUrlEntryAgent());
|
||||
registerUrl(new LLUrlEntryGroup());
|
||||
registerUrl(new LLUrlEntryParcel());
|
||||
registerUrl(new LLUrlEntryTeleport());
|
||||
registerUrl(new LLUrlEntryRegion());
|
||||
registerUrl(new LLUrlEntryWorldMap());
|
||||
registerUrl(new LLUrlEntryObjectIM());
|
||||
registerUrl(new LLUrlEntryPlace());
|
||||
registerUrl(new LLUrlEntryInventory());
|
||||
registerUrl(new LLUrlEntryObjectIM());
|
||||
//LLUrlEntrySL and LLUrlEntrySLLabel have more common pattern,
|
||||
//so it should be registered in the end of list
|
||||
registerUrl(new LLUrlEntrySL());
|
||||
registerUrl(new LLUrlEntrySLLabel());
|
||||
// most common pattern is a URL without any protocol,
|
||||
// e.g., "secondlife.com"
|
||||
registerUrl(new LLUrlEntryHTTPNoProtocol());
|
||||
}
|
||||
|
||||
LLUrlRegistry::~LLUrlRegistry()
|
||||
{
|
||||
// free all of the LLUrlEntryBase objects we are holding
|
||||
std::vector<LLUrlEntryBase *>::iterator it;
|
||||
for (it = mUrlEntry.begin(); it != mUrlEntry.end(); ++it)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
void LLUrlRegistry::registerUrl(LLUrlEntryBase *url, bool force_front)
|
||||
{
|
||||
if (url)
|
||||
{
|
||||
if (force_front) // IDEVO
|
||||
mUrlEntry.insert(mUrlEntry.begin(), url);
|
||||
else
|
||||
mUrlEntry.push_back(url);
|
||||
}
|
||||
}
|
||||
|
||||
static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &end)
|
||||
{
|
||||
boost::cmatch result;
|
||||
bool found;
|
||||
|
||||
// regex_search can potentially throw an exception, so check for it
|
||||
try
|
||||
{
|
||||
found = boost::regex_search(text, result, regex);
|
||||
}
|
||||
catch (std::runtime_error &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! found)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// return the first/last character offset for the matched substring
|
||||
start = static_cast<U32>(result[0].first - text);
|
||||
end = static_cast<U32>(result[0].second - text) - 1;
|
||||
|
||||
// we allow certain punctuation to terminate a Url but not match it,
|
||||
// e.g., "http://foo.com/." should just match "http://foo.com/"
|
||||
if (text[end] == '.' || text[end] == ',')
|
||||
{
|
||||
end--;
|
||||
}
|
||||
// ignore a terminating ')' when Url contains no matching '('
|
||||
// see DEV-19842 for details
|
||||
else if (text[end] == ')' && std::string(text+start, end-start).find('(') == std::string::npos)
|
||||
{
|
||||
end--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool stringHasUrl(const std::string &text)
|
||||
{
|
||||
// fast heuristic test for a URL in a string. This is used
|
||||
// to avoid lots of costly regex calls, BUT it needs to be
|
||||
// kept in sync with the LLUrlEntry regexes we support.
|
||||
return (text.find("://") != std::string::npos ||
|
||||
text.find("www.") != std::string::npos ||
|
||||
text.find(".com") != std::string::npos ||
|
||||
text.find(".net") != std::string::npos ||
|
||||
text.find(".edu") != std::string::npos ||
|
||||
text.find(".org") != std::string::npos ||
|
||||
text.find("<nolink>") != std::string::npos ||
|
||||
text.find("<icon") != std::string::npos);
|
||||
}
|
||||
|
||||
bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb)
|
||||
{
|
||||
// avoid costly regexes if there is clearly no URL in the text
|
||||
if (! stringHasUrl(text))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// find the first matching regex from all url entries in the registry
|
||||
U32 match_start = 0, match_end = 0;
|
||||
LLUrlEntryBase *match_entry = NULL;
|
||||
|
||||
std::vector<LLUrlEntryBase *>::iterator it;
|
||||
for (it = mUrlEntry.begin(); it != mUrlEntry.end(); ++it)
|
||||
{
|
||||
LLUrlEntryBase *url_entry = *it;
|
||||
|
||||
U32 start = 0, end = 0;
|
||||
if (matchRegex(text.c_str(), url_entry->getPattern(), start, end))
|
||||
{
|
||||
// does this match occur in the string before any other match
|
||||
if (start < match_start || match_entry == NULL)
|
||||
{
|
||||
match_start = start;
|
||||
match_end = end;
|
||||
match_entry = url_entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// did we find a match? if so, return its details in the match object
|
||||
if (match_entry)
|
||||
{
|
||||
// fill in the LLUrlMatch object and return it
|
||||
std::string url = text.substr(match_start, match_end - match_start + 1);
|
||||
match.setValues(match_start, match_end,
|
||||
match_entry->getUrl(url),
|
||||
match_entry->getLabel(url, cb),
|
||||
match_entry->getTooltip(url),
|
||||
match_entry->getIcon(url),
|
||||
//match_entry->getStyle(),
|
||||
match_entry->getMenuName(),
|
||||
match_entry->getLocation(url),
|
||||
match_entry->getID(url),
|
||||
match_entry->underlineOnHoverOnly(url));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUrlLabelCallback &cb)
|
||||
{
|
||||
// boost::regex_search() only works on char or wchar_t
|
||||
// types, but wchar_t is only 2-bytes on Win32 (not 4).
|
||||
// So we use UTF-8 to make this work the same everywhere.
|
||||
std::string utf8_text = wstring_to_utf8str(text);
|
||||
if (findUrl(utf8_text, match, cb))
|
||||
{
|
||||
// we cannot blindly return the start/end offsets from
|
||||
// the UTF-8 string because it is a variable-length
|
||||
// character encoding, so we need to update the start
|
||||
// and end values to be correct for the wide string.
|
||||
LLWString wurl = utf8str_to_wstring(match.getUrl());
|
||||
S32 start = text.find(wurl);
|
||||
if (start == std::string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
S32 end = start + wurl.size() - 1;
|
||||
|
||||
match.setValues(start, end, match.getUrl(),
|
||||
match.getLabel(),
|
||||
match.getTooltip(),
|
||||
match.getIcon(),
|
||||
//match.getStyle(),
|
||||
match.getMenuName(),
|
||||
match.getLocation(),
|
||||
match.getID(),
|
||||
match.underlineOnHoverOnly());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LLUrlRegistry::hasUrl(const std::string &text)
|
||||
{
|
||||
LLUrlMatch match;
|
||||
return findUrl(text, match);
|
||||
}
|
||||
|
||||
bool LLUrlRegistry::hasUrl(const LLWString &text)
|
||||
{
|
||||
LLUrlMatch match;
|
||||
return findUrl(text, match);
|
||||
}
|
||||
|
||||
bool LLUrlRegistry::isUrl(const std::string &text)
|
||||
{
|
||||
LLUrlMatch match;
|
||||
if (findUrl(text, match))
|
||||
{
|
||||
return (match.getStart() == 0 && match.getEnd() >= text.size()-1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LLUrlRegistry::isUrl(const LLWString &text)
|
||||
{
|
||||
LLUrlMatch match;
|
||||
if (findUrl(text, match))
|
||||
{
|
||||
return (match.getStart() == 0 && match.getEnd() >= text.size()-1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
97
indra/llui/llurlregistry.h
Normal file
97
indra/llui/llurlregistry.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @file llurlregistry.h
|
||||
* @author Martin Reddy
|
||||
* @brief Contains a set of Url types that can be matched in a string
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLURLREGISTRY_H
|
||||
#define LL_LLURLREGISTRY_H
|
||||
|
||||
#include "llurlentry.h"
|
||||
#include "llurlmatch.h"
|
||||
#include "llsingleton.h"
|
||||
#include "llstring.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/// This default callback for findUrl() simply ignores any label updates
|
||||
void LLUrlRegistryNullCallback(const std::string &url,
|
||||
const std::string &label,
|
||||
const std::string &icon);
|
||||
|
||||
///
|
||||
/// LLUrlRegistry is a singleton that contains a set of Url types that
|
||||
/// can be matched in string. E.g., http:// or secondlife:// Urls.
|
||||
///
|
||||
/// Clients call the findUrl() method on a string to locate the first
|
||||
/// occurence of a supported Urls in that string. If findUrl() returns
|
||||
/// true, the LLUrlMatch object will be updated to describe the Url
|
||||
/// that was matched, including a label that can be used to hyperlink
|
||||
/// the Url, an icon to display next to the Url, and a XUI menu that
|
||||
/// can be used as a popup context menu for that Url.
|
||||
///
|
||||
/// New Url types can be added to the registry with the registerUrl
|
||||
/// method. E.g., to add support for a new secondlife:///app/ Url.
|
||||
///
|
||||
/// Computing the label for a Url could involve a roundtrip request
|
||||
/// to the server (e.g., to find the actual agent or group name).
|
||||
/// As such, you can provide a callback method that will get invoked
|
||||
/// when a new label is available for one of your matched Urls.
|
||||
///
|
||||
class LLUrlRegistry : public LLSingleton<LLUrlRegistry>
|
||||
{
|
||||
public:
|
||||
~LLUrlRegistry();
|
||||
|
||||
/// add a new Url handler to the registry (will be freed on destruction)
|
||||
/// optionally force it to the front of the list, making it take
|
||||
/// priority over other regular expression matches for URLs
|
||||
void registerUrl(LLUrlEntryBase *url, bool force_front = false);
|
||||
|
||||
/// get the next Url in an input string, starting at a given character offset
|
||||
/// your callback is invoked if the matched Url's label changes in the future
|
||||
bool findUrl(const std::string &text, LLUrlMatch &match,
|
||||
const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback);
|
||||
|
||||
/// a slightly less efficient version of findUrl for wide strings
|
||||
bool findUrl(const LLWString &text, LLUrlMatch &match,
|
||||
const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback);
|
||||
|
||||
// return true if the given string contains a URL that findUrl would match
|
||||
bool hasUrl(const std::string &text);
|
||||
bool hasUrl(const LLWString &text);
|
||||
|
||||
// return true if the given string is a URL that findUrl would match
|
||||
bool isUrl(const std::string &text);
|
||||
bool isUrl(const LLWString &text);
|
||||
|
||||
private:
|
||||
LLUrlRegistry();
|
||||
friend class LLSingleton<LLUrlRegistry>;
|
||||
|
||||
std::vector<LLUrlEntryBase *> mUrlEntry;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -41,6 +41,17 @@
|
||||
#include "lluuid.h"
|
||||
|
||||
#include "lldiriterator.h"
|
||||
#include "stringize.h"
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/assign/list_of.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
using boost::assign::list_of;
|
||||
using boost::assign::map_list_of;
|
||||
|
||||
#if LL_WINDOWS
|
||||
#include "lldir_win32.h"
|
||||
@@ -86,12 +97,17 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask)
|
||||
std::string fullpath;
|
||||
S32 result;
|
||||
|
||||
// File masks starting with "/" will match nothing, so we consider them invalid.
|
||||
if (LLStringUtil::startsWith(mask, getDirDelimiter()))
|
||||
{
|
||||
llwarns << "Invalid file mask: " << mask << llendl;
|
||||
llassert(!"Invalid file mask");
|
||||
}
|
||||
|
||||
LLDirIterator iter(dirname, mask);
|
||||
while (iter.next(filename))
|
||||
{
|
||||
fullpath = dirname;
|
||||
fullpath += getDirDelimiter();
|
||||
fullpath += filename;
|
||||
fullpath = add(dirname, filename);
|
||||
|
||||
if(LLFile::isdir(fullpath))
|
||||
{
|
||||
@@ -259,12 +275,12 @@ std::string LLDir::buildSLOSCacheDir() const
|
||||
}
|
||||
else
|
||||
{
|
||||
res = getOSUserAppDir() + mDirDelimiter + "cache_sg1";
|
||||
res = add(getOSUserAppDir(), "cache_sg1");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res = getOSCacheDir() + mDirDelimiter + "SingularityViewer";
|
||||
res = add(getOSCacheDir(), "SingularityViewer");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -312,6 +328,39 @@ const std::string &LLDir::getLLPluginDir() const
|
||||
return mLLPluginDir;
|
||||
}
|
||||
|
||||
static std::string ELLPathToString(ELLPath location)
|
||||
{
|
||||
typedef std::map<ELLPath, const char*> ELLPathMap;
|
||||
#define ENT(symbol) (symbol, #symbol)
|
||||
static const ELLPathMap sMap = map_list_of
|
||||
ENT(LL_PATH_NONE)
|
||||
ENT(LL_PATH_USER_SETTINGS)
|
||||
ENT(LL_PATH_APP_SETTINGS)
|
||||
ENT(LL_PATH_PER_SL_ACCOUNT) // returns/expands to blank string if we don't know the account name yet
|
||||
ENT(LL_PATH_CACHE)
|
||||
ENT(LL_PATH_CHARACTER)
|
||||
ENT(LL_PATH_HELP)
|
||||
ENT(LL_PATH_LOGS)
|
||||
ENT(LL_PATH_TEMP)
|
||||
ENT(LL_PATH_SKINS)
|
||||
ENT(LL_PATH_TOP_SKIN)
|
||||
ENT(LL_PATH_CHAT_LOGS)
|
||||
ENT(LL_PATH_PER_ACCOUNT_CHAT_LOGS)
|
||||
ENT(LL_PATH_USER_SKIN)
|
||||
ENT(LL_PATH_LOCAL_ASSETS)
|
||||
ENT(LL_PATH_EXECUTABLE)
|
||||
ENT(LL_PATH_DEFAULT_SKIN)
|
||||
ENT(LL_PATH_FONTS)
|
||||
ENT(LL_PATH_LAST)
|
||||
;
|
||||
#undef ENT
|
||||
|
||||
ELLPathMap::const_iterator found = sMap.find(location);
|
||||
if (found != sMap.end())
|
||||
return found->second;
|
||||
return STRINGIZE("Invalid ELLPath value " << location);
|
||||
}
|
||||
|
||||
std::string LLDir::getExpandedFilename(ELLPath location, const std::string& filename) const
|
||||
{
|
||||
return getExpandedFilename(location, "", filename);
|
||||
@@ -332,15 +381,11 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
|
||||
break;
|
||||
|
||||
case LL_PATH_APP_SETTINGS:
|
||||
prefix = getAppRODataDir();
|
||||
prefix += mDirDelimiter;
|
||||
prefix += "app_settings";
|
||||
prefix = add(getAppRODataDir(), "app_settings");
|
||||
break;
|
||||
|
||||
case LL_PATH_CHARACTER:
|
||||
prefix = getAppRODataDir();
|
||||
prefix += mDirDelimiter;
|
||||
prefix += "character";
|
||||
prefix = add(getAppRODataDir(), "character");
|
||||
break;
|
||||
|
||||
case LL_PATH_HELP:
|
||||
@@ -352,9 +397,7 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
|
||||
break;
|
||||
|
||||
case LL_PATH_USER_SETTINGS:
|
||||
prefix = getOSUserAppDir();
|
||||
prefix += mDirDelimiter;
|
||||
prefix += "user_settings";
|
||||
prefix = add(getOSUserAppDir(), "user_settings");
|
||||
break;
|
||||
|
||||
case LL_PATH_PER_SL_ACCOUNT:
|
||||
@@ -370,9 +413,7 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
|
||||
break;
|
||||
|
||||
case LL_PATH_LOGS:
|
||||
prefix = getOSUserAppDir();
|
||||
prefix += mDirDelimiter;
|
||||
prefix += "logs";
|
||||
prefix = add(getOSUserAppDir(), "logs");
|
||||
break;
|
||||
|
||||
case LL_PATH_TEMP:
|
||||
@@ -396,9 +437,7 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
|
||||
break;
|
||||
|
||||
case LL_PATH_LOCAL_ASSETS:
|
||||
prefix = getAppRODataDir();
|
||||
prefix += mDirDelimiter;
|
||||
prefix += "local_assets";
|
||||
prefix = add(getAppRODataDir(), "local_assets");
|
||||
break;
|
||||
|
||||
case LL_PATH_EXECUTABLE:
|
||||
@@ -406,56 +445,36 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
|
||||
break;
|
||||
|
||||
case LL_PATH_FONTS:
|
||||
prefix = getAppRODataDir();
|
||||
prefix += mDirDelimiter;
|
||||
prefix += "fonts";
|
||||
prefix = add(getAppRODataDir(), "fonts");
|
||||
break;
|
||||
|
||||
default:
|
||||
llassert(0);
|
||||
}
|
||||
|
||||
std::string filename = in_filename;
|
||||
if (!subdir2.empty())
|
||||
{
|
||||
filename = subdir2 + mDirDelimiter + filename;
|
||||
}
|
||||
|
||||
if (!subdir1.empty())
|
||||
{
|
||||
filename = subdir1 + mDirDelimiter + filename;
|
||||
}
|
||||
|
||||
if (prefix.empty())
|
||||
{
|
||||
llwarns << "prefix is empty, possible bad filename" << llendl;
|
||||
}
|
||||
|
||||
std::string expanded_filename;
|
||||
if (!filename.empty())
|
||||
{
|
||||
if (!prefix.empty())
|
||||
{
|
||||
expanded_filename += prefix;
|
||||
expanded_filename += mDirDelimiter;
|
||||
expanded_filename += filename;
|
||||
}
|
||||
else
|
||||
{
|
||||
expanded_filename = filename;
|
||||
}
|
||||
}
|
||||
else if (!prefix.empty())
|
||||
{
|
||||
// Directory only, no file name.
|
||||
expanded_filename = prefix;
|
||||
}
|
||||
else
|
||||
{
|
||||
expanded_filename.assign("");
|
||||
llwarns << ELLPathToString(location)
|
||||
<< ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename
|
||||
<< "': prefix is empty, possible bad filename" << llendl;
|
||||
}
|
||||
|
||||
//llinfos << "*** EXPANDED FILENAME: <" << expanded_filename << ">" << llendl;
|
||||
std::string expanded_filename = add(add(prefix, subdir1), subdir2);
|
||||
if (expanded_filename.empty() && in_filename.empty())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
// Use explicit concatenation here instead of another add() call. Callers
|
||||
// passing in_filename as "" expect to obtain a pathname ending with
|
||||
// mDirSeparator so they can later directly concatenate with a specific
|
||||
// filename. A caller using add() doesn't care, but there's still code
|
||||
// loose in the system that uses std::string::operator+().
|
||||
expanded_filename += mDirDelimiter;
|
||||
expanded_filename += in_filename;
|
||||
|
||||
LL_DEBUGS("LLDir") << ELLPathToString(location)
|
||||
<< ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename
|
||||
<< "' => '" << expanded_filename << "'" << LL_ENDL;
|
||||
return expanded_filename;
|
||||
}
|
||||
|
||||
@@ -530,12 +549,7 @@ std::string LLDir::getTempFilename() const
|
||||
random_uuid.generate();
|
||||
random_uuid.toString(uuid_str);
|
||||
|
||||
std::string temp_filename = getTempDir();
|
||||
temp_filename += mDirDelimiter;
|
||||
temp_filename += uuid_str;
|
||||
temp_filename += ".tmp";
|
||||
|
||||
return temp_filename;
|
||||
return add(getTempDir(), uuid_str + ".tmp");
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -572,15 +586,9 @@ void LLDir::setLindenUserDir(const std::string &grid, const std::string &first,
|
||||
{
|
||||
// some platforms have case-sensitive filesystems, so be
|
||||
// utterly consistent with our firstname/lastname case.
|
||||
std::string firstlower(first);
|
||||
LLStringUtil::toLower(firstlower);
|
||||
std::string lastlower(last);
|
||||
LLStringUtil::toLower(lastlower);
|
||||
mLindenUserDir = getOSUserAppDir();
|
||||
mLindenUserDir += mDirDelimiter;
|
||||
mLindenUserDir += firstlower;
|
||||
mLindenUserDir += "_";
|
||||
mLindenUserDir += lastlower;
|
||||
std::string userlower(first+"_"+last);
|
||||
LLStringUtil::toLower(userlower);
|
||||
mLindenUserDir = add(getOSUserAppDir(), userlower);
|
||||
|
||||
if (!grid.empty())
|
||||
{
|
||||
@@ -617,16 +625,9 @@ void LLDir::setPerAccountChatLogsDir(const std::string &grid, const std::string
|
||||
{
|
||||
// some platforms have case-sensitive filesystems, so be
|
||||
// utterly consistent with our firstname/lastname case.
|
||||
std::string firstlower(first);
|
||||
LLStringUtil::toLower(firstlower);
|
||||
std::string lastlower(last);
|
||||
LLStringUtil::toLower(lastlower);
|
||||
mPerAccountChatLogsDir = getChatLogsDir();
|
||||
mPerAccountChatLogsDir += mDirDelimiter;
|
||||
mPerAccountChatLogsDir += firstlower;
|
||||
mPerAccountChatLogsDir += "_";
|
||||
mPerAccountChatLogsDir += lastlower;
|
||||
|
||||
std::string userlower(first+"_"+last);
|
||||
LLStringUtil::toLower(userlower);
|
||||
mPerAccountChatLogsDir = add(getChatLogsDir(), userlower);
|
||||
if (!grid.empty())
|
||||
{
|
||||
std::string gridlower(grid);
|
||||
@@ -644,22 +645,18 @@ void LLDir::setPerAccountChatLogsDir(const std::string &grid, const std::string
|
||||
void LLDir::setSkinFolder(const std::string &skin_folder)
|
||||
{
|
||||
mSkinDir = getSkinBaseDir();
|
||||
mSkinDir += mDirDelimiter;
|
||||
mSkinDir += skin_folder;
|
||||
append(mSkinDir, skin_folder);
|
||||
|
||||
// user modifications to current skin
|
||||
// e.g. c:\documents and settings\users\username\application data\second life\skins\dazzle
|
||||
mUserSkinDir = getOSUserAppDir();
|
||||
mUserSkinDir += mDirDelimiter;
|
||||
mUserSkinDir += "skins_sg1";
|
||||
mUserSkinDir += mDirDelimiter;
|
||||
mUserSkinDir += skin_folder;
|
||||
append(mUserSkinDir, "skins_sg1");
|
||||
append(mUserSkinDir, skin_folder);
|
||||
|
||||
// base skin which is used as fallback for all skinned files
|
||||
// e.g. c:\program files\secondlife\skins\default
|
||||
mDefaultSkinDir = getSkinBaseDir();
|
||||
mDefaultSkinDir += mDirDelimiter;
|
||||
mDefaultSkinDir += "default";
|
||||
append(mDefaultSkinDir, "default");
|
||||
}
|
||||
|
||||
bool LLDir::setCacheDir(const std::string &path)
|
||||
@@ -673,7 +670,7 @@ bool LLDir::setCacheDir(const std::string &path)
|
||||
else
|
||||
{
|
||||
LLFile::mkdir(path);
|
||||
std::string tempname = path + mDirDelimiter + "temp";
|
||||
std::string tempname = add(path, "temp");
|
||||
LLFILE* file = LLFile::fopen(tempname,"wt");
|
||||
if (file)
|
||||
{
|
||||
@@ -706,6 +703,57 @@ void LLDir::dumpCurrentDirectories()
|
||||
LL_DEBUGS2("AppInit","Directories") << " SkinDir: " << getSkinDir() << LL_ENDL;
|
||||
}
|
||||
|
||||
std::string LLDir::add(const std::string& path, const std::string& name) const
|
||||
{
|
||||
std::string destpath(path);
|
||||
append(destpath, name);
|
||||
return destpath;
|
||||
}
|
||||
|
||||
void LLDir::append(std::string& destpath, const std::string& name) const
|
||||
{
|
||||
// Delegate question of whether we need a separator to helper method.
|
||||
SepOff sepoff(needSep(destpath, name));
|
||||
if (sepoff.first) // do we need a separator?
|
||||
{
|
||||
destpath += mDirDelimiter;
|
||||
}
|
||||
// If destpath ends with a separator, AND name starts with one, skip
|
||||
// name's leading separator.
|
||||
destpath += name.substr(sepoff.second);
|
||||
}
|
||||
|
||||
LLDir::SepOff LLDir::needSep(const std::string& path, const std::string& name) const
|
||||
{
|
||||
if (path.empty() || name.empty())
|
||||
{
|
||||
// If either path or name are empty, we do not need a separator
|
||||
// between them.
|
||||
return SepOff(false, 0);
|
||||
}
|
||||
// Here we know path and name are both non-empty. But if path already ends
|
||||
// with a separator, or if name already starts with a separator, we need
|
||||
// not add one.
|
||||
std::string::size_type seplen(mDirDelimiter.length());
|
||||
bool path_ends_sep(path.substr(path.length() - seplen) == mDirDelimiter);
|
||||
bool name_starts_sep(name.substr(0, seplen) == mDirDelimiter);
|
||||
if ((! path_ends_sep) && (! name_starts_sep))
|
||||
{
|
||||
// If neither path nor name brings a separator to the junction, then
|
||||
// we need one.
|
||||
return SepOff(true, 0);
|
||||
}
|
||||
if (path_ends_sep && name_starts_sep)
|
||||
{
|
||||
// But if BOTH path and name bring a separator, we need not add one.
|
||||
// Moreover, we should actually skip the leading separator of 'name'.
|
||||
return SepOff(false, seplen);
|
||||
}
|
||||
// Here we know that either path_ends_sep or name_starts_sep is true --
|
||||
// but not both. So don't add a separator, and don't skip any characters:
|
||||
// simple concatenation will do the trick.
|
||||
return SepOff(false, 0);
|
||||
}
|
||||
|
||||
void dir_exists_or_crash(const std::string &dir_name)
|
||||
{
|
||||
|
||||
@@ -140,7 +140,17 @@ class LLDir
|
||||
// Utility routine
|
||||
std::string buildSLOSCacheDir() const;
|
||||
|
||||
/// Append specified @a name to @a destpath, separated by getDirDelimiter()
|
||||
/// if both are non-empty.
|
||||
void append(std::string& destpath, const std::string& name) const;
|
||||
/// Append specified @a name to @a path, separated by getDirDelimiter()
|
||||
/// if both are non-empty. Return result, leaving @a path unmodified.
|
||||
std::string add(const std::string& path, const std::string& name) const;
|
||||
|
||||
protected:
|
||||
// Does an add() or append() call need a directory delimiter?
|
||||
typedef std::pair<bool, unsigned short> SepOff;
|
||||
SepOff needSep(const std::string& path, const std::string& name) const;
|
||||
std::string mAppName; // install directory under progams/ ie "SecondLife"
|
||||
std::string mExecutablePathAndName; // full path + Filename of .exe
|
||||
std::string mExecutableFilename; // Filename of .exe
|
||||
|
||||
@@ -124,10 +124,9 @@ class LLDragDropWin32Target:
|
||||
ScreenToClient( mAppWindowHandle, &pt2 );
|
||||
|
||||
LLCoordWindow cursor_coord_window( pt2.x, pt2.y );
|
||||
window_imp->convertCoords(cursor_coord_window, &gl_coord);
|
||||
MASK mask = gKeyboard->currentMask(TRUE);
|
||||
|
||||
LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask,
|
||||
LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( cursor_coord_window.convert(), mask,
|
||||
LLWindowCallbacks::DNDA_START_TRACKING, mDropUrl );
|
||||
|
||||
switch (result)
|
||||
@@ -180,10 +179,9 @@ class LLDragDropWin32Target:
|
||||
ScreenToClient( mAppWindowHandle, &pt2 );
|
||||
|
||||
LLCoordWindow cursor_coord_window( pt2.x, pt2.y );
|
||||
window_imp->convertCoords(cursor_coord_window, &gl_coord);
|
||||
MASK mask = gKeyboard->currentMask(TRUE);
|
||||
|
||||
LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask,
|
||||
LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( cursor_coord_window.convert(), mask,
|
||||
LLWindowCallbacks::DNDA_TRACK, mDropUrl );
|
||||
|
||||
switch (result)
|
||||
@@ -237,15 +235,13 @@ class LLDragDropWin32Target:
|
||||
LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong( mAppWindowHandle, GWL_USERDATA );
|
||||
if ( NULL != window_imp )
|
||||
{
|
||||
LLCoordGL gl_coord( 0, 0 );
|
||||
|
||||
POINT pt_client;
|
||||
pt_client.x = pt.x;
|
||||
pt_client.y = pt.y;
|
||||
ScreenToClient( mAppWindowHandle, &pt_client );
|
||||
|
||||
LLCoordWindow cursor_coord_window( pt_client.x, pt_client.y );
|
||||
window_imp->convertCoords(cursor_coord_window, &gl_coord);
|
||||
LLCoordGL gl_coord(cursor_coord_window.convert());
|
||||
llinfos << "### (Drop) URL is: " << mDropUrl << llendl;
|
||||
llinfos << "### raw coords are: " << pt.x << " x " << pt.y << llendl;
|
||||
llinfos << "### client coords are: " << pt_client.x << " x " << pt_client.y << llendl;
|
||||
|
||||
@@ -50,14 +50,15 @@ LLSplashScreen *gSplashScreenp = NULL;
|
||||
BOOL gDebugClicks = FALSE;
|
||||
BOOL gDebugWindowProc = FALSE;
|
||||
|
||||
const S32 gURLProtocolWhitelistCount = 3;
|
||||
const std::string gURLProtocolWhitelist[] = { "file:", "http:", "https:" };
|
||||
const S32 gURLProtocolWhitelistCount = 4;
|
||||
const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:"/*, "file:"*/ };
|
||||
|
||||
// CP: added a handler list - this is what's used to open the protocol and is based on registry entry
|
||||
// only meaningful difference currently is that file: protocols are opened using http:
|
||||
// since no protocol handler exists in registry for file:
|
||||
// Important - these lists should match - protocol to handler
|
||||
const std::string gURLProtocolWhitelistHandler[] = { "http", "http", "https" };
|
||||
// Maestro: This list isn't referenced anywhere that I could find
|
||||
//const std::string gURLProtocolWhitelistHandler[] = { "http", "http", "https" };
|
||||
|
||||
|
||||
S32 OSMessageBox(const std::string& text, const std::string& caption, U32 type)
|
||||
@@ -112,6 +113,8 @@ LLWindow::LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags)
|
||||
mCursorHidden(FALSE),
|
||||
mBusyCount(0),
|
||||
mIsMouseClipping(FALSE),
|
||||
mMinWindowWidth(0),
|
||||
mMinWindowHeight(0),
|
||||
mSwapMethod(SWAP_METHOD_UNDEFINED),
|
||||
mHideCursorPermanent(FALSE),
|
||||
mFlags(flags),
|
||||
@@ -180,6 +183,51 @@ void *LLWindow::getMediaWindow()
|
||||
return getPlatformWindow();
|
||||
}
|
||||
|
||||
BOOL LLWindow::setSize(LLCoordScreen size)
|
||||
{
|
||||
if (!getMaximized())
|
||||
{
|
||||
size.mX = llmax(size.mX, mMinWindowWidth);
|
||||
size.mY = llmax(size.mY, mMinWindowHeight);
|
||||
}
|
||||
return setSizeImpl(size);
|
||||
}
|
||||
|
||||
BOOL LLWindow::setSize(LLCoordWindow size)
|
||||
{
|
||||
//HACK: we are inconsistently using minimum window dimensions
|
||||
// in this case, we are constraining the inner "client" rect and other times
|
||||
// we constrain the outer "window" rect
|
||||
// There doesn't seem to be a good way to do this consistently without a bunch of platform
|
||||
// specific code
|
||||
if (!getMaximized())
|
||||
{
|
||||
size.mX = llmax(size.mX, mMinWindowWidth);
|
||||
size.mY = llmax(size.mY, mMinWindowHeight);
|
||||
}
|
||||
return setSizeImpl(size);
|
||||
}
|
||||
|
||||
|
||||
// virtual
|
||||
void LLWindow::setMinSize(U32 min_width, U32 min_height, bool enforce_immediately)
|
||||
{
|
||||
mMinWindowWidth = min_width;
|
||||
mMinWindowHeight = min_height;
|
||||
|
||||
if (enforce_immediately)
|
||||
{
|
||||
LLCoordScreen cur_size;
|
||||
if (!getMaximized() && getSize(&cur_size))
|
||||
{
|
||||
if (cur_size.mX < mMinWindowWidth || cur_size.mY < mMinWindowHeight)
|
||||
{
|
||||
setSizeImpl(LLCoordScreen(llmin(cur_size.mX, mMinWindowWidth), llmin(cur_size.mY, mMinWindowHeight)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//virtual
|
||||
void LLWindow::processMiscNativeEvents()
|
||||
{
|
||||
@@ -209,6 +257,8 @@ std::vector<std::string> LLWindow::getDynamicFallbackFontList()
|
||||
return LLWindowWin32::getDynamicFallbackFontList();
|
||||
#elif LL_DARWIN
|
||||
return LLWindowMacOSX::getDynamicFallbackFontList();
|
||||
#elif LL_MESA_HEADLESS
|
||||
return std::vector<std::string>();
|
||||
#elif LL_SDL
|
||||
return LLWindowSDL::getDynamicFallbackFontList();
|
||||
#else
|
||||
@@ -350,26 +400,26 @@ LLWindow* LLWindowManager::createWindow(
|
||||
#if LL_MESA_HEADLESS
|
||||
new_window = new LLWindowMesaHeadless(callbacks,
|
||||
title, name, x, y, width, height, flags,
|
||||
fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth);
|
||||
fullscreen, clearBg, disable_vsync, ignore_pixel_depth);
|
||||
#elif LL_SDL
|
||||
new_window = new LLWindowSDL(callbacks,
|
||||
title, x, y, width, height, flags,
|
||||
fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
|
||||
fullscreen, clearBg, disable_vsync, ignore_pixel_depth, fsaa_samples);
|
||||
#elif LL_WINDOWS
|
||||
new_window = new LLWindowWin32(callbacks,
|
||||
title, name, x, y, width, height, flags,
|
||||
fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
|
||||
fullscreen, clearBg, disable_vsync, ignore_pixel_depth, fsaa_samples);
|
||||
#elif LL_DARWIN
|
||||
new_window = new LLWindowMacOSX(callbacks,
|
||||
title, name, x, y, width, height, flags,
|
||||
fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
|
||||
fullscreen, clearBg, disable_vsync, ignore_pixel_depth, fsaa_samples);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
new_window = new LLWindowHeadless(callbacks,
|
||||
title, name, x, y, width, height, flags,
|
||||
fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth);
|
||||
fullscreen, clearBg, disable_vsync, ignore_pixel_depth);
|
||||
}
|
||||
|
||||
if (FALSE == new_window->isValid())
|
||||
@@ -404,3 +454,42 @@ BOOL LLWindowManager::isWindowValid(LLWindow *window)
|
||||
{
|
||||
return sWindowList.find(window) != sWindowList.end();
|
||||
}
|
||||
|
||||
//coordinate conversion utility funcs that forward to llwindow
|
||||
LLCoordCommon LL_COORD_TYPE_WINDOW::convertToCommon() const
|
||||
{
|
||||
const LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this);
|
||||
|
||||
LLWindow* windowp = &(*LLWindow::beginInstances());
|
||||
LLCoordGL out;
|
||||
windowp->convertCoords(self, &out);
|
||||
return out.convert();
|
||||
}
|
||||
|
||||
void LL_COORD_TYPE_WINDOW::convertFromCommon(const LLCoordCommon& from)
|
||||
{
|
||||
LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this);
|
||||
|
||||
LLWindow* windowp = &(*LLWindow::beginInstances());
|
||||
LLCoordGL from_gl(from);
|
||||
windowp->convertCoords(from_gl, &self);
|
||||
}
|
||||
|
||||
LLCoordCommon LL_COORD_TYPE_SCREEN::convertToCommon() const
|
||||
{
|
||||
const LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this);
|
||||
|
||||
LLWindow* windowp = &(*LLWindow::beginInstances());
|
||||
LLCoordGL out;
|
||||
windowp->convertCoords(self, &out);
|
||||
return out.convert();
|
||||
}
|
||||
|
||||
void LL_COORD_TYPE_SCREEN::convertFromCommon(const LLCoordCommon& from)
|
||||
{
|
||||
LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this);
|
||||
|
||||
LLWindow* windowp = &(*LLWindow::beginInstances());
|
||||
LLCoordGL from_gl(from);
|
||||
windowp->convertCoords(from_gl, &self);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ const S32 MIN_WINDOW_HEIGHT = 256;
|
||||
|
||||
// Refer to llwindow_test in test/common/llwindow for usage example
|
||||
|
||||
class LLWindow
|
||||
class LLWindow : public LLInstanceTracker<LLWindow>
|
||||
{
|
||||
public:
|
||||
struct LLWindowResolution
|
||||
@@ -79,7 +79,9 @@ public:
|
||||
virtual BOOL getSize(LLCoordScreen *size) = 0;
|
||||
virtual BOOL getSize(LLCoordWindow *size) = 0;
|
||||
virtual BOOL setPosition(LLCoordScreen position) = 0;
|
||||
virtual BOOL setSize(LLCoordScreen size) = 0;
|
||||
BOOL setSize(LLCoordScreen size);
|
||||
BOOL setSize(LLCoordWindow size);
|
||||
virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true);
|
||||
virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) = 0;
|
||||
virtual BOOL setCursorPosition(LLCoordWindow position) = 0;
|
||||
virtual BOOL getCursorPosition(LLCoordWindow *position) = 0;
|
||||
@@ -180,6 +182,9 @@ protected:
|
||||
// Defaults to true
|
||||
virtual BOOL canDelete();
|
||||
|
||||
virtual BOOL setSizeImpl(LLCoordScreen size) = 0;
|
||||
virtual BOOL setSizeImpl(LLCoordWindow size) = 0;
|
||||
|
||||
protected:
|
||||
LLWindowCallbacks* mCallbacks;
|
||||
|
||||
@@ -200,6 +205,8 @@ protected:
|
||||
BOOL mHideCursorPermanent;
|
||||
U32 mFlags;
|
||||
U16 mHighSurrogate;
|
||||
S32 mMinWindowWidth;
|
||||
S32 mMinWindowHeight;
|
||||
|
||||
// Handle a UTF-16 encoding unit received from keyboard.
|
||||
// Converting the series of UTF-16 encoding units to UTF-32 data,
|
||||
@@ -283,7 +290,7 @@ extern BOOL gDebugWindowProc;
|
||||
// Protocols, like "http" and "https" we support in URLs
|
||||
extern const S32 gURLProtocolWhitelistCount;
|
||||
extern const std::string gURLProtocolWhitelist[];
|
||||
extern const std::string gURLProtocolWhitelistHandler[];
|
||||
//extern const std::string gURLProtocolWhitelistHandler[];
|
||||
|
||||
void simpleEscapeString ( std::string& stringIn );
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
//
|
||||
LLWindowHeadless::LLWindowHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height,
|
||||
U32 flags, BOOL fullscreen, BOOL clear_background,
|
||||
BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth)
|
||||
BOOL disable_vsync, BOOL ignore_pixel_depth)
|
||||
: LLWindow(callbacks, fullscreen, flags)
|
||||
{
|
||||
// Initialize a headless keyboard.
|
||||
|
||||
@@ -46,7 +46,8 @@ public:
|
||||
/*virtual*/ BOOL getSize(LLCoordScreen *size) {return FALSE;};
|
||||
/*virtual*/ BOOL getSize(LLCoordWindow *size) {return FALSE;};
|
||||
/*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;};
|
||||
/*virtual*/ BOOL setSize(LLCoordScreen size) {return FALSE;};
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordScreen size) {return FALSE;};
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordWindow size) {return FALSE;};
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;};
|
||||
/*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;};
|
||||
/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;};
|
||||
@@ -95,7 +96,7 @@ public:
|
||||
S32 x, S32 y,
|
||||
S32 width, S32 height,
|
||||
U32 flags, BOOL fullscreen, BOOL clear_background,
|
||||
BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth);
|
||||
BOOL disable_vsync, BOOL ignore_pixel_depth);
|
||||
virtual ~LLWindowHeadless();
|
||||
|
||||
private:
|
||||
|
||||
@@ -3,31 +3,25 @@
|
||||
* @brief Prototypes for functions shared between llwindowmacosx.cpp
|
||||
* and llwindowmacosx-objc.mm.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2006-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* 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$
|
||||
*/
|
||||
|
||||
|
||||
@@ -3,31 +3,25 @@
|
||||
* @brief Definition of functions shared between llwindowmacosx.cpp
|
||||
* and llwindowmacosx-objc.mm.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2006-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* 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$
|
||||
*/
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
|
||||
S32 height, U32 flags,
|
||||
BOOL fullscreen, BOOL clearBg,
|
||||
BOOL disable_vsync, BOOL use_gl,
|
||||
BOOL disable_vsync,
|
||||
BOOL ignore_pixel_depth,
|
||||
U32 fsaa_samples)
|
||||
: LLWindow(NULL, fullscreen, flags)
|
||||
@@ -1256,7 +1256,7 @@ BOOL LLWindowMacOSX::setPosition(const LLCoordScreen position)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LLWindowMacOSX::setSize(const LLCoordScreen size)
|
||||
BOOL LLWindowMacOSX::setSizeImpl(const LLCoordScreen size)
|
||||
{
|
||||
if(mWindow)
|
||||
{
|
||||
@@ -1266,6 +1266,31 @@ BOOL LLWindowMacOSX::setSize(const LLCoordScreen size)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LLWindowMacOSX::setSizeImpl(const LLCoordWindow size)
|
||||
{
|
||||
Rect client_rect;
|
||||
if (mWindow)
|
||||
{
|
||||
OSStatus err = GetWindowBounds(mWindow, kWindowContentRgn, &client_rect);
|
||||
if (err == noErr)
|
||||
{
|
||||
client_rect.right = client_rect.left + size.mX;
|
||||
client_rect.bottom = client_rect.top + size.mY;
|
||||
err = SetWindowBounds(mWindow, kWindowContentRgn, &client_rect);
|
||||
}
|
||||
if (err == noErr)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
llinfos << "Error setting size" << err << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void LLWindowMacOSX::swapBuffers()
|
||||
{
|
||||
aglSwapBuffers(mContext);
|
||||
@@ -2546,6 +2571,9 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
|
||||
{
|
||||
// This is where we would constrain move/resize to a particular screen
|
||||
|
||||
const S32 MIN_WIDTH = mMinWindowWidth;
|
||||
const S32 MIN_HEIGHT = mMinWindowHeight;
|
||||
|
||||
Rect currentBounds;
|
||||
Rect previousBounds;
|
||||
|
||||
@@ -2570,14 +2598,14 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
|
||||
mPreviousWindowRect = previousBounds;
|
||||
}
|
||||
|
||||
if ((currentBounds.right - currentBounds.left) < MIN_WINDOW_WIDTH)
|
||||
if ((currentBounds.right - currentBounds.left) < MIN_WIDTH)
|
||||
{
|
||||
currentBounds.right = currentBounds.left + MIN_WINDOW_WIDTH;
|
||||
currentBounds.right = currentBounds.left + MIN_WIDTH;
|
||||
}
|
||||
|
||||
if ((currentBounds.bottom - currentBounds.top) < MIN_WINDOW_HEIGHT)
|
||||
if ((currentBounds.bottom - currentBounds.top) < MIN_HEIGHT)
|
||||
{
|
||||
currentBounds.bottom = currentBounds.top + MIN_WINDOW_HEIGHT;
|
||||
currentBounds.bottom = currentBounds.top + MIN_HEIGHT;
|
||||
}
|
||||
|
||||
SetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, sizeof(Rect), ¤tBounds);
|
||||
|
||||
@@ -58,7 +58,8 @@ public:
|
||||
/*virtual*/ BOOL getSize(LLCoordScreen *size);
|
||||
/*virtual*/ BOOL getSize(LLCoordWindow *size);
|
||||
/*virtual*/ BOOL setPosition(LLCoordScreen position);
|
||||
/*virtual*/ BOOL setSize(LLCoordScreen size);
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordScreen size);
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordWindow size);
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL);
|
||||
/*virtual*/ BOOL setCursorPosition(LLCoordWindow position);
|
||||
/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position);
|
||||
@@ -123,7 +124,7 @@ public:
|
||||
protected:
|
||||
LLWindowMacOSX(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,
|
||||
BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl,
|
||||
BOOL fullscreen, BOOL clearBg, BOOL disable_vsync,
|
||||
BOOL ignore_pixel_depth,
|
||||
U32 fsaa_samples);
|
||||
~LLWindowMacOSX();
|
||||
|
||||
@@ -41,28 +41,25 @@ U16 *gMesaBuffer = NULL;
|
||||
LLWindowMesaHeadless::LLWindowMesaHeadless(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height,
|
||||
U32 flags, BOOL fullscreen, BOOL clearBg,
|
||||
BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth)
|
||||
BOOL disable_vsync, BOOL ignore_pixel_depth)
|
||||
: LLWindow(callbacks, fullscreen, flags)
|
||||
{
|
||||
if (use_gl)
|
||||
llinfos << "MESA Init" << llendl;
|
||||
mMesaContext = OSMesaCreateContextExt( GL_RGBA, 32, 0, 0, NULL );
|
||||
|
||||
/* Allocate the image buffer */
|
||||
mMesaBuffer = new unsigned char [width * height * 4 * MESA_CHANNEL_SIZE];
|
||||
llassert(mMesaBuffer);
|
||||
|
||||
gMesaBuffer = (U16*)mMesaBuffer;
|
||||
|
||||
/* Bind the buffer to the context and make it current */
|
||||
if (!OSMesaMakeCurrent( mMesaContext, mMesaBuffer, MESA_CHANNEL_TYPE, width, height ))
|
||||
{
|
||||
llinfos << "MESA Init" << llendl;
|
||||
mMesaContext = OSMesaCreateContextExt( GL_RGBA, 32, 0, 0, NULL );
|
||||
|
||||
/* Allocate the image buffer */
|
||||
mMesaBuffer = new unsigned char [width * height * 4 * MESA_CHANNEL_SIZE];
|
||||
llassert(mMesaBuffer);
|
||||
|
||||
gMesaBuffer = (U16*)mMesaBuffer;
|
||||
|
||||
/* Bind the buffer to the context and make it current */
|
||||
if (!OSMesaMakeCurrent( mMesaContext, mMesaBuffer, MESA_CHANNEL_TYPE, width, height ))
|
||||
{
|
||||
llerrs << "MESA: OSMesaMakeCurrent failed!" << llendl;
|
||||
}
|
||||
|
||||
llverify(gGLManager.initGL());
|
||||
llerrs << "MESA: OSMesaMakeCurrent failed!" << llendl;
|
||||
}
|
||||
|
||||
llverify(gGLManager.initGL());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -50,7 +50,8 @@ public:
|
||||
/*virtual*/ BOOL getSize(LLCoordScreen *size) {return FALSE;};
|
||||
/*virtual*/ BOOL getSize(LLCoordWindow *size) {return FALSE;};
|
||||
/*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;};
|
||||
/*virtual*/ BOOL setSize(LLCoordScreen size) {return FALSE;};
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordScreen size) {return FALSE;};
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordWindow size) {return FALSE;};
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;};
|
||||
/*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;};
|
||||
/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;};
|
||||
@@ -97,7 +98,7 @@ public:
|
||||
LLWindowMesaHeadless(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height,
|
||||
U32 flags, BOOL fullscreen, BOOL clearBg,
|
||||
BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth);
|
||||
BOOL disable_vsync, BOOL ignore_pixel_depth);
|
||||
~LLWindowMesaHeadless();
|
||||
|
||||
private:
|
||||
|
||||
@@ -189,7 +189,7 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, S32 x, S32 y, S32 width,
|
||||
S32 height, U32 flags,
|
||||
BOOL fullscreen, BOOL clearBg,
|
||||
BOOL disable_vsync, BOOL use_gl,
|
||||
BOOL disable_vsync,
|
||||
BOOL ignore_pixel_depth, U32 fsaa_samples)
|
||||
: LLWindow(callbacks, fullscreen, flags),
|
||||
Lock_Display(NULL),
|
||||
@@ -200,7 +200,6 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks,
|
||||
gKeyboard->setCallbacks(callbacks);
|
||||
// Note that we can't set up key-repeat until after SDL has init'd video
|
||||
|
||||
// Ignore use_gl for now, only used for drones on PC
|
||||
mWindow = NULL;
|
||||
mNeedsResize = FALSE;
|
||||
mOverrideAspectRatio = 0.f;
|
||||
@@ -975,7 +974,7 @@ BOOL LLWindowSDL::setPosition(const LLCoordScreen position)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LLWindowSDL::setSize(const LLCoordScreen size)
|
||||
BOOL LLWindowSDL::setSizeImpl(const LLCoordScreen size)
|
||||
{
|
||||
if(mWindow)
|
||||
{
|
||||
@@ -993,6 +992,25 @@ BOOL LLWindowSDL::setSize(const LLCoordScreen size)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LLWindowSDL::setSizeImpl(const LLCoordWindow size)
|
||||
{
|
||||
if(mWindow)
|
||||
{
|
||||
// Push a resize event onto SDL's queue - we'll handle it
|
||||
// when it comes out again.
|
||||
SDL_Event event;
|
||||
event.type = SDL_VIDEORESIZE;
|
||||
event.resize.w = size.mX;
|
||||
event.resize.h = size.mY;
|
||||
SDL_PushEvent(&event); // copied into queue
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void LLWindowSDL::swapBuffers()
|
||||
{
|
||||
if (mWindow)
|
||||
@@ -1045,6 +1063,25 @@ void LLWindowSDL::setMouseClipping( BOOL b )
|
||||
//SDL_WM_GrabInput(b ? SDL_GRAB_ON : SDL_GRAB_OFF);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLWindowSDL::setMinSize(U32 min_width, U32 min_height, bool enforce_immediately)
|
||||
{
|
||||
LLWindow::setMinSize(min_width, min_height, enforce_immediately);
|
||||
|
||||
#if LL_X11
|
||||
// Set the minimum size limits for X11 window
|
||||
// so the window manager doesn't allow resizing below those limits.
|
||||
XSizeHints* hints = XAllocSizeHints();
|
||||
hints->flags |= PMinSize;
|
||||
hints->min_width = mMinWindowWidth;
|
||||
hints->min_height = mMinWindowHeight;
|
||||
|
||||
XSetWMNormalHints(mSDL_Display, mSDL_XWindowID, hints);
|
||||
|
||||
XFree(hints);
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL LLWindowSDL::setCursorPosition(const LLCoordWindow position)
|
||||
{
|
||||
BOOL result = TRUE;
|
||||
@@ -1859,8 +1896,8 @@ void LLWindowSDL::gatherInput()
|
||||
llinfos << "Handling a resize event: " << event.resize.w <<
|
||||
"x" << event.resize.h << llendl;
|
||||
|
||||
S32 width = llmax(event.resize.w, MIN_WINDOW_WIDTH);
|
||||
S32 height = llmax(event.resize.h, MIN_WINDOW_HEIGHT);
|
||||
S32 width = llmax(event.resize.w, (S32)mMinWindowWidth);
|
||||
S32 height = llmax(event.resize.h, (S32)mMinWindowHeight);
|
||||
|
||||
if (width != mWindow->w || height != mWindow->h)
|
||||
{
|
||||
@@ -2488,6 +2525,23 @@ void exec_cmd(const std::string& cmd, const std::string& arg)
|
||||
// Must begin with protocol identifier.
|
||||
void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async)
|
||||
{
|
||||
bool found = false;
|
||||
S32 i;
|
||||
for (i = 0; i < gURLProtocolWhitelistCount; i++)
|
||||
{
|
||||
if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
llwarns << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
llinfos << "spawn_web_browser: " << escaped_url << llendl;
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
@@ -2623,9 +2677,9 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()
|
||||
if (sortpat)
|
||||
{
|
||||
// Sort the list of system fonts from most-to-least-desirable.
|
||||
FcResult fresult;
|
||||
FcResult result;
|
||||
fs = FcFontSort(NULL, sortpat, elide_unicode_coverage,
|
||||
NULL, &fresult);
|
||||
NULL, &result);
|
||||
FcPatternDestroy(sortpat);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,8 @@ public:
|
||||
/*virtual*/ BOOL getSize(LLCoordScreen *size);
|
||||
/*virtual*/ BOOL getSize(LLCoordWindow *size);
|
||||
/*virtual*/ BOOL setPosition(LLCoordScreen position);
|
||||
/*virtual*/ BOOL setSize(LLCoordScreen size);
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordScreen size);
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordWindow size);
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL);
|
||||
/*virtual*/ BOOL setCursorPosition(LLCoordWindow position);
|
||||
/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position);
|
||||
@@ -76,6 +77,7 @@ public:
|
||||
/*virtual*/ void captureMouse();
|
||||
/*virtual*/ void releaseMouse();
|
||||
/*virtual*/ void setMouseClipping( BOOL b );
|
||||
/*virtual*/ void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true);
|
||||
|
||||
/*virtual*/ BOOL isClipboardTextAvailable();
|
||||
/*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst);
|
||||
@@ -147,7 +149,7 @@ public:
|
||||
protected:
|
||||
LLWindowSDL(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, int x, int y, int width, int height, U32 flags,
|
||||
BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl,
|
||||
BOOL fullscreen, BOOL clearBg, BOOL disable_vsync,
|
||||
BOOL ignore_pixel_depth, U32 fsaa_samples);
|
||||
~LLWindowSDL();
|
||||
|
||||
|
||||
@@ -363,11 +363,15 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
|
||||
S32 height, U32 flags,
|
||||
BOOL fullscreen, BOOL clearBg,
|
||||
BOOL disable_vsync, BOOL use_gl,
|
||||
BOOL disable_vsync,
|
||||
BOOL ignore_pixel_depth,
|
||||
U32 fsaa_samples)
|
||||
: LLWindow(callbacks, fullscreen, flags)
|
||||
{
|
||||
|
||||
//MAINT-516 -- force a load of opengl32.dll just in case windows went sideways
|
||||
LoadLibrary(L"opengl32.dll");
|
||||
|
||||
mFSAASamples = fsaa_samples;
|
||||
mIconResource = gIconResource;
|
||||
mOverrideAspectRatio = 0.f;
|
||||
@@ -860,13 +864,11 @@ BOOL LLWindowWin32::setPosition(const LLCoordScreen position)
|
||||
return FALSE;
|
||||
}
|
||||
getSize(&size);
|
||||
|
||||
moveWindow(position, size);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LLWindowWin32::setSize(const LLCoordScreen size)
|
||||
BOOL LLWindowWin32::setSizeImpl(const LLCoordScreen size)
|
||||
{
|
||||
LLCoordScreen position;
|
||||
|
||||
@@ -876,11 +878,30 @@ BOOL LLWindowWin32::setSize(const LLCoordScreen size)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
moveWindow(position, size);
|
||||
WINDOWPLACEMENT placement;
|
||||
placement.length = sizeof(WINDOWPLACEMENT);
|
||||
|
||||
if (!GetWindowPlacement(mWindowHandle, &placement)) return FALSE;
|
||||
|
||||
placement.showCmd = SW_RESTORE;
|
||||
|
||||
if (!SetWindowPlacement(mWindowHandle, &placement)) return FALSE;
|
||||
|
||||
moveWindow(position, size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LLWindowWin32::setSizeImpl(const LLCoordWindow size)
|
||||
{
|
||||
RECT window_rect = {0, 0, size.mX, size.mY };
|
||||
DWORD dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
|
||||
DWORD dw_style = WS_OVERLAPPEDWINDOW;
|
||||
|
||||
AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style);
|
||||
|
||||
return setSizeImpl(LLCoordScreen(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top));
|
||||
}
|
||||
|
||||
// changing fullscreen resolution
|
||||
BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)
|
||||
{
|
||||
@@ -891,12 +912,12 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
|
||||
DWORD current_refresh;
|
||||
DWORD dw_ex_style;
|
||||
DWORD dw_style;
|
||||
RECT window_rect;
|
||||
RECT window_rect = {0, 0, 0, 0};
|
||||
S32 width = size.mX;
|
||||
S32 height = size.mY;
|
||||
BOOL auto_show = FALSE;
|
||||
|
||||
if (mhRC)
|
||||
if (mhRC)
|
||||
{
|
||||
auto_show = TRUE;
|
||||
resetDisplayResolution();
|
||||
@@ -1093,6 +1114,37 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// (EXP-1765) dump pixel data to see if there is a pattern that leads to unreproducible crash
|
||||
LL_INFOS("Window") << "--- begin pixel format dump ---" << llendl ;
|
||||
LL_INFOS("Window") << "pixel_format is " << pixel_format << llendl ;
|
||||
LL_INFOS("Window") << "pfd.nSize: " << pfd.nSize << llendl ;
|
||||
LL_INFOS("Window") << "pfd.nVersion: " << pfd.nVersion << llendl ;
|
||||
LL_INFOS("Window") << "pfd.dwFlags: 0x" << std::hex << pfd.dwFlags << std::dec << llendl ;
|
||||
LL_INFOS("Window") << "pfd.iPixelType: " << (int)pfd.iPixelType << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cColorBits: " << (int)pfd.cColorBits << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cRedBits: " << (int)pfd.cRedBits << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cRedShift: " << (int)pfd.cRedShift << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cGreenBits: " << (int)pfd.cGreenBits << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cGreenShift: " << (int)pfd.cGreenShift << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cBlueBits: " << (int)pfd.cBlueBits << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cBlueShift: " << (int)pfd.cBlueShift << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cAlphaBits: " << (int)pfd.cAlphaBits << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cAlphaShift: " << (int)pfd.cAlphaShift << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cAccumBits: " << (int)pfd.cAccumBits << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cAccumRedBits: " << (int)pfd.cAccumRedBits << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cAccumGreenBits: " << (int)pfd.cAccumGreenBits << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cAccumBlueBits: " << (int)pfd.cAccumBlueBits << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cAccumAlphaBits: " << (int)pfd.cAccumAlphaBits << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cDepthBits: " << (int)pfd.cDepthBits << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cStencilBits: " << (int)pfd.cStencilBits << llendl ;
|
||||
LL_INFOS("Window") << "pfd.cAuxBuffers: " << (int)pfd.cAuxBuffers << llendl ;
|
||||
LL_INFOS("Window") << "pfd.iLayerType: " << (int)pfd.iLayerType << llendl ;
|
||||
LL_INFOS("Window") << "pfd.bReserved: " << (int)pfd.bReserved << llendl ;
|
||||
LL_INFOS("Window") << "pfd.dwLayerMask: " << pfd.dwLayerMask << llendl ;
|
||||
LL_INFOS("Window") << "pfd.dwVisibleMask: " << pfd.dwVisibleMask << llendl ;
|
||||
LL_INFOS("Window") << "pfd.dwDamageMask: " << pfd.dwDamageMask << llendl ;
|
||||
LL_INFOS("Window") << "--- end pixel format dump ---" << llendl ;
|
||||
|
||||
if (pfd.cColorBits < 32)
|
||||
{
|
||||
close();
|
||||
@@ -1564,7 +1616,8 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
|
||||
}
|
||||
else
|
||||
{
|
||||
llinfos << "Created OpenGL " << llformat("%d.%d", attribs[1], attribs[3]) << " context." << llendl;
|
||||
llinfos << "Created OpenGL " << llformat("%d.%d", attribs[1], attribs[3]) <<
|
||||
(LLRender::sGLCoreProfile ? " core" : " compatibility") << " context." << llendl;
|
||||
done = true;
|
||||
|
||||
if (LLRender::sGLCoreProfile)
|
||||
@@ -1675,24 +1728,15 @@ void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScre
|
||||
|
||||
BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position)
|
||||
{
|
||||
LLCoordScreen screen_pos;
|
||||
|
||||
mMousePositionModified = TRUE;
|
||||
if (!mWindowHandle)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!convertCoords(position, &screen_pos))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Inform the application of the new mouse position (needed for per-frame
|
||||
// hover/picking to function).
|
||||
LLCoordGL gl_pos;
|
||||
convertCoords(position, &gl_pos);
|
||||
mCallbacks->handleMouseMove(this, gl_pos, (MASK)0);
|
||||
mCallbacks->handleMouseMove(this, position.convert(), (MASK)0);
|
||||
|
||||
// DEV-18951 VWR-8524 Camera moves wildly when alt-clicking.
|
||||
// Because we have preemptively notified the application of the new
|
||||
@@ -1702,24 +1746,23 @@ BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position)
|
||||
while (PeekMessage(&msg, NULL, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE))
|
||||
{ }
|
||||
|
||||
return SetCursorPos(screen_pos.mX, screen_pos.mY);
|
||||
LLCoordScreen screen_pos(position.convert());
|
||||
return ::SetCursorPos(screen_pos.mX, screen_pos.mY);
|
||||
}
|
||||
|
||||
BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position)
|
||||
{
|
||||
POINT cursor_point;
|
||||
LLCoordScreen screen_pos;
|
||||
|
||||
if (!mWindowHandle ||
|
||||
!GetCursorPos(&cursor_point))
|
||||
if (!mWindowHandle
|
||||
|| !GetCursorPos(&cursor_point)
|
||||
|| !position)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
screen_pos.mX = cursor_point.x;
|
||||
screen_pos.mY = cursor_point.y;
|
||||
|
||||
return convertCoords(screen_pos, position);
|
||||
*position = LLCoordScreen(cursor_point.x, cursor_point.y).convert();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLWindowWin32::hideCursor()
|
||||
@@ -1880,7 +1923,7 @@ void LLWindowWin32::gatherInput()
|
||||
MSG msg;
|
||||
int msg_count = 0;
|
||||
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) && msg_count < MAX_MESSAGE_PER_UPDATE)
|
||||
while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
mCallbacks->handlePingWatchdog(this, "Main:TranslateGatherInput");
|
||||
TranslateMessage(&msg);
|
||||
@@ -1936,6 +1979,10 @@ static LLFastTimer::DeclareTimer FTM_MOUSEHANDLER("Handle Mouse");
|
||||
|
||||
LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param)
|
||||
{
|
||||
// Ignore clicks not originated in the client area, i.e. mouse-up events not preceded with a WM_LBUTTONDOWN.
|
||||
// This helps prevent avatar walking after maximizing the window by double-clicking the title bar.
|
||||
static bool sHandleLeftMouseUp = true;
|
||||
|
||||
LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(h_wnd, GWL_USERDATA);
|
||||
|
||||
|
||||
@@ -2282,10 +2329,20 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
||||
window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE));
|
||||
return 0;
|
||||
|
||||
case WM_NCLBUTTONDOWN:
|
||||
{
|
||||
window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_NCLBUTTONDOWN");
|
||||
// A click in a non-client area, e.g. title bar or window border.
|
||||
sHandleLeftMouseUp = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
{
|
||||
window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN");
|
||||
LLFastTimer t2(FTM_MOUSEHANDLER);
|
||||
sHandleLeftMouseUp = true;
|
||||
|
||||
if (LLWinImm::isAvailable() && window_imp->mPreeditor)
|
||||
{
|
||||
window_imp->interruptLanguageTextInput();
|
||||
@@ -2296,15 +2353,15 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
||||
// If we don't do this, many clicks could get buffered up, and if the
|
||||
// first click changes the cursor position, all subsequent clicks
|
||||
// will occur at the wrong location. JC
|
||||
LLCoordWindow cursor_coord_window;
|
||||
if (window_imp->mMousePositionModified)
|
||||
{
|
||||
LLCoordWindow cursor_coord_window;
|
||||
window_imp->getCursorPosition(&cursor_coord_window);
|
||||
window_imp->convertCoords(cursor_coord_window, &gl_coord);
|
||||
gl_coord = cursor_coord_window.convert();
|
||||
}
|
||||
else
|
||||
{
|
||||
window_imp->convertCoords(window_coord, &gl_coord);
|
||||
gl_coord = window_coord.convert();
|
||||
}
|
||||
MASK mask = gKeyboard->currentMask(TRUE);
|
||||
// generate move event to update mouse coordinates
|
||||
@@ -2326,15 +2383,15 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
||||
// If we don't do this, many clicks could get buffered up, and if the
|
||||
// first click changes the cursor position, all subsequent clicks
|
||||
// will occur at the wrong location. JC
|
||||
LLCoordWindow cursor_coord_window;
|
||||
if (window_imp->mMousePositionModified)
|
||||
{
|
||||
LLCoordWindow cursor_coord_window;
|
||||
window_imp->getCursorPosition(&cursor_coord_window);
|
||||
window_imp->convertCoords(cursor_coord_window, &gl_coord);
|
||||
gl_coord = cursor_coord_window.convert();
|
||||
}
|
||||
else
|
||||
{
|
||||
window_imp->convertCoords(window_coord, &gl_coord);
|
||||
gl_coord = window_coord.convert();
|
||||
}
|
||||
MASK mask = gKeyboard->currentMask(TRUE);
|
||||
// generate move event to update mouse coordinates
|
||||
@@ -2350,6 +2407,13 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
||||
{
|
||||
window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP");
|
||||
LLFastTimer t2(FTM_MOUSEHANDLER);
|
||||
|
||||
if (!sHandleLeftMouseUp)
|
||||
{
|
||||
sHandleLeftMouseUp = true;
|
||||
break;
|
||||
}
|
||||
|
||||
//if (gDebugClicks)
|
||||
//{
|
||||
// LL_INFOS("Window") << "WndProc left button up" << LL_ENDL;
|
||||
@@ -2359,15 +2423,15 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
||||
// If we don't do this, many clicks could get buffered up, and if the
|
||||
// first click changes the cursor position, all subsequent clicks
|
||||
// will occur at the wrong location. JC
|
||||
LLCoordWindow cursor_coord_window;
|
||||
if (window_imp->mMousePositionModified)
|
||||
{
|
||||
LLCoordWindow cursor_coord_window;
|
||||
window_imp->getCursorPosition(&cursor_coord_window);
|
||||
window_imp->convertCoords(cursor_coord_window, &gl_coord);
|
||||
gl_coord = cursor_coord_window.convert();
|
||||
}
|
||||
else
|
||||
{
|
||||
window_imp->convertCoords(window_coord, &gl_coord);
|
||||
gl_coord = window_coord.convert();
|
||||
}
|
||||
MASK mask = gKeyboard->currentMask(TRUE);
|
||||
// generate move event to update mouse coordinates
|
||||
@@ -2394,15 +2458,15 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
||||
// If we don't do this, many clicks could get buffered up, and if the
|
||||
// first click changes the cursor position, all subsequent clicks
|
||||
// will occur at the wrong location. JC
|
||||
LLCoordWindow cursor_coord_window;
|
||||
if (window_imp->mMousePositionModified)
|
||||
{
|
||||
LLCoordWindow cursor_coord_window;
|
||||
window_imp->getCursorPosition(&cursor_coord_window);
|
||||
window_imp->convertCoords(cursor_coord_window, &gl_coord);
|
||||
gl_coord = cursor_coord_window.convert();
|
||||
}
|
||||
else
|
||||
{
|
||||
window_imp->convertCoords(window_coord, &gl_coord);
|
||||
gl_coord = window_coord.convert();
|
||||
}
|
||||
MASK mask = gKeyboard->currentMask(TRUE);
|
||||
// generate move event to update mouse coordinates
|
||||
@@ -2423,15 +2487,15 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
||||
// If we don't do this, many clicks could get buffered up, and if the
|
||||
// first click changes the cursor position, all subsequent clicks
|
||||
// will occur at the wrong location. JC
|
||||
LLCoordWindow cursor_coord_window;
|
||||
if (window_imp->mMousePositionModified)
|
||||
{
|
||||
LLCoordWindow cursor_coord_window;
|
||||
window_imp->getCursorPosition(&cursor_coord_window);
|
||||
window_imp->convertCoords(cursor_coord_window, &gl_coord);
|
||||
gl_coord = cursor_coord_window.convert();
|
||||
}
|
||||
else
|
||||
{
|
||||
window_imp->convertCoords(window_coord, &gl_coord);
|
||||
gl_coord = window_coord.convert();
|
||||
}
|
||||
MASK mask = gKeyboard->currentMask(TRUE);
|
||||
// generate move event to update mouse coordinates
|
||||
@@ -2458,15 +2522,15 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
||||
// If we don't do this, many clicks could get buffered up, and if the
|
||||
// first click changes the cursor position, all subsequent clicks
|
||||
// will occur at the wrong location. JC
|
||||
LLCoordWindow cursor_coord_window;
|
||||
if (window_imp->mMousePositionModified)
|
||||
{
|
||||
LLCoordWindow cursor_coord_window;
|
||||
window_imp->getCursorPosition(&cursor_coord_window);
|
||||
window_imp->convertCoords(cursor_coord_window, &gl_coord);
|
||||
gl_coord = cursor_coord_window.convert();
|
||||
}
|
||||
else
|
||||
{
|
||||
window_imp->convertCoords(window_coord, &gl_coord);
|
||||
gl_coord = window_coord.convert();
|
||||
}
|
||||
MASK mask = gKeyboard->currentMask(TRUE);
|
||||
// generate move event to update mouse coordinates
|
||||
@@ -2487,15 +2551,15 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
||||
// If we don't do this, many clicks could get buffered up, and if the
|
||||
// first click changes the cursor position, all subsequent clicks
|
||||
// will occur at the wrong location. JC
|
||||
LLCoordWindow cursor_coord_window;
|
||||
if (window_imp->mMousePositionModified)
|
||||
{
|
||||
LLCoordWindow cursor_coord_window;
|
||||
window_imp->getCursorPosition(&cursor_coord_window);
|
||||
window_imp->convertCoords(cursor_coord_window, &gl_coord);
|
||||
gl_coord = cursor_coord_window.convert();
|
||||
}
|
||||
else
|
||||
{
|
||||
window_imp->convertCoords(window_coord, &gl_coord);
|
||||
gl_coord = window_coord.convert();
|
||||
}
|
||||
MASK mask = gKeyboard->currentMask(TRUE);
|
||||
// generate move event to update mouse coordinates
|
||||
@@ -2567,17 +2631,16 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
||||
case WM_MOUSEMOVE:
|
||||
{
|
||||
window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEMOVE");
|
||||
window_imp->convertCoords(window_coord, &gl_coord);
|
||||
MASK mask = gKeyboard->currentMask(TRUE);
|
||||
window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
|
||||
window_imp->mCallbacks->handleMouseMove(window_imp, window_coord.convert(), mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_GETMINMAXINFO:
|
||||
{
|
||||
LPMINMAXINFO min_max = (LPMINMAXINFO)l_param;
|
||||
min_max->ptMinTrackSize.x = MIN_WINDOW_WIDTH;
|
||||
min_max->ptMinTrackSize.y = MIN_WINDOW_HEIGHT;
|
||||
min_max->ptMinTrackSize.x = window_imp->mMinWindowWidth;
|
||||
min_max->ptMinTrackSize.y = window_imp->mMinWindowHeight;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3483,7 +3546,7 @@ void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position )
|
||||
|
||||
LLWinImm::setCompositionWindow( himc, &ime_form );
|
||||
|
||||
sWinIMEWindowPosition.set( win_pos.mX, win_pos.mY );
|
||||
sWinIMEWindowPosition = win_pos;
|
||||
}
|
||||
|
||||
LLWinImm::releaseContext(mWindowHandle, himc);
|
||||
|
||||
@@ -57,7 +57,8 @@ public:
|
||||
/*virtual*/ BOOL getSize(LLCoordScreen *size);
|
||||
/*virtual*/ BOOL getSize(LLCoordWindow *size);
|
||||
/*virtual*/ BOOL setPosition(LLCoordScreen position);
|
||||
/*virtual*/ BOOL setSize(LLCoordScreen size);
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordScreen size);
|
||||
/*virtual*/ BOOL setSizeImpl(LLCoordWindow size);
|
||||
/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL);
|
||||
/*virtual*/ BOOL setCursorPosition(LLCoordWindow position);
|
||||
/*virtual*/ BOOL getCursorPosition(LLCoordWindow *position);
|
||||
@@ -120,7 +121,7 @@ public:
|
||||
protected:
|
||||
LLWindowWin32(LLWindowCallbacks* callbacks,
|
||||
const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,
|
||||
BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl,
|
||||
BOOL fullscreen, BOOL clearBg, BOOL disable_vsync,
|
||||
BOOL ignore_pixel_depth, U32 fsaa_samples);
|
||||
~LLWindowWin32();
|
||||
|
||||
|
||||
@@ -1133,9 +1133,7 @@ void *updatethreadproc(void*)
|
||||
|
||||
llinfos << "Clearing cache..." << llendl;
|
||||
|
||||
char mask[LL_MAX_PATH]; /* Flawfinder: ignore */
|
||||
snprintf(mask, LL_MAX_PATH, "%s*.*", gDirUtilp->getDirDelimiter().c_str());
|
||||
gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);
|
||||
gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),"*.*");
|
||||
|
||||
llinfos << "Clear complete." << llendl;
|
||||
|
||||
|
||||
@@ -222,7 +222,6 @@ set(viewer_SOURCE_FILES
|
||||
llfloaterlandholdings.cpp
|
||||
llfloaterlandmark.cpp
|
||||
llfloatermap.cpp
|
||||
llfloatermediabrowser.cpp
|
||||
llfloatermemleak.cpp
|
||||
llfloatermessagelog.cpp
|
||||
llfloatermodelpreview.cpp
|
||||
@@ -262,6 +261,7 @@ set(viewer_SOURCE_FILES
|
||||
llfloaterurldisplay.cpp
|
||||
llfloaterurlentry.cpp
|
||||
llfloaterwater.cpp
|
||||
llfloaterwebcontent.cpp
|
||||
llfloaterwindlight.cpp
|
||||
llfloaterworldmap.cpp
|
||||
llfolderview.cpp
|
||||
@@ -317,6 +317,7 @@ set(viewer_SOURCE_FILES
|
||||
llmarketplacefunctions.cpp
|
||||
llmarketplacenotifications.cpp
|
||||
llmediactrl.cpp
|
||||
llmediadataclient.cpp
|
||||
llmediaremotectrl.cpp
|
||||
llmenucommands.cpp
|
||||
llmenuoptionpathfindingrebakenavmesh.cpp
|
||||
@@ -367,7 +368,6 @@ set(viewer_SOURCE_FILES
|
||||
llpanellogin.cpp
|
||||
llpanelmaininventory.cpp
|
||||
llpanelmarketplaceoutboxinventory.cpp
|
||||
llpanelmediahud.cpp
|
||||
llpanelmorph.cpp
|
||||
llpanelmsgs.cpp
|
||||
llpanelnetwork.cpp
|
||||
@@ -376,6 +376,7 @@ set(viewer_SOURCE_FILES
|
||||
llpanelpermissions.cpp
|
||||
llpanelpick.cpp
|
||||
llpanelplace.cpp
|
||||
llpanelprimmediacontrols.cpp
|
||||
llpanelprofile.cpp
|
||||
llpanelskins.cpp
|
||||
llpanelvoicedevicesettings.cpp
|
||||
@@ -417,6 +418,7 @@ set(viewer_SOURCE_FILES
|
||||
llscrollingpanelparambase.cpp
|
||||
llselectmgr.cpp
|
||||
llsky.cpp
|
||||
llslurl.cpp
|
||||
llspatialpartition.cpp
|
||||
llspeakers.cpp
|
||||
llsprite.cpp
|
||||
@@ -459,7 +461,6 @@ set(viewer_SOURCE_FILES
|
||||
llurl.cpp
|
||||
llurldispatcher.cpp
|
||||
llurlhistory.cpp
|
||||
llurlsimstring.cpp
|
||||
llurlwhitelist.cpp
|
||||
lluserauth.cpp
|
||||
llvectorperfoptions.cpp
|
||||
@@ -485,9 +486,7 @@ set(viewer_SOURCE_FILES
|
||||
llviewerlayer.cpp
|
||||
llviewermedia.cpp
|
||||
llviewermedia_streamingaudio.cpp
|
||||
llviewermediaeventemitter.cpp
|
||||
llviewermediafocus.cpp
|
||||
llviewermediaobserver.cpp
|
||||
llviewermenu.cpp
|
||||
llviewermenufile.cpp
|
||||
llviewermessage.cpp
|
||||
@@ -727,7 +726,6 @@ set(viewer_HEADER_FILES
|
||||
llfloaterlandholdings.h
|
||||
llfloaterlandmark.h
|
||||
llfloatermap.h
|
||||
llfloatermediabrowser.h
|
||||
llfloatermemleak.h
|
||||
llfloatermessagelog.h
|
||||
llfloatermodelpreview.h
|
||||
@@ -767,6 +765,7 @@ set(viewer_HEADER_FILES
|
||||
llfloaterurldisplay.h
|
||||
llfloaterurlentry.h
|
||||
llfloaterwater.h
|
||||
llfloaterwebcontent.h
|
||||
llfloaterwindlight.h
|
||||
llfloaterworldmap.h
|
||||
llfolderview.h
|
||||
@@ -822,6 +821,7 @@ set(viewer_HEADER_FILES
|
||||
llmarketplacefunctions.h
|
||||
llmarketplacenotifications.h
|
||||
llmediactrl.h
|
||||
llmediadataclient.h
|
||||
llmediaremotectrl.h
|
||||
llmenucommands.h
|
||||
llmenuoptionpathfindingrebakenavmesh.h
|
||||
@@ -872,7 +872,6 @@ set(viewer_HEADER_FILES
|
||||
llpanellogin.h
|
||||
llpanelmaininventory.h
|
||||
llpanelmarketplaceoutboxinventory.h
|
||||
llpanelmediahud.h
|
||||
llpanelmorph.h
|
||||
llpanelmsgs.h
|
||||
llpanelnetwork.h
|
||||
@@ -881,6 +880,7 @@ set(viewer_HEADER_FILES
|
||||
llpanelpermissions.h
|
||||
llpanelpick.h
|
||||
llpanelplace.h
|
||||
llpanelprimmediacontrols.h
|
||||
llpanelprofile.h
|
||||
llpanelskins.h
|
||||
llpanelvoicedevicesettings.h
|
||||
@@ -924,6 +924,7 @@ set(viewer_HEADER_FILES
|
||||
llselectmgr.h
|
||||
llsimplestat.h
|
||||
llsky.h
|
||||
llslurl.h
|
||||
llspatialpartition.h
|
||||
llspeakers.h
|
||||
llsprite.h
|
||||
@@ -969,7 +970,6 @@ set(viewer_HEADER_FILES
|
||||
llurl.h
|
||||
llurldispatcher.h
|
||||
llurlhistory.h
|
||||
llurlsimstring.h
|
||||
llurlwhitelist.h
|
||||
lluserauth.h
|
||||
llvectorperfoptions.h
|
||||
@@ -994,9 +994,7 @@ set(viewer_HEADER_FILES
|
||||
llviewerkeyboard.h
|
||||
llviewerlayer.h
|
||||
llviewermedia.h
|
||||
llviewermediaeventemitter.h
|
||||
llviewermediafocus.h
|
||||
llviewermediaobserver.h
|
||||
llviewermenu.h
|
||||
llviewermenufile.h
|
||||
llviewermessage.h
|
||||
|
||||
@@ -2235,6 +2235,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>0.075</real>
|
||||
</map>
|
||||
<key>AudioStreamingMedia</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable streaming</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>AudioStreamingMusic</key>
|
||||
<map>
|
||||
@@ -2247,17 +2258,6 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>AudioStreamingVideo</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable streaming video</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>AuditTexture</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -2702,23 +2702,23 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>PluginAttachDebuggerToPlugins</key>
|
||||
<key>BrowserEnableJSObject</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Opens a terminal window with a debugger and attach it, every time a new SLPlugin process is started.</string>
|
||||
<string>(WARNING: Advanced feature. Use if you are aware of the implications). Enable or disable the viewer to Javascript bridge object.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>BlockAvatarAppearanceMessages</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Ignores appearance messages (for simulating Ruth)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Ignores appearance messages (for simulating Ruth)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
@@ -3780,17 +3780,6 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<string/>
|
||||
</array>
|
||||
</map>
|
||||
<key>CmdLineRegionURI</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>URL of region to connect to through Agent Domain.</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string/>
|
||||
</map>
|
||||
<key>ColorPaletteEntry01</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -5430,6 +5419,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>DisableExternalBrowser</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Disable opening an external browser.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>DisableRendering</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -5441,6 +5441,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>DisableTextHyperlinkActions</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Disable highlighting and linking of URLs in XUI text boxes</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>DisableVerticalSync</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -6014,17 +6025,6 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>FirstLoginThisInstall</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Specifies that you have not successfully logged in since you installed the latest update</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>FirstName</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -6069,6 +6069,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>FirstLoginThisInstall</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Specifies that you have not successfully logged in since you installed the latest update</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>FixedWeather</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -9109,16 +9120,16 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>LoginLastLocation</key>
|
||||
<key>LoginLocation</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Login at same location you last logged out</string>
|
||||
<string>Default Login location ('last', 'home') preference</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
<string>last</string>
|
||||
</map>
|
||||
<key>LoginPage</key>
|
||||
<map>
|
||||
@@ -9435,13 +9446,68 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>MemoryFailurePreventionEnabled</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>MediaPerformanceManagerDebug</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether to show debug data for the media performance manager in the nearby media list.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>MediaShowOnOthers</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether or not to show media on other avatars</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>MediaShowOutsideParcel</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether or not to show media from outside the current parcel</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>MediaShowWithinParcel</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether or not to show media within the current parcel</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>MediaTentativeAutoPlay</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>This is a tentative flag that may be temporarily set off by the user, until she teleports</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>MemoryFailurePreventionEnabled</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>If set, the viewer will quit to avoid crash when memory failure happens</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
@@ -10426,6 +10492,86 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>PluginAttachDebuggerToPlugins</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>If true, attach a debugger session to each plugin process as it's launched.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>PluginInstancesCPULimit</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Amount of total plugin CPU usage before inworld plugins start getting turned down to "slideshow" priority. Set to 0 to disable this check.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>0.9</real>
|
||||
</map>
|
||||
|
||||
<key>PlainTextChatHistory</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable/Disable plain text chat history style</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
|
||||
<key>PluginInstancesLow</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Limit on the number of inworld media plugins that will run at "low" priority</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>4</integer>
|
||||
</map>
|
||||
<key>PluginInstancesNormal</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Limit on the number of inworld media plugins that will run at "normal" or higher priority</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>2</integer>
|
||||
</map>
|
||||
<key>PluginInstancesTotal</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Hard limit on the number of plugins that will be instantiated at once for inworld media</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>8</integer>
|
||||
</map>
|
||||
|
||||
<key>PluginUseReadThread</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Use a separate thread to read incoming messages from plugins</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>PlayTypingSound</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -10629,6 +10775,94 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
</array>
|
||||
</map>
|
||||
|
||||
<key>PrimMediaMasterEnabled</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether or not Media on a Prim is enabled.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>PrimMediaControlsUseHoverControlSet</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether or not hovering over prim media uses minimal "hover" controls or the authored control set.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>PrimMediaDragNDrop</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable drag and drop of URLs onto prim faces</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>PrimMediaMaxRetries</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Maximum number of retries for media queries.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>4</integer>
|
||||
</map>
|
||||
<key>PrimMediaRequestQueueDelay</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Timer delay for fetching media from the queue (in seconds).</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>1.0</real>
|
||||
</map>
|
||||
<key>PrimMediaRetryTimerDelay</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Timer delay for retrying on media queries (in seconds).</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>5.0</real>
|
||||
</map>
|
||||
<key>PrimMediaMaxSortedQueueSize</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Maximum number of objects the viewer will load media for initially</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>100000</integer>
|
||||
</map>
|
||||
<key>PrimMediaMaxRoundRobinQueueSize</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Maximum number of objects the viewer will continuously update media for</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>100000</integer>
|
||||
</map>
|
||||
<key>PreviewAnimRect</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -10937,6 +11171,50 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<real>1.0</real>
|
||||
</map>
|
||||
<key>WebContentWindowLimit</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Maximum number of web browser windows that can be open at once in the Web content floater (0 for no limit)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>5</integer>
|
||||
</map>
|
||||
<key>MediaRollOffRate</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Multiplier to change rate of media attenuation</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>0.125</real>
|
||||
</map>
|
||||
<key>MediaRollOffMin</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Adjusts the distance at which media attentuation starts</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>5.0</real>
|
||||
</map>
|
||||
<key>MediaRollOffMax</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Distance at which media volume is set to 0</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>30.0</real>
|
||||
</map>
|
||||
<key>RecentItemsSortOrder</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -16551,6 +16829,28 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>SLURLDragNDrop</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable drag and drop of SLURLs onto the viewer</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>SLURLPassToOtherInstance</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Pass execution to prevoius viewer instances if there is a given slurl</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>soundsbeacon</key>
|
||||
<map>
|
||||
@@ -16629,6 +16929,19 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>180</integer>
|
||||
</map>
|
||||
|
||||
<key>SLURLTeleportDirectly</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Clicking on a slurl will teleport you directly instead of opening places panel</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
|
||||
<key>UseHTTPInventory</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
||||
@@ -41,6 +41,17 @@
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SHEnableFMODEXVerboseDebugging</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable profiler tool if using FMOD Ex</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SHFMODExStreamBufferSize</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
||||
@@ -60,6 +60,8 @@
|
||||
#include "lltooldraganddrop.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "llselectmgr.h"
|
||||
#include "llslurl.h"
|
||||
#include "llurlaction.h"
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
@@ -374,7 +376,6 @@ bool cmd_line_chat(std::string revised_text, EChatType type)
|
||||
S32 agent_y = llround( (F32)fmod( agentPos.mdV[VY], (F64)REGION_WIDTH_METERS ) );
|
||||
S32 agent_z = llround( (F32)agentPos.mdV[VZ] );
|
||||
std::string region_name = LLWeb::escapeURL(revised_text.substr(command.length()+1));
|
||||
std::string url;
|
||||
|
||||
if(!sAscentCmdLineMapToKeepPos)
|
||||
{
|
||||
@@ -383,8 +384,8 @@ bool cmd_line_chat(std::string revised_text, EChatType type)
|
||||
agent_z = 0;
|
||||
}
|
||||
|
||||
url = llformat("secondlife:///app/teleport/%s/%d/%d/%d",region_name.c_str(),agent_x,agent_y,agent_z);
|
||||
LLURLDispatcher::dispatch(url, NULL, true);
|
||||
LLSLURL slurl(region_name,LLVector3(agent_x,agent_y,agent_z));
|
||||
LLUrlAction::teleportToLocation(std::string("secondlife:///app/teleport/")+slurl.getLocationString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
#include "llsdmessage.h"
|
||||
#include "llsdutil.h"
|
||||
#include "llsky.h"
|
||||
#include "llslurl.h"
|
||||
#include "llsmoothstep.h"
|
||||
#include "llspeakers.h"
|
||||
#include "llstartup.h"
|
||||
@@ -65,6 +66,8 @@
|
||||
#include "lltoolpie.h"
|
||||
#include "lltoolmgr.h"
|
||||
#include "lltrans.h"
|
||||
#include "lluictrl.h"
|
||||
#include "llurlentry.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llviewerdisplay.h"
|
||||
#include "llviewerjoystick.h"
|
||||
@@ -345,6 +348,7 @@ LLAgent::LLAgent() :
|
||||
mAgentAccess(new LLAgentAccess(gSavedSettings)),
|
||||
mGodLevelChangeSignal(),
|
||||
mCanEditParcel(false),
|
||||
mTeleportSourceSLURL(new LLSLURL),
|
||||
mTeleportRequest(),
|
||||
mTeleportFinishedSlot(),
|
||||
mTeleportFailedSlot(),
|
||||
@@ -485,6 +489,8 @@ LLAgent::~LLAgent()
|
||||
mAgentAccess = NULL;
|
||||
delete mEffectColor;
|
||||
mEffectColor = NULL;
|
||||
delete mTeleportSourceSLURL;
|
||||
mTeleportSourceSLURL = NULL;
|
||||
}
|
||||
|
||||
// Handle any actions that need to be performed when the main app gains focus
|
||||
@@ -949,24 +955,6 @@ const LLHost& LLAgent::getRegionHost() const
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// getSLURL()
|
||||
// returns empty() if getRegion() == NULL
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string LLAgent::getSLURL() const
|
||||
{
|
||||
std::string slurl;
|
||||
LLViewerRegion *regionp = getRegion();
|
||||
if (regionp)
|
||||
{
|
||||
LLVector3d agentPos = getPositionGlobal();
|
||||
S32 x = llround( (F32)fmod( agentPos.mdV[VX], (F64)REGION_WIDTH_METERS ) );
|
||||
S32 y = llround( (F32)fmod( agentPos.mdV[VY], (F64)REGION_WIDTH_METERS ) );
|
||||
S32 z = llround( (F32)agentPos.mdV[VZ] );
|
||||
slurl = LLURLDispatcher::buildSLURL(regionp->getName(), x, y, z);
|
||||
}
|
||||
return slurl;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// inPrelude()
|
||||
@@ -3916,7 +3904,7 @@ bool LLAgent::teleportCore(bool is_local)
|
||||
LLFloaterLand::hideInstance();
|
||||
|
||||
LLViewerParcelMgr::getInstance()->deselectLand();
|
||||
LLViewerMediaFocus::getInstance()->setFocusFace(false, NULL, 0, NULL);
|
||||
LLViewerMediaFocus::getInstance()->clearFocus();
|
||||
|
||||
// Close all pie menus, deselect land, etc.
|
||||
// Don't change the camera until we know teleport succeeded. JC
|
||||
@@ -4308,7 +4296,7 @@ void LLAgent::setTeleportState(ETeleportState state)
|
||||
|
||||
case TELEPORT_MOVING:
|
||||
// We're outa here. Save "back" slurl.
|
||||
mTeleportSourceSLURL = getSLURL();
|
||||
LLAgentUI::buildSLURL(*mTeleportSourceSLURL);
|
||||
break;
|
||||
|
||||
case TELEPORT_ARRIVING:
|
||||
@@ -4734,6 +4722,10 @@ void LLAgent::parseTeleportMessages(const std::string& xml_filename)
|
||||
}//end for (all message sets in xml file)
|
||||
}
|
||||
|
||||
const void LLAgent::getTeleportSourceSLURL(LLSLURL& slurl) const
|
||||
{
|
||||
slurl = *mTeleportSourceSLURL;
|
||||
}
|
||||
|
||||
void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& directory_visibility )
|
||||
{
|
||||
@@ -4787,14 +4779,13 @@ void LLAgent::renderAutoPilotTarget()
|
||||
}
|
||||
}
|
||||
|
||||
void LLAgent::showLureDestination(const std::string fromname, const int global_x, const int global_y, const int x, const int y, const int z, const std::string maturity)
|
||||
void LLAgent::showLureDestination(const std::string fromname, U64& handle, U32 x, U32 y, U32 z)
|
||||
{
|
||||
const LLVector3d posglobal = LLVector3d(F64(global_x), F64(global_y), F64(0));
|
||||
LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromPosGlobal(posglobal);
|
||||
LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
|
||||
|
||||
if(mPendingLure)
|
||||
delete mPendingLure;
|
||||
mPendingLure = new SHLureRequest(fromname,posglobal,x,y,z);
|
||||
mPendingLure = new SHLureRequest(fromname,handle,x,y,z);
|
||||
|
||||
if(siminfo) //We already have an entry? Go right on to displaying it.
|
||||
{
|
||||
@@ -4802,8 +4793,8 @@ void LLAgent::showLureDestination(const std::string fromname, const int global_x
|
||||
}
|
||||
else
|
||||
{
|
||||
U16 grid_x = (U16)(global_x / REGION_WIDTH_UNITS);
|
||||
U16 grid_y = (U16)(global_y / REGION_WIDTH_UNITS);
|
||||
U32 grid_x, grid_y;
|
||||
grid_from_region_handle(handle,&grid_x,&grid_y);
|
||||
LLWorldMapMessage::getInstance()->sendMapBlockRequest(grid_x, grid_y, grid_x, grid_y, true); //Will call onFoundLureDestination on response
|
||||
}
|
||||
}
|
||||
@@ -4814,7 +4805,7 @@ void LLAgent::onFoundLureDestination(LLSimInfo *siminfo)
|
||||
return;
|
||||
|
||||
if(!siminfo)
|
||||
siminfo = LLWorldMap::getInstance()->simInfoFromPosGlobal(mPendingLure->mPosGlobal);
|
||||
siminfo = LLWorldMap::getInstance()->simInfoFromHandle(mPendingLure->mRegionHandle);
|
||||
if(siminfo)
|
||||
{
|
||||
const std::string sim_name = siminfo->getName();
|
||||
@@ -4823,7 +4814,7 @@ void LLAgent::onFoundLureDestination(LLSimInfo *siminfo)
|
||||
llinfos << mPendingLure->mAvatarName << "'s teleport lure is to " << sim_name << " (" << maturity << ")" << llendl;
|
||||
LLStringUtil::format_map_t args;
|
||||
args["[NAME]"] = mPendingLure->mAvatarName;
|
||||
args["[DESTINATION]"] = LLURLDispatcher::buildSLURL(sim_name, (S32)mPendingLure->mPosLocal[0], (S32)mPendingLure->mPosLocal[1], (S32)mPendingLure->mPosLocal[2] );
|
||||
args["[DESTINATION]"] = LLSLURL(sim_name,mPendingLure->mPosLocal).getSLURLString();
|
||||
std::string msg = LLTrans::getString("TeleportOfferMaturity", args);
|
||||
if (!maturity.empty())
|
||||
{
|
||||
|
||||
@@ -68,6 +68,7 @@ class LLPickInfo;
|
||||
class LLViewerObject;
|
||||
class LLAgentDropGroupViewerNode;
|
||||
class LLAgentAccess;
|
||||
class LLSLURL;
|
||||
class LLSimInfo;
|
||||
class LLTeleportRequest;
|
||||
|
||||
@@ -245,20 +246,18 @@ public:
|
||||
LLViewerRegion *getRegion() const { return mRegionp; }
|
||||
const LLHost& getRegionHost() const;
|
||||
BOOL inPrelude();
|
||||
std::string getSLURL() const; //Return uri for current region
|
||||
|
||||
|
||||
// <edit>
|
||||
struct SHLureRequest
|
||||
{
|
||||
SHLureRequest(const std::string& avatar_name, const LLVector3d& pos_global, const int x, const int y, const int z) :
|
||||
mAvatarName(avatar_name), mPosGlobal(pos_global)
|
||||
{ mPosLocal[0] = x; mPosLocal[1] = y; mPosLocal[2] = z;}
|
||||
SHLureRequest(const std::string& avatar_name, U64& handle, const U32 x, const U32 y, const U32 z) :
|
||||
mAvatarName(avatar_name), mRegionHandle(handle), mPosLocal(x,y,z) {}
|
||||
const std::string mAvatarName;
|
||||
const LLVector3d mPosGlobal;
|
||||
int mPosLocal[3];
|
||||
const U64 mRegionHandle;
|
||||
LLVector3 mPosLocal;
|
||||
};
|
||||
SHLureRequest *mPendingLure;
|
||||
void showLureDestination(const std::string fromname, const int global_x, const int global_y, const int x, const int y, const int z, const std::string maturity);
|
||||
void showLureDestination(const std::string fromname, U64& handle, U32 x, U32 y, U32 z);
|
||||
void onFoundLureDestination(LLSimInfo *siminfo = NULL);
|
||||
// </edit>
|
||||
|
||||
@@ -584,13 +583,14 @@ public:
|
||||
|
||||
public:
|
||||
static void parseTeleportMessages(const std::string& xml_filename);
|
||||
const std::string& getTeleportSourceSLURL() const { return mTeleportSourceSLURL; }
|
||||
const void getTeleportSourceSLURL(LLSLURL& slurl) const;
|
||||
public:
|
||||
// ! TODO ! Define ERROR and PROGRESS enums here instead of exposing the mappings.
|
||||
static std::map<std::string, std::string> sTeleportErrorMessages;
|
||||
static std::map<std::string, std::string> sTeleportProgressMessages;
|
||||
public:
|
||||
std::string mTeleportSourceSLURL; // SLURL where last TP began.
|
||||
private:
|
||||
LLSLURL * mTeleportSourceSLURL; // SLURL where last TP began
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Teleport Actions
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "llviewerregion.h"
|
||||
#include "llviewerparcelmgr.h"
|
||||
#include "llvoavatarself.h"
|
||||
#include "llslurl.h"
|
||||
// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d)
|
||||
#include "rlvhandler.h"
|
||||
// [/RLVa:KB]
|
||||
@@ -48,9 +49,8 @@ void LLAgentUI::buildFullname(std::string& name)
|
||||
name = gAgentAvatarp->getFullname();
|
||||
}
|
||||
|
||||
/*
|
||||
//static
|
||||
void LLAgentUI::buildSLURL(LLSLURL& slurl, const bool escaped /= true/ )
|
||||
void LLAgentUI::buildSLURL(LLSLURL& slurl, const bool escaped /*= true*/)
|
||||
{
|
||||
LLSLURL return_slurl;
|
||||
LLViewerRegion *regionp = gAgent.getRegion();
|
||||
@@ -59,7 +59,7 @@ void LLAgentUI::buildSLURL(LLSLURL& slurl, const bool escaped /= true/ )
|
||||
return_slurl = LLSLURL(regionp->getName(), gAgent.getPositionGlobal());
|
||||
}
|
||||
slurl = return_slurl;
|
||||
}*/
|
||||
}
|
||||
|
||||
//static
|
||||
BOOL LLAgentUI::checkAgentDistance(const LLVector3& pole, F32 radius)
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "llmodaldialog.h"
|
||||
#include "llpumpio.h"
|
||||
#include "llmimetypes.h"
|
||||
#include "llslurl.h"
|
||||
#include "llstartup.h"
|
||||
#include "llfocusmgr.h"
|
||||
#include "llviewerjoystick.h"
|
||||
@@ -80,6 +81,7 @@
|
||||
#include "llvector4a.h"
|
||||
#include "llvoicechannel.h"
|
||||
#include "llvoavatarself.h"
|
||||
#include "llurlmatch.h"
|
||||
#include "llprogressview.h"
|
||||
#include "llvocache.h"
|
||||
#include "llvopartgroup.h"
|
||||
@@ -94,6 +96,8 @@
|
||||
#include "llimagej2c.h"
|
||||
#include "llmemory.h"
|
||||
#include "llprimitive.h"
|
||||
#include "llurlaction.h"
|
||||
#include "llurlentry.h"
|
||||
#include "llnotifications.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include <boost/bind.hpp>
|
||||
@@ -149,7 +153,6 @@
|
||||
#include "llworld.h"
|
||||
#include "llhudeffecttrail.h"
|
||||
#include "llvectorperfoptions.h"
|
||||
#include "llurlsimstring.h"
|
||||
#include "llwatchdog.h"
|
||||
|
||||
// Included so that constants/settings might be initialized
|
||||
@@ -755,9 +758,11 @@ bool LLAppViewer::init()
|
||||
|
||||
LLWeb::initClass(); // do this after LLUI
|
||||
|
||||
LLTextEditor::setURLCallbacks(&LLWeb::loadURL,
|
||||
&LLURLDispatcher::dispatchFromTextEditor,
|
||||
&LLURLDispatcher::dispatchFromTextEditor);
|
||||
// Provide the text fields with callbacks for opening Urls
|
||||
LLUrlAction::setOpenURLCallback(boost::bind(&LLWeb::loadURL, _1, LLStringUtil::null, LLStringUtil::null));
|
||||
LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null));
|
||||
LLUrlAction::setOpenURLExternalCallback(boost::bind(&LLWeb::loadURLExternal, _1, true, LLStringUtil::null));
|
||||
LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor);
|
||||
|
||||
LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated
|
||||
|
||||
@@ -975,6 +980,8 @@ bool LLAppViewer::init()
|
||||
LLEnvManagerNew::instance().usePrefs();
|
||||
|
||||
gGLActive = FALSE;
|
||||
LLViewerMedia::initClass();
|
||||
LL_INFOS("InitInfo") << "Viewer media initialized." << LL_ENDL ;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1701,8 +1708,7 @@ bool LLAppViewer::cleanup()
|
||||
if (mPurgeOnExit)
|
||||
{
|
||||
llinfos << "Purging all cache files on exit" << llendflush;
|
||||
std::string mask = gDirUtilp->getDirDelimiter() + "*.*";
|
||||
gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);
|
||||
gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),"*.*");
|
||||
}
|
||||
|
||||
removeMarkerFile(); // Any crashes from here on we'll just have to ignore
|
||||
@@ -1779,7 +1785,6 @@ bool LLAppViewer::cleanup()
|
||||
//Note:
|
||||
//LLViewerMedia::cleanupClass() has to be put before gTextureList.shutdown()
|
||||
//because some new image might be generated during cleaning up media. --bao
|
||||
LLViewerMediaFocus::cleanupClass();
|
||||
LLViewerMedia::cleanupClass();
|
||||
LLViewerParcelMedia::cleanupClass();
|
||||
gTextureList.shutdown(); // shutdown again in case a callback added something
|
||||
@@ -2329,30 +2334,17 @@ bool LLAppViewer::initConfiguration()
|
||||
// injection and steal passwords. Phoenix. SL-55321
|
||||
if(clp.hasOption("url"))
|
||||
{
|
||||
std::string slurl = clp.getOption("url")[0];
|
||||
if (LLURLDispatcher::isSLURLCommand(slurl))
|
||||
{
|
||||
LLStartUp::sSLURLCommand = slurl;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLURLSimString::setString(slurl);
|
||||
}
|
||||
LLStartUp::setStartSLURL(LLSLURL(clp.getOption("url")[0]));
|
||||
if(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION)
|
||||
{
|
||||
gHippoGridManager->setCurrentGrid(LLStartUp::getStartSLURL().getGrid());
|
||||
|
||||
}
|
||||
}
|
||||
else if(clp.hasOption("slurl"))
|
||||
{
|
||||
std::string slurl = clp.getOption("slurl")[0];
|
||||
if(LLURLDispatcher::isSLURL(slurl))
|
||||
{
|
||||
if (LLURLDispatcher::isSLURLCommand(slurl))
|
||||
{
|
||||
LLStartUp::sSLURLCommand = slurl;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLURLSimString::setString(slurl);
|
||||
}
|
||||
}
|
||||
LLSLURL start_slurl(clp.getOption("slurl")[0]);
|
||||
LLStartUp::setStartSLURL(start_slurl);
|
||||
}
|
||||
|
||||
const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent");
|
||||
@@ -2431,18 +2423,11 @@ bool LLAppViewer::initConfiguration()
|
||||
// don't call anotherInstanceRunning() when doing URL handoff, as
|
||||
// it relies on checking a marker file which will not work when running
|
||||
// out of different directories
|
||||
std::string slurl;
|
||||
if (!LLStartUp::sSLURLCommand.empty())
|
||||
|
||||
if (LLStartUp::getStartSLURL().isValid() &&
|
||||
(gSavedSettings.getBOOL("SLURLPassToOtherInstance")))
|
||||
{
|
||||
slurl = LLStartUp::sSLURLCommand;
|
||||
}
|
||||
else if (LLURLSimString::parse())
|
||||
{
|
||||
slurl = LLURLSimString::getURL();
|
||||
}
|
||||
if (!slurl.empty())
|
||||
{
|
||||
if (sendURLToOtherInstance(slurl))
|
||||
if (sendURLToOtherInstance(LLStartUp::getStartSLURL().getSLURLString()))
|
||||
{
|
||||
// successfully handed off URL to existing instance, exit
|
||||
return false;
|
||||
@@ -2498,9 +2483,10 @@ bool LLAppViewer::initConfiguration()
|
||||
|
||||
// need to do this here - need to have initialized global settings first
|
||||
std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" );
|
||||
if ( nextLoginLocation.length() )
|
||||
if ( !nextLoginLocation.empty() )
|
||||
{
|
||||
LLURLSimString::setString( nextLoginLocation );
|
||||
LL_DEBUGS("AppInit")<<"set start from NextLoginLocation: "<<nextLoginLocation<<LL_ENDL;
|
||||
LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation));
|
||||
}
|
||||
|
||||
gLastRunVersion = gSavedSettings.getString("LastRunVersion");
|
||||
@@ -2684,8 +2670,7 @@ void LLAppViewer::cleanupSavedSettings()
|
||||
|
||||
void LLAppViewer::removeCacheFiles(const std::string& file_mask)
|
||||
{
|
||||
std::string mask = gDirUtilp->getDirDelimiter() + file_mask;
|
||||
gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), mask);
|
||||
gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), file_mask);
|
||||
}
|
||||
|
||||
void LLAppViewer::writeSystemInfo()
|
||||
|
||||
@@ -459,7 +459,7 @@ gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **succ
|
||||
std::string url = slurl;
|
||||
LLMediaCtrl* web = NULL;
|
||||
const bool trusted_browser = false;
|
||||
if (LLURLDispatcher::dispatch(url, web, trusted_browser))
|
||||
if (LLURLDispatcher::dispatch(url, "", web, trusted_browser))
|
||||
{
|
||||
// bring window to foreground, as it has just been "launched" from a URL
|
||||
// todo: hmm, how to get there from here?
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
#include "llviewernetwork.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llmd5.h"
|
||||
#include "llurlsimstring.h"
|
||||
#include "llfloaterworldmap.h"
|
||||
#include "llurldispatcher.h"
|
||||
#include <Carbon/Carbon.h>
|
||||
@@ -476,7 +475,7 @@ OSErr AEGURLHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn)
|
||||
|
||||
LLMediaCtrl* web = NULL;
|
||||
const bool trusted_browser = false;
|
||||
LLURLDispatcher::dispatch(url, web, trusted_browser);
|
||||
LLURLDispatcher::dispatch(url, "", web, trusted_browser);
|
||||
}
|
||||
|
||||
return(result);
|
||||
|
||||
@@ -488,7 +488,7 @@ bool LLAppViewerWin32::initHardwareTest()
|
||||
if (OSBTN_NO== button)
|
||||
{
|
||||
LL_INFOS("AppInit") << "User quitting after failed DirectX 9 detection" << LL_ENDL;
|
||||
LLWeb::loadURLExternal(DIRECTX_9_URL);
|
||||
LLWeb::loadURLExternal(DIRECTX_9_URL, false);
|
||||
return false;
|
||||
}
|
||||
gSavedSettings.setWarning("AboutDirectX9", FALSE);
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "lltrans.h"
|
||||
#include "llvoiceclient.h"
|
||||
#include "llweb.h"
|
||||
#include "llslurl.h" // IDEVO
|
||||
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h
|
||||
#include "rlvhandler.h"
|
||||
// [/RLVa:KB]
|
||||
@@ -177,7 +178,7 @@ void LLAvatarActions::startIM(const LLUUID& id)
|
||||
if ( (idSession.notNull()) && (!gIMMgr->hasSession(idSession)) )
|
||||
{
|
||||
make_ui_sound("UISndInvalidOp");
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", id/*LLSLURL("agent", id, "completename").getSLURLString()*/));
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -231,7 +232,7 @@ void LLAvatarActions::startCall(const LLUUID& id)
|
||||
if ( (idSession.notNull()) && (!gIMMgr->hasSession(idSession)) )
|
||||
{
|
||||
make_ui_sound("UISndInvalidOp");
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", id));//LLSLURL("agent", id, "completename").getSLURLString()));
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -258,7 +259,7 @@ void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids)
|
||||
if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStartIM(idAgent)) )
|
||||
{
|
||||
make_ui_sound("UISndInvalidOp");
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF, LLSD().with("RECIPIENT", idAgent));//LLSLURL("agent", idAgent, "completename").getSLURLString()));
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF, LLSD().with("RECIPIENT", LLSLURL("agent", idAgent, "completename").getSLURLString()));
|
||||
return;
|
||||
}
|
||||
id_array.push_back(idAgent);
|
||||
@@ -312,7 +313,7 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids)
|
||||
if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStartIM(idAgent)) )
|
||||
{
|
||||
make_ui_sound("UISndInvalidOp");
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF, LLSD().with("RECIPIENT", idAgent/*LLSLURL("agent", idAgent, "completename").getSLURLString()*/));
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF, LLSD().with("RECIPIENT", LLSLURL("agent", idAgent, "completename").getSLURLString()));
|
||||
return;
|
||||
}
|
||||
// [/RLVa:KB]
|
||||
|
||||
@@ -896,7 +896,7 @@ class LLChatHandler : public LLCommandHandler
|
||||
{
|
||||
public:
|
||||
// not allowed from outside the app
|
||||
LLChatHandler() : LLCommandHandler("chat", true) { }
|
||||
LLChatHandler() : LLCommandHandler("chat", UNTRUSTED_BLOCK) { }
|
||||
|
||||
// Your code here
|
||||
bool handle(const LLSD& tokens, const LLSD& query_map,
|
||||
|
||||
@@ -4,46 +4,47 @@
|
||||
* which manipulate user interface. For example, the command
|
||||
* "agent (uuid) about" will open the UI for an avatar's profile.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2007-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llcommandhandler.h"
|
||||
#include "llnotificationsutil.h"
|
||||
//#include "llcommanddispatcherlistener.h"
|
||||
#include "stringize.h"
|
||||
|
||||
// system includes
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
#define THROTTLE_PERIOD 5 // required seconds between throttled commands
|
||||
|
||||
//static LLCommandDispatcherListener sCommandDispatcherListener;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Underlying registry for command handlers, not directly accessible.
|
||||
//---------------------------------------------------------------------------
|
||||
struct LLCommandHandlerInfo
|
||||
{
|
||||
bool mRequireTrustedBrowser;
|
||||
LLCommandHandler::EUntrustedAccess mUntrustedBrowserAccess;
|
||||
LLCommandHandler* mHandler; // safe, all of these are static objects
|
||||
};
|
||||
|
||||
@@ -51,14 +52,18 @@ class LLCommandHandlerRegistry
|
||||
{
|
||||
public:
|
||||
static LLCommandHandlerRegistry& instance();
|
||||
void add(const char* cmd, bool require_trusted_browser, LLCommandHandler* handler);
|
||||
void add(const char* cmd,
|
||||
LLCommandHandler::EUntrustedAccess untrusted_access,
|
||||
LLCommandHandler* handler);
|
||||
bool dispatch(const std::string& cmd,
|
||||
const LLSD& params,
|
||||
const LLSD& query_map,
|
||||
LLMediaCtrl* web,
|
||||
const std::string& nav_type,
|
||||
bool trusted_browser);
|
||||
|
||||
private:
|
||||
friend LLSD LLCommandDispatcher::enumerate();
|
||||
std::map<std::string, LLCommandHandlerInfo> mMap;
|
||||
};
|
||||
|
||||
@@ -72,10 +77,12 @@ LLCommandHandlerRegistry& LLCommandHandlerRegistry::instance()
|
||||
return instance;
|
||||
}
|
||||
|
||||
void LLCommandHandlerRegistry::add(const char* cmd, bool require_trusted_browser, LLCommandHandler* handler)
|
||||
void LLCommandHandlerRegistry::add(const char* cmd,
|
||||
LLCommandHandler::EUntrustedAccess untrusted_access,
|
||||
LLCommandHandler* handler)
|
||||
{
|
||||
LLCommandHandlerInfo info;
|
||||
info.mRequireTrustedBrowser = require_trusted_browser;
|
||||
info.mUntrustedBrowserAccess = untrusted_access;
|
||||
info.mHandler = handler;
|
||||
|
||||
mMap[cmd] = info;
|
||||
@@ -85,17 +92,60 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
|
||||
const LLSD& params,
|
||||
const LLSD& query_map,
|
||||
LLMediaCtrl* web,
|
||||
const std::string& nav_type,
|
||||
bool trusted_browser)
|
||||
{
|
||||
static bool slurl_blocked = false;
|
||||
static bool slurl_throttled = false;
|
||||
static F64 last_throttle_time = 0.0;
|
||||
F64 cur_time = 0.0;
|
||||
std::map<std::string, LLCommandHandlerInfo>::iterator it = mMap.find(cmd);
|
||||
if (it == mMap.end()) return false;
|
||||
const LLCommandHandlerInfo& info = it->second;
|
||||
if (!trusted_browser && info.mRequireTrustedBrowser)
|
||||
if (!trusted_browser)
|
||||
{
|
||||
// block request from external browser, but report as
|
||||
// "handled" because it was well formatted.
|
||||
LL_WARNS_ONCE("SLURL") << "Blocked SLURL command from untrusted browser" << LL_ENDL;
|
||||
return true;
|
||||
switch (info.mUntrustedBrowserAccess)
|
||||
{
|
||||
case LLCommandHandler::UNTRUSTED_ALLOW:
|
||||
// fall through and let the command be handled
|
||||
break;
|
||||
|
||||
case LLCommandHandler::UNTRUSTED_BLOCK:
|
||||
// block request from external browser, but report as
|
||||
// "handled" because it was well formatted.
|
||||
LL_WARNS_ONCE("SLURL") << "Blocked SLURL command from untrusted browser" << LL_ENDL;
|
||||
if (! slurl_blocked)
|
||||
{
|
||||
LLNotificationsUtil::add("BlockedSLURL");
|
||||
slurl_blocked = true;
|
||||
}
|
||||
return true;
|
||||
|
||||
case LLCommandHandler::UNTRUSTED_THROTTLE:
|
||||
// if users actually click on a link, we don't need to throttle it
|
||||
// (throttling mechanism is used to prevent an avalanche of clicks via
|
||||
// javascript
|
||||
if ( nav_type == "clicked" )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
cur_time = LLTimer::getElapsedSeconds();
|
||||
if (cur_time < last_throttle_time + THROTTLE_PERIOD)
|
||||
{
|
||||
// block request from external browser if it happened
|
||||
// within THROTTLE_PERIOD seconds of the last command
|
||||
LL_WARNS_ONCE("SLURL") << "Throttled SLURL command from untrusted browser" << LL_ENDL;
|
||||
if (! slurl_throttled)
|
||||
{
|
||||
LLNotificationsUtil::add("ThrottledSLURL");
|
||||
slurl_throttled = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
last_throttle_time = cur_time;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!info.mHandler) return false;
|
||||
return info.mHandler->handle(params, query_map, web);
|
||||
@@ -106,10 +156,9 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
LLCommandHandler::LLCommandHandler(const char* cmd,
|
||||
bool require_trusted_browser)
|
||||
EUntrustedAccess untrusted_access)
|
||||
{
|
||||
LLCommandHandlerRegistry::instance().add(
|
||||
cmd, require_trusted_browser, this);
|
||||
LLCommandHandlerRegistry::instance().add(cmd, untrusted_access, this);
|
||||
}
|
||||
|
||||
LLCommandHandler::~LLCommandHandler()
|
||||
@@ -127,8 +176,62 @@ bool LLCommandDispatcher::dispatch(const std::string& cmd,
|
||||
const LLSD& params,
|
||||
const LLSD& query_map,
|
||||
LLMediaCtrl* web,
|
||||
const std::string& nav_type,
|
||||
bool trusted_browser)
|
||||
{
|
||||
return LLCommandHandlerRegistry::instance().dispatch(
|
||||
cmd, params, query_map, web, trusted_browser);
|
||||
cmd, params, query_map, web, nav_type, trusted_browser);
|
||||
}
|
||||
|
||||
static std::string lookup(LLCommandHandler::EUntrustedAccess value);
|
||||
|
||||
LLSD LLCommandDispatcher::enumerate()
|
||||
{
|
||||
LLSD response;
|
||||
LLCommandHandlerRegistry& registry(LLCommandHandlerRegistry::instance());
|
||||
for (std::map<std::string, LLCommandHandlerInfo>::const_iterator chi(registry.mMap.begin()),
|
||||
chend(registry.mMap.end());
|
||||
chi != chend; ++chi)
|
||||
{
|
||||
LLSD info;
|
||||
info["untrusted"] = chi->second.mUntrustedBrowserAccess;
|
||||
info["untrusted_str"] = lookup(chi->second.mUntrustedBrowserAccess);
|
||||
response[chi->first] = info;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/*------------------------------ lookup stuff ------------------------------*/
|
||||
struct symbol_info
|
||||
{
|
||||
const char* name;
|
||||
LLCommandHandler::EUntrustedAccess value;
|
||||
};
|
||||
|
||||
#define ent(SYMBOL) \
|
||||
{ \
|
||||
#SYMBOL + 28, /* skip "LLCommandHandler::UNTRUSTED_" prefix */ \
|
||||
SYMBOL \
|
||||
}
|
||||
|
||||
symbol_info symbols[] =
|
||||
{
|
||||
ent(LLCommandHandler::UNTRUSTED_ALLOW), // allow commands from untrusted browsers
|
||||
ent(LLCommandHandler::UNTRUSTED_BLOCK), // ignore commands from untrusted browsers
|
||||
ent(LLCommandHandler::UNTRUSTED_THROTTLE) // allow untrusted, but only a few per min.
|
||||
};
|
||||
|
||||
#undef ent
|
||||
|
||||
static std::string lookup(LLCommandHandler::EUntrustedAccess value)
|
||||
{
|
||||
for (symbol_info *sii(symbols), *siend(symbols + (sizeof(symbols)/sizeof(symbols[0])));
|
||||
sii != siend; ++sii)
|
||||
{
|
||||
if (sii->value == value)
|
||||
{
|
||||
return sii->name;
|
||||
}
|
||||
}
|
||||
return STRINGIZE("UNTRUSTED_" << value);
|
||||
}
|
||||
|
||||
@@ -4,36 +4,32 @@
|
||||
* which manipulate user interface. For example, the command
|
||||
* "agent (uuid) about" will open the UI for an avatar's profile.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2007-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLCOMMANDHANDLER_H
|
||||
#define LLCOMMANDHANDLER_H
|
||||
|
||||
#include "llsd.h"
|
||||
|
||||
/* Example: secondlife:///app/foo/<uuid>
|
||||
Command "foo" that takes one parameter, a UUID.
|
||||
|
||||
@@ -43,7 +39,7 @@ public:
|
||||
// Inform the system you handle commands starting
|
||||
// with "foo" and they are only allowed from
|
||||
// "trusted" (pointed at Linden content) browsers
|
||||
LLFooHandler() : LLCommandHandler("foo", true) { }
|
||||
LLFooHandler() : LLCommandHandler("foo", UNTRUSTED_BLOCK) { }
|
||||
|
||||
// Your code here
|
||||
bool handle(const LLSD& tokens, const LLSD& query_map,
|
||||
@@ -65,7 +61,14 @@ class LLMediaCtrl;
|
||||
class LLCommandHandler
|
||||
{
|
||||
public:
|
||||
LLCommandHandler(const char* command, bool allow_from_untrusted_browser);
|
||||
enum EUntrustedAccess
|
||||
{
|
||||
UNTRUSTED_ALLOW, // allow commands from untrusted browsers
|
||||
UNTRUSTED_BLOCK, // ignore commands from untrusted browsers
|
||||
UNTRUSTED_THROTTLE // allow untrusted, but only a few per min.
|
||||
};
|
||||
|
||||
LLCommandHandler(const char* command, EUntrustedAccess untrusted_access);
|
||||
// Automatically registers object to get called when
|
||||
// command is executed. All commands can be processed
|
||||
// in links from LLMediaCtrl, but some (like teleport)
|
||||
@@ -92,10 +95,14 @@ public:
|
||||
const LLSD& params,
|
||||
const LLSD& query_map,
|
||||
LLMediaCtrl* web,
|
||||
const std::string& nav_type,
|
||||
bool trusted_browser);
|
||||
// Execute a command registered via the above mechanism,
|
||||
// passing string parameters.
|
||||
// Returns true if command was found and executed correctly.
|
||||
/// Return an LLSD::Map of registered LLCommandHandlers and associated
|
||||
/// info (e.g. EUntrustedAccess).
|
||||
static LLSD enumerate();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -190,8 +190,9 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
|
||||
|
||||
mImportanceToCamera = 0.f ;
|
||||
mBoundingSphereRadius = 0.0f ;
|
||||
}
|
||||
|
||||
mHasMedia = FALSE ;
|
||||
}
|
||||
|
||||
void LLFace::destroy()
|
||||
{
|
||||
@@ -2065,6 +2066,20 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//check if the face has a media
|
||||
BOOL LLFace::hasMedia() const
|
||||
{
|
||||
if(mHasMedia)
|
||||
{
|
||||
return TRUE ;
|
||||
}
|
||||
if(mTexture.notNull())
|
||||
{
|
||||
return mTexture->hasParcelMedia() ; //if has a parcel media
|
||||
}
|
||||
|
||||
return FALSE ; //no media.
|
||||
}
|
||||
const F32 LEAST_IMPORTANCE = 0.05f ;
|
||||
const F32 LEAST_IMPORTANCE_FOR_LARGE_IMAGE = 0.3f ;
|
||||
|
||||
@@ -2134,7 +2149,7 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
|
||||
t.load3(camera->getOrigin().mV);
|
||||
lookAt.setSub(center, t);
|
||||
F32 dist = lookAt.getLength3().getF32();
|
||||
dist = llmax(dist-size.getLength3().getF32(), 0.f);
|
||||
dist = llmax(dist-size.getLength3().getF32(), 0.001f);
|
||||
lookAt.normalize3fast() ;
|
||||
|
||||
//get area of circle around node
|
||||
@@ -2145,9 +2160,33 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
|
||||
x_axis.load3(camera->getXAxis().mV);
|
||||
cos_angle_to_view_dir = lookAt.dot3(x_axis).getF32();
|
||||
|
||||
//if has media, check if the face is out of the view frustum.
|
||||
if(hasMedia())
|
||||
{
|
||||
if(!camera->AABBInFrustum(center, size))
|
||||
{
|
||||
mImportanceToCamera = 0.f ;
|
||||
return false ;
|
||||
}
|
||||
if(cos_angle_to_view_dir > camera->getCosHalfFov()) //the center is within the view frustum
|
||||
{
|
||||
cos_angle_to_view_dir = 1.0f ;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLVector4a d;
|
||||
d.setSub(lookAt, x_axis);
|
||||
|
||||
if(dist * dist * d.dot3(d) < size_squared)
|
||||
{
|
||||
cos_angle_to_view_dir = 1.0f ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(dist < mBoundingSphereRadius) //camera is very close
|
||||
{
|
||||
cos_angle_to_view_dir = 1.0f;
|
||||
cos_angle_to_view_dir = 1.0f ;
|
||||
mImportanceToCamera = 1.0f;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -224,6 +224,9 @@ public:
|
||||
|
||||
F32 getTextureVirtualSize() ;
|
||||
F32 getImportanceToCamera()const {return mImportanceToCamera ;}
|
||||
|
||||
void setHasMedia(bool has_media) { mHasMedia = has_media ;}
|
||||
BOOL hasMedia() const ;
|
||||
//vertex buffer tracking
|
||||
void setVertexBuffer(LLVertexBuffer* buffer);
|
||||
void clearVertexBuffer(); //sets mVertexBuffer and mLastVertexBuffer to NULL
|
||||
@@ -289,6 +292,7 @@ private:
|
||||
//based on the distance from the face to the view point and the angle from the face center to the view direction.
|
||||
F32 mImportanceToCamera ;
|
||||
F32 mBoundingSphereRadius ;
|
||||
bool mHasMedia ;
|
||||
|
||||
protected:
|
||||
static BOOL sSafeRenderSelect;
|
||||
|
||||
@@ -55,7 +55,7 @@ class LLClassifiedHandler : public LLCommandHandler
|
||||
{
|
||||
public:
|
||||
// requires trusted browser to trigger
|
||||
LLClassifiedHandler() : LLCommandHandler("classified", true) { }
|
||||
LLClassifiedHandler() : LLCommandHandler("classified", UNTRUSTED_THROTTLE) { }
|
||||
bool handle(const LLSD& tokens, const LLSD& query_map,
|
||||
LLMediaCtrl* web)
|
||||
{
|
||||
|
||||
@@ -56,7 +56,7 @@ class LLEventHandler : public LLCommandHandler
|
||||
{
|
||||
public:
|
||||
// requires trusted browser to trigger
|
||||
LLEventHandler() : LLCommandHandler("event", true) { }
|
||||
LLEventHandler() : LLCommandHandler("event", UNTRUSTED_THROTTLE) { }
|
||||
bool handle(const LLSD& tokens, const LLSD& query_map,
|
||||
LLMediaCtrl* web)
|
||||
{
|
||||
|
||||
@@ -38,7 +38,7 @@ class LLFloaterHandler
|
||||
: public LLCommandHandler
|
||||
{
|
||||
public:
|
||||
LLFloaterHandler() : LLCommandHandler("floater", true) { }
|
||||
LLFloaterHandler() : LLCommandHandler("floater", UNTRUSTED_BLOCK) { }
|
||||
bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web);
|
||||
};
|
||||
|
||||
|
||||
@@ -63,5 +63,5 @@ void LLFloaterHtmlSimple::navigateTo(const std::string &url)
|
||||
void LLFloaterHtmlSimple::setTrusted(bool trusted)
|
||||
{
|
||||
LLMediaCtrl* web = getChild<LLMediaCtrl>("browser");
|
||||
web->setTrusted(trusted);
|
||||
web->setTrustedContent(trusted);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ LLFloaterHUD::LLFloaterHUD()
|
||||
if (mWebBrowser)
|
||||
{
|
||||
// Open links in internal browser
|
||||
mWebBrowser->setOpenInExternalBrowser(false);
|
||||
//mWebBrowser->setOpenInExternalBrowser(false);
|
||||
|
||||
// This is a "chrome" floater, so we don't want anything to
|
||||
// take focus (as the user needs to be able to walk with
|
||||
|
||||
@@ -1,434 +0,0 @@
|
||||
/**
|
||||
* @file llfloaterhtmlhelp.cpp
|
||||
* @brief HTML Help floater - uses embedded web browser control
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2006-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloatermediabrowser.h"
|
||||
#include "llfloaterhtml.h"
|
||||
|
||||
#include "llparcel.h"
|
||||
#include "llpluginclassmedia.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llmediactrl.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llviewerparcelmgr.h"
|
||||
#include "llweb.h"
|
||||
#include "llui.h"
|
||||
#include "roles_constants.h"
|
||||
#include "llwindow.h"
|
||||
|
||||
#include "llurlhistory.h"
|
||||
#include "llmediactrl.h"
|
||||
#include "llviewermedia.h"
|
||||
#include "llviewerparcelmedia.h"
|
||||
#include "llcombobox.h"
|
||||
#include "llnotificationsutil.h"
|
||||
|
||||
// TEMP
|
||||
#include "llsdutil.h"
|
||||
|
||||
LLFloaterMediaBrowser::LLFloaterMediaBrowser(const LLSD& media_data)
|
||||
{
|
||||
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_media_browser.xml");
|
||||
|
||||
}
|
||||
|
||||
|
||||
void LLFloaterMediaBrowser::geometryChanged(S32 x, S32 y, S32 width, S32 height)
|
||||
{
|
||||
// Make sure the layout of the browser control is updated, so this calculation is correct.
|
||||
LLLayoutStack::updateClass();
|
||||
|
||||
// TODO: need to adjust size and constrain position to make sure floaters aren't moved outside the window view, etc.
|
||||
LLCoordWindow window_size;
|
||||
getWindow()->getSize(&window_size);
|
||||
|
||||
// Adjust width and height for the size of the chrome on the Media Browser window.
|
||||
width += getRect().getWidth() - mBrowser->getRect().getWidth();
|
||||
height += getRect().getHeight() - mBrowser->getRect().getHeight();
|
||||
|
||||
LLRect geom;
|
||||
geom.setOriginAndSize(x, window_size.mY - (y + height), width, height);
|
||||
|
||||
lldebugs << "geometry change: " << geom << llendl;
|
||||
|
||||
handleReshape(geom,false);
|
||||
}
|
||||
|
||||
void LLFloaterMediaBrowser::draw()
|
||||
{
|
||||
childSetEnabled("go", !mAddressCombo->getValue().asString().empty());
|
||||
LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
|
||||
if(parcel)
|
||||
{
|
||||
childSetVisible("parcel_owner_controls", LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_CHANGE_MEDIA));
|
||||
childSetEnabled("assign", !mAddressCombo->getValue().asString().empty());
|
||||
}
|
||||
bool show_time_controls = false;
|
||||
bool media_playing = false;
|
||||
if(mBrowser)
|
||||
{
|
||||
LLPluginClassMedia* media_plugin = mBrowser->getMediaPlugin();
|
||||
if(media_plugin)
|
||||
{
|
||||
show_time_controls = media_plugin->pluginSupportsMediaTime();
|
||||
media_playing = media_plugin->getStatus() == LLPluginClassMediaOwner::MEDIA_PLAYING;
|
||||
}
|
||||
}
|
||||
childSetVisible("time_controls", show_time_controls);
|
||||
childSetVisible("rewind", show_time_controls);
|
||||
childSetVisible("play", show_time_controls && ! media_playing);
|
||||
childSetVisible("pause", show_time_controls && media_playing);
|
||||
childSetVisible("stop", show_time_controls);
|
||||
childSetVisible("seek", show_time_controls);
|
||||
|
||||
childSetEnabled("play", ! media_playing);
|
||||
childSetEnabled("stop", media_playing);
|
||||
|
||||
childSetEnabled("back", mBrowser->canNavigateBack());
|
||||
childSetEnabled("forward", mBrowser->canNavigateForward());
|
||||
|
||||
LLFloater::draw();
|
||||
}
|
||||
|
||||
BOOL LLFloaterMediaBrowser::postBuild()
|
||||
{
|
||||
mBrowser = getChild<LLMediaCtrl>("browser");
|
||||
mBrowser->addObserver(this);
|
||||
|
||||
mAddressCombo = getChild<LLComboBox>("address");
|
||||
mAddressCombo->setCommitCallback(onEnterAddress);
|
||||
mAddressCombo->setCallbackUserData(this);
|
||||
mAddressCombo->sortByName();
|
||||
|
||||
childSetAction("back", onClickBack, this);
|
||||
childSetAction("forward", onClickForward, this);
|
||||
childSetAction("reload", onClickRefresh, this);
|
||||
childSetAction("rewind", onClickRewind, this);
|
||||
childSetAction("play", onClickPlay, this);
|
||||
childSetAction("stop", onClickStop, this);
|
||||
childSetAction("pause", onClickPlay, this);
|
||||
childSetAction("seek", onClickSeek, this);
|
||||
childSetAction("go", onClickGo, this);
|
||||
childSetAction("open_browser", onClickOpenWebBrowser, this);
|
||||
childSetAction("assign", onClickAssign, this);
|
||||
|
||||
buildURLHistory();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLFloaterMediaBrowser::buildURLHistory()
|
||||
{
|
||||
LLCtrlListInterface* url_list = childGetListInterface("address");
|
||||
if (url_list)
|
||||
{
|
||||
url_list->operateOnAll(LLCtrlListInterface::OP_DELETE);
|
||||
}
|
||||
|
||||
// Get all of the entries in the "browser" collection
|
||||
LLSD browser_history = LLURLHistory::getURLHistory("browser");
|
||||
|
||||
LLSD::array_iterator iter_history =
|
||||
browser_history.beginArray();
|
||||
LLSD::array_iterator end_history =
|
||||
browser_history.endArray();
|
||||
for(; iter_history != end_history; ++iter_history)
|
||||
{
|
||||
std::string url = (*iter_history).asString();
|
||||
if(! url.empty())
|
||||
url_list->addSimpleElement(url);
|
||||
}
|
||||
|
||||
// initialize URL history in the plugin
|
||||
if(mBrowser && mBrowser->getMediaPlugin())
|
||||
{
|
||||
mBrowser->getMediaPlugin()->initializeUrlHistory(browser_history);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LLFloaterMediaBrowser::getSupportURL()
|
||||
{
|
||||
return getString("support_page_url");
|
||||
}
|
||||
void LLFloaterMediaBrowser::onClose(bool app_quitting)
|
||||
{
|
||||
//setVisible(FALSE);
|
||||
destroy();
|
||||
}
|
||||
|
||||
void LLFloaterMediaBrowser::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
|
||||
{
|
||||
if(event == MEDIA_EVENT_LOCATION_CHANGED)
|
||||
{
|
||||
setCurrentURL(self->getLocation());
|
||||
}
|
||||
else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
|
||||
{
|
||||
// This is the event these flags are sent with.
|
||||
childSetEnabled("back", self->getHistoryBackAvailable());
|
||||
childSetEnabled("forward", self->getHistoryForwardAvailable());
|
||||
}
|
||||
else if(event == MEDIA_EVENT_CLOSE_REQUEST)
|
||||
{
|
||||
// The browser instance wants its window closed.
|
||||
close();
|
||||
}
|
||||
else if(event == MEDIA_EVENT_GEOMETRY_CHANGE)
|
||||
{
|
||||
geometryChanged(self->getGeometryX(), self->getGeometryY(), self->getGeometryWidth(), self->getGeometryHeight());
|
||||
}
|
||||
}
|
||||
void LLFloaterMediaBrowser::setCurrentURL(const std::string& url)
|
||||
{
|
||||
mCurrentURL = url;
|
||||
|
||||
// redirects will navigate momentarily to about:blank, don't add to history
|
||||
if (mCurrentURL != "about:blank")
|
||||
{
|
||||
mAddressCombo->remove(mCurrentURL);
|
||||
mAddressCombo->add(mCurrentURL, ADD_SORTED);
|
||||
mAddressCombo->selectByValue(mCurrentURL);
|
||||
|
||||
// Serialize url history
|
||||
LLURLHistory::removeURL("browser", mCurrentURL);
|
||||
LLURLHistory::addURL("browser", mCurrentURL);
|
||||
}
|
||||
childSetEnabled("back", mBrowser->canNavigateBack());
|
||||
childSetEnabled("forward", mBrowser->canNavigateForward());
|
||||
childSetEnabled("reload", TRUE);
|
||||
}
|
||||
|
||||
LLFloaterMediaBrowser* LLFloaterMediaBrowser::showInstance(const LLSD& media_url)
|
||||
{
|
||||
LLFloaterMediaBrowser* floaterp = LLUISingleton<LLFloaterMediaBrowser, VisibilityPolicy<LLFloater> >::showInstance(media_url);
|
||||
|
||||
floaterp->openMedia(media_url.asString());
|
||||
return floaterp;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterMediaBrowser::onEnterAddress(LLUICtrl* ctrl, void* user_data)
|
||||
{
|
||||
LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data;
|
||||
self->mBrowser->navigateTo(self->mAddressCombo->getValue().asString());
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterMediaBrowser::onClickRefresh(void* user_data)
|
||||
{
|
||||
LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data;
|
||||
|
||||
self->mAddressCombo->remove(0);
|
||||
if( self->mBrowser->getMediaPlugin() && self->mBrowser->getMediaPlugin()->pluginSupportsMediaBrowser())
|
||||
{
|
||||
bool ignore_cache = true;
|
||||
self->mBrowser->getMediaPlugin()->browse_reload( ignore_cache );
|
||||
}
|
||||
else
|
||||
{
|
||||
self->mBrowser->navigateTo(self->mCurrentURL);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterMediaBrowser::onClickForward(void* user_data)
|
||||
{
|
||||
LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data;
|
||||
|
||||
self->mBrowser->navigateForward();
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterMediaBrowser::onClickBack(void* user_data)
|
||||
{
|
||||
LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data;
|
||||
|
||||
self->mBrowser->navigateBack();
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterMediaBrowser::onClickGo(void* user_data)
|
||||
{
|
||||
LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data;
|
||||
|
||||
self->mBrowser->navigateTo(self->mAddressCombo->getValue().asString());
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterMediaBrowser::onClickOpenWebBrowser(void* user_data)
|
||||
{
|
||||
LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data;
|
||||
|
||||
std::string url = self->mCurrentURL.empty() ?
|
||||
self->mBrowser->getHomePageUrl() :
|
||||
self->mCurrentURL;
|
||||
LLWeb::loadURLExternal(url);
|
||||
}
|
||||
|
||||
void LLFloaterMediaBrowser::onClickAssign(void* user_data)
|
||||
{
|
||||
LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data;
|
||||
|
||||
LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
|
||||
if (!parcel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::string media_url = self->mAddressCombo->getValue().asString();
|
||||
LLStringUtil::trim(media_url);
|
||||
|
||||
if(parcel->getMediaType() != "text/html")
|
||||
{
|
||||
parcel->setMediaURL(media_url);
|
||||
parcel->setMediaCurrentURL(media_url);
|
||||
parcel->setMediaType(std::string("text/html"));
|
||||
LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel, true );
|
||||
LLViewerParcelMedia::sendMediaNavigateMessage(media_url);
|
||||
LLViewerParcelMedia::stop();
|
||||
// LLViewerParcelMedia::update( parcel );
|
||||
}
|
||||
LLViewerParcelMedia::sendMediaNavigateMessage(media_url);
|
||||
}
|
||||
//static
|
||||
void LLFloaterMediaBrowser::onClickRewind(void* user_data)
|
||||
{
|
||||
LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data;
|
||||
|
||||
if(self->mBrowser->getMediaPlugin())
|
||||
self->mBrowser->getMediaPlugin()->start(-2.0f);
|
||||
}
|
||||
//static
|
||||
void LLFloaterMediaBrowser::onClickPlay(void* user_data)
|
||||
{
|
||||
LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data;
|
||||
|
||||
LLPluginClassMedia* plugin = self->mBrowser->getMediaPlugin();
|
||||
if(plugin)
|
||||
{
|
||||
if(plugin->getStatus() == LLPluginClassMediaOwner::MEDIA_PLAYING)
|
||||
{
|
||||
plugin->pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
plugin->start();
|
||||
}
|
||||
}
|
||||
}
|
||||
//static
|
||||
void LLFloaterMediaBrowser::onClickStop(void* user_data)
|
||||
{
|
||||
LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data;
|
||||
|
||||
if(self->mBrowser->getMediaPlugin())
|
||||
self->mBrowser->getMediaPlugin()->stop();
|
||||
}
|
||||
//static
|
||||
void LLFloaterMediaBrowser::onClickSeek(void* user_data)
|
||||
{
|
||||
LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data;
|
||||
|
||||
if(self->mBrowser->getMediaPlugin())
|
||||
self->mBrowser->getMediaPlugin()->start(2.0f);
|
||||
}
|
||||
void LLFloaterMediaBrowser::openMedia(const std::string& media_url)
|
||||
{
|
||||
mBrowser->setHomePageUrl(media_url);
|
||||
mBrowser->navigateTo(media_url);
|
||||
setCurrentURL(media_url);
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
LLViewerHtmlHelp gViewerHtmlHelp;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
LLViewerHtmlHelp::LLViewerHtmlHelp()
|
||||
{
|
||||
|
||||
LLUI::setHtmlHelp(this);
|
||||
}
|
||||
|
||||
LLViewerHtmlHelp::~LLViewerHtmlHelp()
|
||||
{
|
||||
|
||||
LLUI::setHtmlHelp(NULL);
|
||||
}
|
||||
|
||||
void LLViewerHtmlHelp::show()
|
||||
{
|
||||
show("");
|
||||
}
|
||||
|
||||
void LLViewerHtmlHelp::show(std::string url)
|
||||
{
|
||||
LLFloaterMediaBrowser* floater_html = LLFloaterMediaBrowser::getInstance();
|
||||
floater_html->setVisible(FALSE);
|
||||
|
||||
if (url.empty())
|
||||
{
|
||||
url = floater_html->getSupportURL();
|
||||
}
|
||||
|
||||
if (gSavedSettings.getBOOL("UseExternalBrowser"))
|
||||
{
|
||||
LLSD notificationData;
|
||||
notificationData["url"] = url;
|
||||
|
||||
LLNotificationsUtil::add("ClickOpenF1Help", notificationData, LLSD(), onClickF1HelpLoadURL);
|
||||
floater_html->close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// don't wait, just do it
|
||||
floater_html->setVisible(TRUE);
|
||||
floater_html->openMedia(url);
|
||||
}
|
||||
}
|
||||
// static
|
||||
bool LLViewerHtmlHelp::onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response)
|
||||
{
|
||||
LLFloaterMediaBrowser* floater_html = LLFloaterMediaBrowser::getInstance();
|
||||
floater_html->setVisible(FALSE);
|
||||
std::string url = floater_html->getSupportURL();
|
||||
S32 option = LLNotification::getSelectedOption(notification, response);
|
||||
if (option == 0)
|
||||
{
|
||||
LLWeb::loadURL(url);
|
||||
}
|
||||
floater_html->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
/**
|
||||
* @file llfloaterhtmlhelp.h
|
||||
* @brief HTML Help floater - uses embedded web browser control
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2006-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERHTMLHELP_H
|
||||
#define LL_LLFLOATERHTMLHELP_H
|
||||
|
||||
#include "llhtmlhelp.h"
|
||||
#include "llfloater.h"
|
||||
#include "llmediactrl.h"
|
||||
|
||||
class LLViewerHtmlHelp : public LLHtmlHelp
|
||||
{
|
||||
public:
|
||||
LLViewerHtmlHelp();
|
||||
virtual ~LLViewerHtmlHelp();
|
||||
|
||||
/*virtual*/ void show();
|
||||
/*virtual*/ void show(std::string start_url);
|
||||
void show(std::string start_url, std::string title);
|
||||
|
||||
static bool onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response);
|
||||
|
||||
};
|
||||
|
||||
class LLComboBox;
|
||||
class LLMediaCtrl;
|
||||
|
||||
class LLFloaterMediaBrowser :
|
||||
public LLFloater,
|
||||
public LLUISingleton<LLFloaterMediaBrowser,
|
||||
VisibilityPolicy<LLFloater> >,
|
||||
public LLViewerMediaObserver
|
||||
{
|
||||
friend class LLUISingleton<LLFloaterMediaBrowser, VisibilityPolicy<LLFloater> >;
|
||||
public:
|
||||
LLFloaterMediaBrowser(const LLSD& media_data);
|
||||
|
||||
|
||||
void geometryChanged(S32 x, S32 y, S32 width, S32 height);
|
||||
|
||||
/*virtual*/ BOOL postBuild();
|
||||
/*virtual*/ void onClose(bool app_quitting);
|
||||
/*virtual*/ void draw();
|
||||
|
||||
// inherited from LLViewerMediaObserver
|
||||
/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
|
||||
|
||||
void openMedia(const std::string& media_url);
|
||||
void buildURLHistory();
|
||||
std::string getSupportURL();
|
||||
void setCurrentURL(const std::string& url);
|
||||
|
||||
static LLFloaterMediaBrowser* showInstance(const LLSD& id);
|
||||
static void onEnterAddress(LLUICtrl* ctrl, void* user_data);
|
||||
static void onClickRefresh(void* user_data);
|
||||
static void onClickBack(void* user_data);
|
||||
static void onClickForward(void* user_data);
|
||||
static void onClickGo(void* user_data);
|
||||
static void onClickOpenWebBrowser(void* user_data);
|
||||
static void onClickAssign(void* user_data);
|
||||
static void onClickRewind(void* user_data);
|
||||
static void onClickPlay(void* user_data);
|
||||
static void onClickStop(void* user_data);
|
||||
static void onClickSeek(void* user_data);
|
||||
|
||||
private:
|
||||
LLMediaCtrl* mBrowser;
|
||||
LLComboBox* mAddressCombo;
|
||||
std::string mCurrentURL;
|
||||
};
|
||||
|
||||
extern LLViewerHtmlHelp gViewerHtmlHelp;
|
||||
|
||||
#endif // LL_LLFLOATERHTMLHELP_H
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#define LL_LLFLOATER_NOTIFICATIONS_CONSOLE_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "lllayoutstack.h"
|
||||
#include "llnotifications.h"
|
||||
|
||||
class LLFloaterNotificationConsole :
|
||||
|
||||
@@ -42,9 +42,13 @@
|
||||
#include "llfloatermute.h"
|
||||
#include "llgroupactions.h"
|
||||
#include "llmutelist.h"
|
||||
#include "llsdutil.h"
|
||||
#include "llslurl.h"
|
||||
#include "lltrans.h"
|
||||
#include "llui.h"
|
||||
#include "lluictrl.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llurldispatcher.h"
|
||||
#include "llurlaction.h"
|
||||
#include "llweb.h"
|
||||
|
||||
// [RLVa:KB] - Version: 1.23.4
|
||||
#include "rlvhandler.h"
|
||||
@@ -52,34 +56,9 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// LLFloaterObjectIMInfo
|
||||
class LLFloaterObjectIMInfo : public LLFloater, public LLFloaterSingleton<LLFloaterObjectIMInfo>
|
||||
{
|
||||
public:
|
||||
LLFloaterObjectIMInfo(const LLSD& sd);
|
||||
virtual ~LLFloaterObjectIMInfo() { };
|
||||
|
||||
BOOL postBuild(void);
|
||||
|
||||
void update(const LLUUID& id, const std::string& name, const std::string& slurl, const LLUUID& owner, bool owner_is_group);
|
||||
|
||||
// UI Handlers
|
||||
static void onClickMap(void* data);
|
||||
static void onClickOwner(void* data);
|
||||
static void onClickMute(void* data);
|
||||
|
||||
void nameCallback(const LLUUID& id, const std::string& full_name, bool is_group);
|
||||
|
||||
private:
|
||||
LLUUID mObjectID;
|
||||
std::string mObjectName;
|
||||
std::string mSlurl;
|
||||
LLUUID mOwnerID;
|
||||
std::string mOwnerName;
|
||||
bool mOwnerIsGroup;
|
||||
};
|
||||
|
||||
LLFloaterObjectIMInfo::LLFloaterObjectIMInfo(const LLSD& seed)
|
||||
: mObjectID(), mObjectName(), mSlurl(), mOwnerID(), mOwnerName(), mOwnerIsGroup(false)
|
||||
: mObjectID(), mName(), mSLurl(), mOwnerID(), mGroupOwned(false)
|
||||
{
|
||||
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_object_im_info.xml");
|
||||
|
||||
@@ -99,34 +78,37 @@ BOOL LLFloaterObjectIMInfo::postBuild(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLFloaterObjectIMInfo::update(const LLUUID& object_id, const std::string& name, const std::string& slurl, const LLUUID& owner_id, bool owner_is_group)
|
||||
void LLFloaterObjectIMInfo::update(LLSD& data)
|
||||
{
|
||||
// Extract appropriate object information from input LLSD
|
||||
// (Eventually, it might be nice to query server for details
|
||||
// rather than require caller to pass in the information.)
|
||||
mObjectID = data["object_id"].asUUID();
|
||||
mName = data["name"].asString();
|
||||
mOwnerID = data["owner_id"].asUUID();
|
||||
mGroupOwned = data["group_owned"].asBoolean();
|
||||
mSLurl = data["slurl"].asString();
|
||||
|
||||
// When talking to an old region we won't have a slurl.
|
||||
// The object id isn't really the object id either but we don't use it so who cares.
|
||||
//bool have_slurl = !slurl.empty();
|
||||
// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-04 (RLVa-1.0.0a) | Added: RLVa-0.2.0g
|
||||
bool have_slurl = (!slurl.empty()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
|
||||
bool have_slurl = (!mSLurl.empty()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
|
||||
// [/RLVa:KB]
|
||||
childSetVisible("Unknown_Slurl",!have_slurl);
|
||||
childSetVisible("Slurl",have_slurl);
|
||||
|
||||
childSetText("ObjectName",name);
|
||||
childSetText("Slurl",slurl);
|
||||
childSetText("ObjectName",mName);
|
||||
childSetText("Slurl",mSLurl);
|
||||
childSetText("OwnerName",std::string(""));
|
||||
|
||||
// bool my_object = (owner_id == gAgentID);
|
||||
// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g
|
||||
bool my_object = (owner_id == gAgentID) || ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(owner_id)));
|
||||
bool my_object = (mOwnerID == gAgentID) || ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(mOwnerID)));
|
||||
// [/RLVa:KB]
|
||||
childSetEnabled("Mute",!my_object);
|
||||
|
||||
mObjectID = object_id;
|
||||
mObjectName = name;
|
||||
mSlurl = slurl;
|
||||
mOwnerID = owner_id;
|
||||
mOwnerIsGroup = owner_is_group;
|
||||
|
||||
if (gCacheName) gCacheName->get(owner_id,owner_is_group,boost::bind(&LLFloaterObjectIMInfo::nameCallback,this,_1,_2,_3));
|
||||
if (gCacheName) gCacheName->get(mOwnerID,mGroupOwned,boost::bind(&LLFloaterObjectIMInfo::nameCallback,this,_1,_2,_3));
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -134,17 +116,15 @@ void LLFloaterObjectIMInfo::onClickMap(void* data)
|
||||
{
|
||||
LLFloaterObjectIMInfo* self = (LLFloaterObjectIMInfo*)data;
|
||||
|
||||
std::ostringstream link;
|
||||
link << "secondlife://" << self->mSlurl;
|
||||
class LLMediaCtrl* web = NULL;
|
||||
LLURLDispatcher::dispatch(link.str(), web, true);
|
||||
std::string url = "secondlife://" + self->mSLurl;
|
||||
LLUrlAction::showLocationOnMap(url);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterObjectIMInfo::onClickOwner(void* data)
|
||||
{
|
||||
LLFloaterObjectIMInfo* self = (LLFloaterObjectIMInfo*)data;
|
||||
if (self->mOwnerIsGroup)
|
||||
if (self->mGroupOwned)
|
||||
{
|
||||
LLGroupActions::show(self->mOwnerID);
|
||||
}
|
||||
@@ -162,7 +142,7 @@ void LLFloaterObjectIMInfo::onClickMute(void* data)
|
||||
{
|
||||
LLFloaterObjectIMInfo* self = (LLFloaterObjectIMInfo*)data;
|
||||
|
||||
LLMute::EType mute_type = (self->mOwnerIsGroup) ? LLMute::GROUP : LLMute::AGENT;
|
||||
LLMute::EType mute_type = (self->mGroupOwned) ? LLMute::GROUP : LLMute::AGENT;
|
||||
// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g
|
||||
if ( (LLMute::GROUP != mute_type) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(self->mOwnerID)) )
|
||||
{
|
||||
@@ -170,7 +150,7 @@ void LLFloaterObjectIMInfo::onClickMute(void* data)
|
||||
}
|
||||
// [/RLVa:KB]
|
||||
|
||||
LLMute mute(self->mOwnerID, self->mOwnerName, mute_type);
|
||||
LLMute mute(self->mOwnerID, self->mName, mute_type);
|
||||
LLMuteList::getInstance()->add(mute);
|
||||
LLFloaterMute::showInstance();
|
||||
self->close();
|
||||
@@ -179,49 +159,50 @@ void LLFloaterObjectIMInfo::onClickMute(void* data)
|
||||
//static
|
||||
void LLFloaterObjectIMInfo::nameCallback(const LLUUID& id, const std::string& full_name, bool is_group)
|
||||
{
|
||||
mOwnerName = full_name;
|
||||
mName = full_name;
|
||||
// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g
|
||||
if ( (!is_group) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(id)) )
|
||||
{
|
||||
mOwnerName = RlvStrings::getAnonym(mOwnerName);
|
||||
mName = RlvStrings::getAnonym(mName);
|
||||
}
|
||||
// [/RLVa:KB]
|
||||
|
||||
childSetText("OwnerName", mOwnerName);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// LLObjectIMInfo
|
||||
void LLObjectIMInfo::show(const LLUUID &object_id, const std::string &name, const std::string &location, const LLUUID &owner_id, bool owner_is_group)
|
||||
{
|
||||
LLFloaterObjectIMInfo* im_info_floater = LLFloaterObjectIMInfo::showInstance();
|
||||
im_info_floater->update(object_id,name,location,owner_id,owner_is_group);
|
||||
childSetText("OwnerName", mName);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// LLObjectIMInfoHandler
|
||||
//moved to llchathistory.cpp in v2
|
||||
class LLObjectIMInfoHandler : public LLCommandHandler
|
||||
{
|
||||
public:
|
||||
LLObjectIMInfoHandler() : LLCommandHandler("objectim", true) { }
|
||||
LLObjectIMInfoHandler() : LLCommandHandler("objectim", UNTRUSTED_THROTTLE) { }
|
||||
|
||||
bool handle(const LLSD& tokens, const LLSD& query_map,
|
||||
LLMediaCtrl* web);
|
||||
bool handle(const LLSD& params, const LLSD& query_map,LLMediaCtrl* web)
|
||||
{
|
||||
if (params.size() < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LLUUID object_id;
|
||||
if (!object_id.set(params[0], FALSE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LLSD payload;
|
||||
payload["object_id"] = object_id;
|
||||
payload["owner_id"] = query_map["owner"];
|
||||
payload["name"] = query_map["name"];
|
||||
payload["slurl"] = LLWeb::escapeURL(query_map["slurl"]);
|
||||
payload["group_owned"] = query_map["groupowned"];
|
||||
|
||||
LLFloaterObjectIMInfo::showInstance()->update(payload);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Creating the object registers with the dispatcher.
|
||||
LLObjectIMInfoHandler gObjectIMHandler;
|
||||
|
||||
// ex. secondlife:///app/objectim/9426adfc-9c17-8765-5f09-fdf19957d003?owner=a112d245-9095-4e9c-ace4-ffa31717f934&groupowned=true&slurl=ahern/123/123/123&name=Object
|
||||
bool LLObjectIMInfoHandler::handle(const LLSD &tokens, const LLSD &query_map, LLMediaCtrl* web)
|
||||
{
|
||||
LLUUID task_id = tokens[0].asUUID();
|
||||
std::string name = query_map["name"].asString();
|
||||
std::string slurl = query_map["slurl"].asString();
|
||||
LLUUID owner = query_map["owner"].asUUID();
|
||||
bool group_owned = query_map.has("groupowned");
|
||||
|
||||
LLObjectIMInfo::show(task_id,name,slurl,owner,group_owned);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -33,14 +33,31 @@
|
||||
#ifndef LL_LLFLOATEROBJECTIMINFO_H
|
||||
#define LL_LLFLOATEROBJECTIMINFO_H
|
||||
|
||||
namespace LLObjectIMInfo
|
||||
#include "llfloater.h"
|
||||
|
||||
class LLFloaterObjectIMInfo : public LLFloater, public LLFloaterSingleton<LLFloaterObjectIMInfo>
|
||||
{
|
||||
// Show an LLFloaterObjectIMInfo for this object.
|
||||
static void show(const LLUUID& object_id,
|
||||
const std::string& name,
|
||||
const std::string& location,
|
||||
const LLUUID& owner_id,
|
||||
bool owner_is_group);
|
||||
public:
|
||||
LLFloaterObjectIMInfo(const LLSD& sd);
|
||||
virtual ~LLFloaterObjectIMInfo() { };
|
||||
|
||||
/*virtual*/ BOOL postBuild(void);
|
||||
|
||||
void update(LLSD& payload);
|
||||
|
||||
// UI Handlers
|
||||
static void onClickMap(void* data);
|
||||
static void onClickOwner(void* data);
|
||||
static void onClickMute(void* data);
|
||||
|
||||
void nameCallback(const LLUUID& id, const std::string& full_name, bool is_group);
|
||||
|
||||
private:
|
||||
LLUUID mObjectID;
|
||||
LLUUID mOwnerID;
|
||||
std::string mSLurl;
|
||||
std::string mName;
|
||||
bool mGroupOwned;
|
||||
};
|
||||
|
||||
#endif // LL_LLFLOATERURLDISPLAY_H
|
||||
|
||||
@@ -49,11 +49,12 @@
|
||||
|
||||
LLMap< const LLUUID, LLFloaterParcelInfo* > gPlaceInfoInstances;
|
||||
|
||||
//moved to llpanelplaces.cpp in v2
|
||||
class LLParcelHandler : public LLCommandHandler
|
||||
{
|
||||
public:
|
||||
// requires trusted browser to trigger
|
||||
LLParcelHandler() : LLCommandHandler("parcel", true) { }
|
||||
LLParcelHandler() : LLCommandHandler("parcel", UNTRUSTED_THROTTLE) { }
|
||||
bool handle(const LLSD& params, const LLSD& query_map,
|
||||
LLMediaCtrl* web)
|
||||
{
|
||||
|
||||
@@ -93,7 +93,7 @@ class LLPreferencesHandler : public LLCommandHandler
|
||||
{
|
||||
public:
|
||||
// requires trusted browser
|
||||
LLPreferencesHandler() : LLCommandHandler("preferences", true) { }
|
||||
LLPreferencesHandler() : LLCommandHandler("preferences", UNTRUSTED_BLOCK) { }
|
||||
bool handle(const LLSD& tokens, const LLSD& query_map,
|
||||
LLMediaCtrl* web)
|
||||
{
|
||||
@@ -469,7 +469,7 @@ void LLFloaterPreference::onBtnOK( void* userdata )
|
||||
llinfos << "Can't close preferences!" << llendl;
|
||||
}
|
||||
|
||||
LLPanelLogin::refreshLocation( false );
|
||||
LLPanelLogin::updateLocationSelectorsVisibility();
|
||||
}
|
||||
|
||||
|
||||
@@ -480,14 +480,14 @@ void LLFloaterPreference::onBtnApply( void* userdata )
|
||||
if (fp->hasFocus())
|
||||
{
|
||||
LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
|
||||
if (cur_focus->acceptsTextInput())
|
||||
if (cur_focus && cur_focus->acceptsTextInput())
|
||||
{
|
||||
cur_focus->onCommit();
|
||||
}
|
||||
}
|
||||
fp->apply();
|
||||
|
||||
LLPanelLogin::refreshLocation( false );
|
||||
LLPanelLogin::updateLocationSelectorsVisibility();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -51,9 +51,11 @@
|
||||
|
||||
// viewer project includes
|
||||
#include "llagent.h"
|
||||
#include "llagentui.h"
|
||||
#include "llbutton.h"
|
||||
#include "lltexturectrl.h"
|
||||
#include "llscrolllistctrl.h"
|
||||
#include "llslurl.h"
|
||||
#include "lldispatcher.h"
|
||||
#include "llviewerobject.h"
|
||||
#include "llviewerregion.h"
|
||||
@@ -122,7 +124,9 @@ void LLFloaterReporter::processRegionInfo(LLMessageSystem* msg)
|
||||
// virtual
|
||||
BOOL LLFloaterReporter::postBuild()
|
||||
{
|
||||
getChild<LLUICtrl>("abuse_location_edit")->setValue(gAgent.getSLURL());
|
||||
LLSLURL slurl;
|
||||
LLAgentUI::buildSLURL(slurl);
|
||||
getChild<LLUICtrl>("abuse_location_edit")->setValue(slurl.getSLURLString());
|
||||
|
||||
enableControls(TRUE);
|
||||
|
||||
|
||||
@@ -44,15 +44,17 @@
|
||||
#include "llappviewer.h"
|
||||
#include "llfloaterteleporthistory.h"
|
||||
#include "llfloaterworldmap.h"
|
||||
#include "llslurl.h"
|
||||
#include "lltimer.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llurldispatcher.h"
|
||||
#include "llurlsimstring.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llwindow.h"
|
||||
#include "llweb.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llurlaction.h"
|
||||
|
||||
// [RLVa:KB]
|
||||
#include "rlvhandler.h"
|
||||
// [/RLVa:KB]
|
||||
@@ -137,12 +139,12 @@ void LLFloaterTeleportHistory::addPendingEntry(std::string regionName, S16 x, S1
|
||||
// Set pending position
|
||||
mPendingPosition = llformat("%d, %d, %d", x, y, z);
|
||||
|
||||
LLSLURL slurl(regionName, LLVector3(x, y, z));
|
||||
// prepare simstring for later parsing
|
||||
mPendingSimString = regionName + llformat("/%d/%d/%d", x, y, z);
|
||||
mPendingSimString = LLWeb::escapeURL(mPendingSimString);
|
||||
mPendingSimString = LLWeb::escapeURL(slurl.getLocationString());
|
||||
|
||||
// Prepare the SLURL
|
||||
mPendingSLURL = LLURLDispatcher::buildSLURL(regionName, x, y, z);
|
||||
mPendingSLURL = slurl.getSLURLString();
|
||||
}
|
||||
|
||||
void LLFloaterTeleportHistory::addEntry(std::string parcelName)
|
||||
@@ -332,9 +334,8 @@ void LLFloaterTeleportHistory::onTeleport(void* data)
|
||||
LLFloaterTeleportHistory* self = (LLFloaterTeleportHistory*) data;
|
||||
|
||||
// build secondlife::/app link from simstring for instant teleport to destination
|
||||
std::string slapp = "secondlife:///app/teleport/" + self->mPlacesList->getFirstSelected()->getColumn(LIST_SIMSTRING)->getValue().asString();
|
||||
LLMediaCtrl* web = NULL;
|
||||
LLURLDispatcher::dispatch(slapp, web, TRUE);
|
||||
std::string slapp = "secondlife:///app/teleport/" + self->mPlacesList->getFirstSelected()->getColumn(LIST_SLURL)->getValue().asString();
|
||||
LLUrlAction::teleportToLocation(slapp);
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -344,15 +345,11 @@ void LLFloaterTeleportHistory::onShowOnMap(void* data)
|
||||
|
||||
// get simstring from selected entry and parse it for its components
|
||||
std::string simString = self->mPlacesList->getFirstSelected()->getColumn(LIST_SIMSTRING)->getValue().asString();
|
||||
std::string region = "";
|
||||
S32 x = 128;
|
||||
S32 y = 128;
|
||||
S32 z = 20;
|
||||
|
||||
LLURLSimString::parse(simString, ®ion, &x, &y, &z);
|
||||
LLSLURL slurl(simString);
|
||||
|
||||
// point world map at position
|
||||
gFloaterWorldMap->trackURL(region, x, y, z);
|
||||
gFloaterWorldMap->trackURL(slurl.getRegion(), slurl.getPosition().mV[VX], slurl.getPosition().mV[VY], slurl.getPosition().mV[VZ]);
|
||||
LLFloaterWorldMap::show(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,12 +32,15 @@
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llhttpclient.h"
|
||||
|
||||
#include "llfloaterurlentry.h"
|
||||
|
||||
#include "llpanellandmedia.h"
|
||||
#include "llpanelface.h"
|
||||
|
||||
// project includes
|
||||
#include "llcombobox.h"
|
||||
#include "llmimetypes.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llurlhistory.h"
|
||||
#include "lluictrlfactory.h"
|
||||
@@ -83,7 +86,7 @@ public:
|
||||
{
|
||||
// Set empty type to none/none. Empty string is reserved for legacy parcels
|
||||
// which have no mime type set.
|
||||
std::string resolved_mime_type = ! mime_type.empty() ? mime_type : "none/none";
|
||||
std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType();
|
||||
LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get();
|
||||
if ( floater_url_entry )
|
||||
floater_url_entry->headerFetchComplete( status, resolved_mime_type );
|
||||
@@ -165,6 +168,16 @@ void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_
|
||||
panel_media->setMediaType(mime_type);
|
||||
panel_media->setMediaURL(mMediaURLEdit->getValue().asString());
|
||||
}
|
||||
else
|
||||
{
|
||||
LLPanelFace* panel_face = dynamic_cast<LLPanelFace*>(mPanelLandMediaHandle.get());
|
||||
if(panel_face)
|
||||
{
|
||||
panel_face->setMediaType(mime_type);
|
||||
panel_face->setMediaURL(mMediaURLEdit->getValue().asString());
|
||||
}
|
||||
|
||||
}
|
||||
// Decrement the cursor
|
||||
getWindow()->decBusyCount();
|
||||
getChildView("loading_label")->setVisible( false);
|
||||
@@ -172,26 +185,18 @@ void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_
|
||||
}
|
||||
|
||||
// static
|
||||
LLHandle<LLFloater> LLFloaterURLEntry::show(LLHandle<LLPanel> parent)
|
||||
LLHandle<LLFloater> LLFloaterURLEntry::show(LLHandle<LLPanel> parent, const std::string media_url)
|
||||
{
|
||||
if (!sInstance)
|
||||
{
|
||||
sInstance = new LLFloaterURLEntry(parent);
|
||||
}
|
||||
sInstance->open();
|
||||
sInstance->updateFromLandMediaPanel();
|
||||
sInstance->addURLToCombobox(media_url);
|
||||
return sInstance->getHandle();
|
||||
}
|
||||
|
||||
void LLFloaterURLEntry::updateFromLandMediaPanel()
|
||||
{
|
||||
LLPanelLandMedia* panel_media = (LLPanelLandMedia*)mPanelLandMediaHandle.get();
|
||||
if (panel_media)
|
||||
{
|
||||
std::string media_url = panel_media->getMediaURL();
|
||||
addURLToCombobox(media_url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLFloaterURLEntry::addURLToCombobox(const std::string& media_url)
|
||||
{
|
||||
|
||||
@@ -44,10 +44,8 @@ class LLFloaterURLEntry : public LLFloater
|
||||
public:
|
||||
// Can only be shown by LLPanelLandMedia, and pushes data back into
|
||||
// that panel via the handle.
|
||||
static LLHandle<LLFloater> show(LLHandle<LLPanel> panel_land_media_handle);
|
||||
static LLHandle<LLFloater> show(LLHandle<LLPanel> panel_land_media_handle, const std::string media_url);
|
||||
/*virtual*/ BOOL postBuild();
|
||||
void updateFromLandMediaPanel();
|
||||
|
||||
void headerFetchComplete(U32 status, const std::string& mime_type);
|
||||
|
||||
bool addURLToCombobox(const std::string& media_url);
|
||||
|
||||
517
indra/newview/llfloaterwebcontent.cpp
Normal file
517
indra/newview/llfloaterwebcontent.cpp
Normal file
@@ -0,0 +1,517 @@
|
||||
/**
|
||||
* @file llfloaterwebcontent.cpp
|
||||
* @brief floater for displaying web content - e.g. profiles and search (eventually)
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llcombobox.h"
|
||||
#include "lliconctrl.h"
|
||||
#include "lllayoutstack.h"
|
||||
#include "llpluginclassmedia.h"
|
||||
#include "llprogressbar.h"
|
||||
#include "lltextbox.h"
|
||||
#include "llurlhistory.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llweb.h"
|
||||
#include "llwindow.h"
|
||||
#include "lluictrlfactory.h"
|
||||
|
||||
#include "llfloaterwebcontent.h"
|
||||
|
||||
LLFloaterWebContent::_Params::_Params()
|
||||
: url("url"),
|
||||
target("target"),
|
||||
id("id"),
|
||||
window_class("window_class", "web_content"),
|
||||
show_chrome("show_chrome", true),
|
||||
allow_address_entry("allow_address_entry", true),
|
||||
preferred_media_size("preferred_media_size"),
|
||||
trusted_content("trusted_content", false),
|
||||
show_page_title("show_page_title", true)
|
||||
{}
|
||||
|
||||
LLFloaterWebContent::LLFloaterWebContent( const Params& params )
|
||||
: LLFloater( params.id ),
|
||||
LLInstanceTracker<LLFloaterWebContent, std::string>(params.id()),
|
||||
mWebBrowser(NULL),
|
||||
mAddressCombo(NULL),
|
||||
mSecureLockIcon(NULL),
|
||||
mStatusBarText(NULL),
|
||||
mStatusBarProgress(NULL),
|
||||
mBtnBack(NULL),
|
||||
mBtnForward(NULL),
|
||||
mBtnReload(NULL),
|
||||
mBtnStop(NULL),
|
||||
mUUID(params.id()),
|
||||
mShowPageTitle(params.show_page_title),
|
||||
mKey(params)
|
||||
{
|
||||
mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this ));
|
||||
mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this ));
|
||||
mCommitCallbackRegistrar.add( "WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this ));
|
||||
mCommitCallbackRegistrar.add( "WebContent.Stop", boost::bind( &LLFloaterWebContent::onClickStop, this ));
|
||||
mCommitCallbackRegistrar.add( "WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this ));
|
||||
mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind( &LLFloaterWebContent::onPopExternal, this ));
|
||||
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_web_content.xml");
|
||||
mAgeTimer.reset();
|
||||
}
|
||||
|
||||
BOOL LLFloaterWebContent::postBuild()
|
||||
{
|
||||
// these are used in a bunch of places so cache them
|
||||
mWebBrowser = getChild< LLMediaCtrl >( "webbrowser" );
|
||||
mAddressCombo = getChild< LLComboBox >( "address" );
|
||||
mStatusBarText = getChild< LLTextBox >( "statusbartext" );
|
||||
mStatusBarProgress = getChild<LLProgressBar>("statusbarprogress" );
|
||||
|
||||
mBtnBack = getChildView( "back" );
|
||||
mBtnForward = getChildView( "forward" );
|
||||
mBtnReload = getChildView( "reload" );
|
||||
mBtnStop = getChildView( "stop" );
|
||||
|
||||
// observe browser events
|
||||
mWebBrowser->addObserver( this );
|
||||
|
||||
// these buttons are always enabled
|
||||
mBtnReload->setEnabled( true );
|
||||
getChildView("popexternal")->setEnabled( true );
|
||||
|
||||
// cache image for secure browsing
|
||||
mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag");
|
||||
|
||||
// initialize the URL history using the system URL History manager
|
||||
initializeURLHistory();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLFloaterWebContent::initializeURLHistory()
|
||||
{
|
||||
// start with an empty list
|
||||
LLCtrlListInterface* url_list = childGetListInterface("address");
|
||||
if (url_list)
|
||||
{
|
||||
url_list->operateOnAll(LLCtrlListInterface::OP_DELETE);
|
||||
}
|
||||
|
||||
// Get all of the entries in the "browser" collection
|
||||
LLSD browser_history = LLURLHistory::getURLHistory("browser");
|
||||
LLSD::array_iterator iter_history = browser_history.beginArray();
|
||||
LLSD::array_iterator end_history = browser_history.endArray();
|
||||
for(; iter_history != end_history; ++iter_history)
|
||||
{
|
||||
std::string url = (*iter_history).asString();
|
||||
if(! url.empty())
|
||||
url_list->addSimpleElement(url);
|
||||
}
|
||||
}
|
||||
|
||||
bool LLFloaterWebContent::matchesKey(const LLSD& key)
|
||||
{
|
||||
Params p(mKey);
|
||||
Params other_p(key);
|
||||
if (!other_p.target().empty() && other_p.target() != "_blank")
|
||||
{
|
||||
return other_p.target() == p.target();
|
||||
}
|
||||
else
|
||||
{
|
||||
return other_p.id() == p.id();
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterWebContent::showInstance(const std::string& window_class, Params& p)
|
||||
{
|
||||
p.window_class(window_class);
|
||||
|
||||
LLSD key = p;
|
||||
|
||||
instance_iter it = beginInstances();
|
||||
for(;it!=endInstances();++it)
|
||||
{
|
||||
if(it->mKey["window_class"].asString() == window_class)
|
||||
{
|
||||
if(it->matchesKey(key))
|
||||
{
|
||||
it->mKey = key;
|
||||
it->setKey(p.id());
|
||||
it->mAgeTimer.reset();
|
||||
it->open();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
LLFloaterWebContent* old_inst = getInstance(p.id());
|
||||
if(old_inst)
|
||||
{
|
||||
llwarns << "Replacing unexpected duplicate floater: " << p.id() << llendl;
|
||||
old_inst->mKey = key;
|
||||
old_inst->mAgeTimer.reset();
|
||||
old_inst->open();
|
||||
}
|
||||
assert(!old_inst);
|
||||
|
||||
if(!old_inst)
|
||||
LLFloaterWebContent::create(p);
|
||||
}
|
||||
|
||||
//static
|
||||
LLFloater* LLFloaterWebContent::create( Params p)
|
||||
{
|
||||
preCreate(p);
|
||||
return new LLFloaterWebContent(p);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterWebContent::closeRequest(const std::string &uuid)
|
||||
{
|
||||
LLFloaterWebContent* floaterp = instance_tracker_t::getInstance(uuid);
|
||||
if (floaterp)
|
||||
{
|
||||
floaterp->close();
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height)
|
||||
{
|
||||
LLFloaterWebContent* floaterp = instance_tracker_t::getInstance(uuid);
|
||||
if (floaterp)
|
||||
{
|
||||
floaterp->geometryChanged(x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height)
|
||||
{
|
||||
// Make sure the layout of the browser control is updated, so this calculation is correct.
|
||||
getChild<LLLayoutStack>("stack1")->updateLayout();
|
||||
|
||||
// TODO: need to adjust size and constrain position to make sure floaters aren't moved outside the window view, etc.
|
||||
LLCoordWindow window_size;
|
||||
getWindow()->getSize(&window_size);
|
||||
|
||||
// Adjust width and height for the size of the chrome on the web Browser window.
|
||||
LLRect browser_rect;
|
||||
mWebBrowser->localRectToOtherView(mWebBrowser->getLocalRect(), &browser_rect, this);
|
||||
|
||||
S32 requested_browser_bottom = window_size.mY - (y + height);
|
||||
LLRect geom;
|
||||
geom.setOriginAndSize(x - browser_rect.mLeft,
|
||||
requested_browser_bottom - browser_rect.mBottom,
|
||||
width + getRect().getWidth() - browser_rect.getWidth(),
|
||||
height + getRect().getHeight() - browser_rect.getHeight());
|
||||
|
||||
lldebugs << "geometry change: " << geom << llendl;
|
||||
|
||||
LLRect new_rect;
|
||||
getParent()->screenRectToLocal(geom, &new_rect);
|
||||
setShape(new_rect);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterWebContent::preCreate(LLFloaterWebContent::Params& p)
|
||||
{
|
||||
lldebugs << "url = " << p.url() << ", target = " << p.target() << ", uuid = " << p.id() << llendl;
|
||||
|
||||
if (!p.id.isProvided())
|
||||
{
|
||||
p.id = LLUUID::generateNewID().asString();
|
||||
}
|
||||
|
||||
if(p.target().empty() || p.target() == "_blank")
|
||||
{
|
||||
p.target = p.id();
|
||||
}
|
||||
|
||||
S32 browser_window_limit = gSavedSettings.getS32("WebContentWindowLimit");
|
||||
if(browser_window_limit != 0)
|
||||
{
|
||||
// showInstance will open a new window. Figure out how many web browsers are already open,
|
||||
// and close the least recently opened one if this will put us over the limit.
|
||||
|
||||
std::vector<LLFloaterWebContent*> instances;
|
||||
instances.reserve(instanceCount());
|
||||
instance_iter it = beginInstances();
|
||||
for(;it!=endInstances();++it)
|
||||
{
|
||||
if(it->mKey["window_class"].asString() == p.window_class.getValue())
|
||||
instances.push_back(&*it);
|
||||
}
|
||||
|
||||
std::sort(instances.begin(), instances.end(), CompareAgeDescending());
|
||||
|
||||
//LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList(p.window_class);
|
||||
lldebugs << "total instance count is " << instances.size() << llendl;
|
||||
|
||||
for(std::vector<LLFloaterWebContent*>::const_iterator iter = instances.begin(); iter != instances.end(); iter++)
|
||||
{
|
||||
lldebugs << " " << (*iter)->mKey["target"] << llendl;
|
||||
}
|
||||
|
||||
if(instances.size() >= (size_t)browser_window_limit)
|
||||
{
|
||||
// Destroy the least recently opened instance
|
||||
(*instances.begin())->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterWebContent::open_media(const Params& p)
|
||||
{
|
||||
// Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin.
|
||||
LLViewerMedia::proxyWindowOpened(p.target(), p.id());
|
||||
mWebBrowser->setHomePageUrl(p.url, "text/html");
|
||||
mWebBrowser->setTarget(p.target);
|
||||
mWebBrowser->navigateTo(p.url, "text/html");
|
||||
|
||||
set_current_url(p.url);
|
||||
|
||||
getChild<LLPanel>("status_bar")->setVisible(p.show_chrome);
|
||||
getChild<LLPanel>("nav_controls")->setVisible(p.show_chrome);
|
||||
bool address_entry_enabled = p.allow_address_entry && !p.trusted_content;
|
||||
getChildView("address")->setEnabled(address_entry_enabled);
|
||||
getChildView("popexternal")->setEnabled(address_entry_enabled);
|
||||
|
||||
if (!address_entry_enabled)
|
||||
{
|
||||
mWebBrowser->setFocus(TRUE);
|
||||
}
|
||||
|
||||
if (!p.show_chrome)
|
||||
{
|
||||
setResizeLimits(100, 100);
|
||||
}
|
||||
|
||||
if (!p.preferred_media_size().isEmpty())
|
||||
{
|
||||
getChild<LLLayoutStack>("stack1")->updateLayout();
|
||||
LLRect browser_rect = mWebBrowser->calcScreenRect();
|
||||
LLCoordWindow window_size;
|
||||
getWindow()->getSize(&window_size);
|
||||
|
||||
geometryChanged(browser_rect.mLeft, window_size.mY - browser_rect.mTop, p.preferred_media_size().getWidth(), p.preferred_media_size().getHeight());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLFloaterWebContent::onOpen()
|
||||
{
|
||||
Params params(mKey);
|
||||
|
||||
if (!params.validateBlock())
|
||||
{
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
mWebBrowser->setTrustedContent(params.trusted_content);
|
||||
|
||||
// tell the browser instance to load the specified URL
|
||||
open_media(params);
|
||||
}
|
||||
|
||||
//virtual
|
||||
void LLFloaterWebContent::onClose(bool app_quitting)
|
||||
{
|
||||
LLViewerMedia::proxyWindowClosed(mUUID);
|
||||
destroy();
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLFloaterWebContent::draw()
|
||||
{
|
||||
// this is asynchronous so we need to keep checking
|
||||
mBtnBack->setEnabled( mWebBrowser->canNavigateBack() );
|
||||
mBtnForward->setEnabled( mWebBrowser->canNavigateForward() );
|
||||
|
||||
LLFloater::draw();
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
|
||||
{
|
||||
if(event == MEDIA_EVENT_LOCATION_CHANGED)
|
||||
{
|
||||
const std::string url = self->getLocation();
|
||||
|
||||
if ( url.length() )
|
||||
mStatusBarText->setText( url );
|
||||
|
||||
set_current_url( url );
|
||||
}
|
||||
else if(event == MEDIA_EVENT_NAVIGATE_BEGIN)
|
||||
{
|
||||
// flags are sent with this event
|
||||
mBtnBack->setEnabled( self->getHistoryBackAvailable() );
|
||||
mBtnForward->setEnabled( self->getHistoryForwardAvailable() );
|
||||
|
||||
// toggle visibility of these buttons based on browser state
|
||||
mBtnReload->setVisible( false );
|
||||
mBtnStop->setVisible( true );
|
||||
|
||||
// turn "on" progress bar now we're about to start loading
|
||||
mStatusBarProgress->setVisible( true );
|
||||
}
|
||||
else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
|
||||
{
|
||||
// flags are sent with this event
|
||||
mBtnBack->setEnabled( self->getHistoryBackAvailable() );
|
||||
mBtnForward->setEnabled( self->getHistoryForwardAvailable() );
|
||||
|
||||
// toggle visibility of these buttons based on browser state
|
||||
mBtnReload->setVisible( true );
|
||||
mBtnStop->setVisible( false );
|
||||
|
||||
// turn "off" progress bar now we're loaded
|
||||
mStatusBarProgress->setVisible( false );
|
||||
|
||||
// we populate the status bar with URLs as they change so clear it now we're done
|
||||
const std::string end_str = "";
|
||||
mStatusBarText->setText( end_str );
|
||||
|
||||
// decide if secure browsing icon should be displayed
|
||||
std::string prefix = std::string("https://");
|
||||
std::string test_prefix = mCurrentURL.substr(0, prefix.length());
|
||||
LLStringUtil::toLower(test_prefix);
|
||||
if(test_prefix == prefix)
|
||||
{
|
||||
mSecureLockIcon->setVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSecureLockIcon->setVisible(false);
|
||||
}
|
||||
}
|
||||
else if(event == MEDIA_EVENT_CLOSE_REQUEST)
|
||||
{
|
||||
// The browser instance wants its window closed.
|
||||
close();
|
||||
}
|
||||
else if(event == MEDIA_EVENT_GEOMETRY_CHANGE)
|
||||
{
|
||||
geometryChanged(self->getGeometryX(), self->getGeometryY(), self->getGeometryWidth(), self->getGeometryHeight());
|
||||
}
|
||||
else if(event == MEDIA_EVENT_STATUS_TEXT_CHANGED )
|
||||
{
|
||||
const std::string text = self->getStatusText();
|
||||
if ( text.length() )
|
||||
mStatusBarText->setText( text );
|
||||
}
|
||||
else if(event == MEDIA_EVENT_PROGRESS_UPDATED )
|
||||
{
|
||||
int percent = (int)self->getProgressPercent();
|
||||
mStatusBarProgress->setPercent( percent );
|
||||
}
|
||||
else if(event == MEDIA_EVENT_NAME_CHANGED )
|
||||
{
|
||||
std::string page_title = self->getMediaName();
|
||||
// simulate browser behavior - title is empty, use the current URL
|
||||
if (mShowPageTitle)
|
||||
{
|
||||
if ( page_title.length() > 0 )
|
||||
setTitle( page_title );
|
||||
else
|
||||
setTitle( mCurrentURL );
|
||||
}
|
||||
}
|
||||
else if(event == MEDIA_EVENT_LINK_HOVERED )
|
||||
{
|
||||
const std::string link = self->getHoverLink();
|
||||
mStatusBarText->setText( link );
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterWebContent::set_current_url(const std::string& url)
|
||||
{
|
||||
mCurrentURL = url;
|
||||
|
||||
// serialize url history into the system URL History manager
|
||||
LLURLHistory::removeURL("browser", mCurrentURL);
|
||||
LLURLHistory::addURL("browser", mCurrentURL);
|
||||
|
||||
mAddressCombo->remove( mCurrentURL );
|
||||
mAddressCombo->add( mCurrentURL );
|
||||
mAddressCombo->selectByValue( mCurrentURL );
|
||||
}
|
||||
|
||||
void LLFloaterWebContent::onClickForward()
|
||||
{
|
||||
mWebBrowser->navigateForward();
|
||||
}
|
||||
|
||||
void LLFloaterWebContent::onClickBack()
|
||||
{
|
||||
mWebBrowser->navigateBack();
|
||||
}
|
||||
|
||||
void LLFloaterWebContent::onClickReload()
|
||||
{
|
||||
|
||||
if( mWebBrowser->getMediaPlugin() )
|
||||
{
|
||||
bool ignore_cache = true;
|
||||
mWebBrowser->getMediaPlugin()->browse_reload( ignore_cache );
|
||||
}
|
||||
else
|
||||
{
|
||||
mWebBrowser->navigateTo(mCurrentURL);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterWebContent::onClickStop()
|
||||
{
|
||||
if( mWebBrowser->getMediaPlugin() )
|
||||
mWebBrowser->getMediaPlugin()->browse_stop();
|
||||
|
||||
// still should happen when we catch the navigate complete event
|
||||
// but sometimes (don't know why) that event isn't sent from Qt
|
||||
// and we ghetto a point where the stop button stays active.
|
||||
mBtnReload->setVisible( true );
|
||||
mBtnStop->setVisible( false );
|
||||
}
|
||||
|
||||
void LLFloaterWebContent::onEnterAddress()
|
||||
{
|
||||
// make sure there is at least something there.
|
||||
// (perhaps this test should be for minimum length of a URL)
|
||||
std::string url = mAddressCombo->getValue().asString();
|
||||
if ( url.length() > 0 )
|
||||
{
|
||||
mWebBrowser->navigateTo( url, "text/html");
|
||||
};
|
||||
}
|
||||
|
||||
void LLFloaterWebContent::onPopExternal()
|
||||
{
|
||||
// make sure there is at least something there.
|
||||
// (perhaps this test should be for minimum length of a URL)
|
||||
std::string url = mAddressCombo->getValue().asString();
|
||||
if ( url.length() > 0 )
|
||||
{
|
||||
LLWeb::loadURLExternal( url );
|
||||
};
|
||||
}
|
||||
125
indra/newview/llfloaterwebcontent.h
Normal file
125
indra/newview/llfloaterwebcontent.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* @file llfloaterwebcontent.h
|
||||
* @brief floater for displaying web content - e.g. profiles and search (eventually)
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERWEBCONTENT_H
|
||||
#define LL_LLFLOATERWEBCONTENT_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "llmediactrl.h"
|
||||
#include "llsdparam.h"
|
||||
|
||||
class LLMediaCtrl;
|
||||
class LLComboBox;
|
||||
class LLTextBox;
|
||||
class LLProgressBar;
|
||||
class LLIconCtrl;
|
||||
|
||||
class LLFloaterWebContent :
|
||||
public LLFloater,
|
||||
public LLViewerMediaObserver,
|
||||
public LLInstanceTracker<LLFloaterWebContent, std::string>
|
||||
{
|
||||
public:
|
||||
typedef LLInstanceTracker<LLFloaterWebContent, std::string> instance_tracker_t;
|
||||
LOG_CLASS(LLFloaterWebContent);
|
||||
|
||||
struct _Params : public LLInitParam::Block<_Params>
|
||||
{
|
||||
Optional<std::string> url,
|
||||
target,
|
||||
window_class,
|
||||
id;
|
||||
Optional<bool> show_chrome,
|
||||
allow_address_entry,
|
||||
trusted_content,
|
||||
show_page_title;
|
||||
Optional<LLRect> preferred_media_size;
|
||||
|
||||
_Params();
|
||||
};
|
||||
|
||||
typedef LLSDParamAdapter<_Params> Params;
|
||||
|
||||
LLFloaterWebContent(const Params& params);
|
||||
|
||||
void initializeURLHistory();
|
||||
|
||||
static LLFloater* create(Params);
|
||||
|
||||
static void showInstance(const std::string& window_class, Params& p);
|
||||
static void closeRequest(const std::string &uuid);
|
||||
static void geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height);
|
||||
void geometryChanged(S32 x, S32 y, S32 width, S32 height);
|
||||
|
||||
/* virtual */ BOOL postBuild();
|
||||
/* virtual */ void onOpen();
|
||||
/* virtual */ bool matchesKey(const LLSD& key);
|
||||
/* virtual */ void onClose(bool app_quitting);
|
||||
/* virtual */ void draw();
|
||||
|
||||
protected:
|
||||
// inherited from LLViewerMediaObserver
|
||||
/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
|
||||
|
||||
void onClickBack();
|
||||
void onClickForward();
|
||||
void onClickReload();
|
||||
void onClickStop();
|
||||
void onEnterAddress();
|
||||
void onPopExternal();
|
||||
|
||||
static void preCreate(Params& p);
|
||||
void open_media(const Params& );
|
||||
void set_current_url(const std::string& url);
|
||||
|
||||
LLMediaCtrl* mWebBrowser;
|
||||
LLComboBox* mAddressCombo;
|
||||
LLIconCtrl* mSecureLockIcon;
|
||||
LLTextBox* mStatusBarText;
|
||||
LLProgressBar* mStatusBarProgress;
|
||||
|
||||
LLView* mBtnBack;
|
||||
LLView* mBtnForward;
|
||||
LLView* mBtnReload;
|
||||
LLView* mBtnStop;
|
||||
|
||||
std::string mCurrentURL;
|
||||
std::string mUUID;
|
||||
bool mShowPageTitle;
|
||||
|
||||
LLSD mKey;
|
||||
LLTimer mAgeTimer;
|
||||
|
||||
struct CompareAgeDescending
|
||||
{
|
||||
bool operator()(const LLFloaterWebContent* const& lhs, const LLFloaterWebContent* const& rhs)
|
||||
{
|
||||
return lhs->mAgeTimer.getElapsedTimeF64() > lhs->mAgeTimer.getElapsedTimeF64();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#endif // LL_LLFLOATERWEBCONTENT_H
|
||||
@@ -75,6 +75,7 @@
|
||||
#include "llmapimagetype.h"
|
||||
#include "llweb.h"
|
||||
#include "llwindow.h" // copyTextToClipboard()
|
||||
#include "llslurl.h"
|
||||
|
||||
|
||||
// [RLVa:KB]
|
||||
@@ -728,7 +729,7 @@ void LLFloaterWorldMap::updateLocation()
|
||||
|
||||
// Figure out where user is
|
||||
// Set the current SLURL
|
||||
mSLURL = LLURLDispatcher::buildSLURL(agent_sim_name, x, y, z);
|
||||
mSLURL = LLSLURL(agent_sim_name, LLVector3(x, y, z)).getSLURLString();
|
||||
|
||||
// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
|
||||
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
|
||||
@@ -774,7 +775,7 @@ void LLFloaterWorldMap::updateLocation()
|
||||
S32 x = llround( (F32)fmod( (F32)coord_pos[VX], (F32)REGION_WIDTH_METERS ) );
|
||||
S32 y = llround( (F32)fmod( (F32)coord_pos[VY], (F32)REGION_WIDTH_METERS ) );
|
||||
S32 z = llround( (F32)coord_pos[VZ] );
|
||||
mSLURL = LLURLDispatcher::buildSLURL(sim_name, x, y, z);
|
||||
mSLURL = LLSLURL(sim_name, LLVector3(x, y, z)).getSLURLString();
|
||||
}
|
||||
else
|
||||
{ // Empty SLURL will disable the "Copy SLURL to clipboard" button
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#include "groupchatlistener.h"
|
||||
#include "hippolimits.h" // for getMaxAgentGroups
|
||||
// [RLVa:KB] - Checked: 2011-03-28 (RLVa-1.3.0f)
|
||||
//#include "llslurl.h"
|
||||
#include "llslurl.h"
|
||||
#include "rlvhandler.h"
|
||||
// [/RLVa:KB]
|
||||
|
||||
@@ -55,7 +55,7 @@ class LLGroupHandler : public LLCommandHandler
|
||||
{
|
||||
public:
|
||||
// requires trusted browser to trigger
|
||||
LLGroupHandler() : LLCommandHandler("group", true/*UNTRUSTED_THROTTLE*/) { }
|
||||
LLGroupHandler() : LLCommandHandler("group", UNTRUSTED_THROTTLE) { }
|
||||
bool handle(const LLSD& tokens, const LLSD& query_map,
|
||||
LLMediaCtrl* web)
|
||||
{
|
||||
@@ -402,7 +402,7 @@ LLUUID LLGroupActions::startIM(const LLUUID& group_id)
|
||||
if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStartIM(group_id)) && (!gIMMgr->hasSession(group_id)) )
|
||||
{
|
||||
make_ui_sound("UISndInvalidOp");
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", group_id/*LLSLURL("group", group_id, "about").getSLURLString()*/));
|
||||
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString()));
|
||||
return LLUUID::null;
|
||||
}
|
||||
// [/RLVa:KB]
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
|
||||
// viewer includes
|
||||
#include "llpanellogin.h" // save_password_to_disk()
|
||||
#include "llslurl.h"
|
||||
#include "llstartup.h" // getStartupState()
|
||||
#include "llurlsimstring.h"
|
||||
#include "llviewercontrol.h" // gSavedSettings
|
||||
#include "llviewernetwork.h" // EGridInfo
|
||||
|
||||
@@ -79,17 +79,15 @@ void LLLoginHandler::parse(const LLSD& queryMap)
|
||||
|
||||
if (startLocation == "specify")
|
||||
{
|
||||
LLURLSimString::setString(queryMap["region"].asString());
|
||||
LLStartUp::setStartSLURL(queryMap["region"].asString());
|
||||
}
|
||||
else if (startLocation == "home")
|
||||
{
|
||||
gSavedSettings.setBOOL("LoginLastLocation", FALSE);
|
||||
LLURLSimString::setString(LLStringUtil::null);
|
||||
LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME));
|
||||
}
|
||||
else if (startLocation == "last")
|
||||
{
|
||||
gSavedSettings.setBOOL("LoginLastLocation", TRUE);
|
||||
LLURLSimString::setString(LLStringUtil::null);
|
||||
LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class LLLoginHandler : public LLCommandHandler
|
||||
{
|
||||
public:
|
||||
// allow from external browsers
|
||||
LLLoginHandler() : LLCommandHandler("login", false) { }
|
||||
LLLoginHandler() : LLCommandHandler("login", UNTRUSTED_ALLOW) { }
|
||||
/*virtual*/ bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web);
|
||||
|
||||
// Fill in our internal fields from a SLURL like
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user