From 2aacee62ad2c001b8c860f8bedc84e2b7f634fef Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 17 Feb 2010 18:17:48 -0500 Subject: Work in progress on EXT-5333: Bodyparts missing from appearance and COF --- indra/newview/llagentwearables.cpp | 33 +++++++++++++++++++++++---------- indra/newview/llappearancemgr.cpp | 36 +++++++++++++++--------------------- indra/newview/llappearancemgr.h | 12 ++++++++++++ 3 files changed, 50 insertions(+), 31 deletions(-) (limited to 'indra') diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 68ee9cd612..401e8d25c5 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -286,6 +286,7 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i } if (mTodo & CALL_RECOVERDONE) { + LLAppearanceManager::instance().addCOFItemLink(inv_item,false); gAgentWearables.recoverMissingWearableDone(); } /* @@ -1038,8 +1039,10 @@ void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void* { return; } - - if (wearable) +// BAP RESTORE TMP + if (wearable && type != WT_SHAPE) // force failure for shape to test recovery path. + +// if (wearable) { llassert(type == wearable->getType()); wearable->setItemID(wear_data->mItemID); @@ -1057,6 +1060,7 @@ void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void* // Somehow the asset doesn't exist in the database. gAgentWearables.recoverMissingWearable(type,index); } + gInventory.notifyObservers(); @@ -2484,7 +2488,7 @@ class LLFetchAndLinkObserver: public LLInventoryFetchObserver public: LLFetchAndLinkObserver(LLInventoryFetchObserver::item_ref_t& ids): m_ids(ids), - LLInventoryFetchObserver(true) + LLInventoryFetchObserver(true) // retry for missing items { } ~LLFetchAndLinkObserver() @@ -2493,7 +2497,9 @@ public: virtual void done() { gInventory.removeObserver(this); + // Link to all fetched items in COF. + LLPointer link_waiter = new LLUpdateAppearanceOnDestroy; for (LLInventoryFetchObserver::item_ref_t::iterator it = m_ids.begin(); it != m_ids.end(); ++it) @@ -2505,8 +2511,13 @@ public: llwarns << "fetch failed!" << llendl; continue; } - link_inventory_item(gAgent.getID(), item->getLinkedUUID(), LLAppearanceManager::instance().getCOF(), item->getName(), - LLAssetType::AT_LINK, LLPointer(NULL)); + + link_inventory_item(gAgent.getID(), + item->getLinkedUUID(), + LLAppearanceManager::instance().getCOF(), + item->getName(), + LLAssetType::AT_LINK, + link_waiter); } } private: @@ -2529,11 +2540,13 @@ void LLInitialWearablesFetch::processWearablesMessage() #ifdef USE_CURRENT_OUTFIT_FOLDER ids.push_back(wearable_data->mItemID); #endif - // Fetch the wearables - LLWearableList::instance().getAsset(wearable_data->mAssetID, - LLStringUtil::null, - LLWearableDictionary::getAssetType(wearable_data->mType), - LLAgentWearables::onInitialWearableAssetArrived, (void*)(wearable_data)); +#if 0 +// // Fetch the wearables +// LLWearableList::instance().getAsset(wearable_data->mAssetID, +// LLStringUtil::null, +// LLWearableDictionary::getAssetType(wearable_data->mType), +// LLAgentWearables::onInitialWearableAssetArrived, (void*)(wearable_data)); +#endif } else { diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index eb4a47664b..9da341b669 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -301,32 +301,26 @@ void LLOutfitFetch::done() delete this; } -class LLUpdateAppearanceOnDestroy: public LLInventoryCallback +LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(): + mFireCount(0) { -public: - LLUpdateAppearanceOnDestroy(): - mFireCount(0) - { - } +} - virtual ~LLUpdateAppearanceOnDestroy() +LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() +{ + llinfos << "done update appearance on destroy" << llendl; + + if (!LLApp::isExiting()) { - llinfos << "done update appearance on destroy" << llendl; - - if (!LLApp::isExiting()) - { - LLAppearanceManager::instance().updateAppearanceFromCOF(); - } + LLAppearanceManager::instance().updateAppearanceFromCOF(); } +} - /* virtual */ void fire(const LLUUID& inv_item) - { - llinfos << "callback fired" << llendl; - mFireCount++; - } -private: - U32 mFireCount; -}; +void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) +{ + llinfos << "callback fired" << llendl; + mFireCount++; +} struct LLFoundData { diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 28b51ee0f6..e7e2f33520 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -151,6 +151,18 @@ public: BOOL getIsProtectedCOFItem(const LLUUID& obj_id) const; }; +class LLUpdateAppearanceOnDestroy: public LLInventoryCallback +{ +public: + LLUpdateAppearanceOnDestroy(); + virtual ~LLUpdateAppearanceOnDestroy(); + /* virtual */ void fire(const LLUUID& inv_item); + +private: + U32 mFireCount; +}; + + #define SUPPORT_ENSEMBLES 0 LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name); -- cgit v1.2.3 From 284eb11a102af4889f3e1a1ef97699f67e4c0fa3 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 18 Feb 2010 16:10:35 -0500 Subject: Work in progress on EXT-5333: Bodyparts missing from appearance and COF --- indra/newview/llagentwearables.cpp | 6 +++--- indra/newview/llappearancemgr.cpp | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'indra') diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index a955696447..94fd5132ca 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -1040,9 +1040,9 @@ void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void* return; } // BAP RESTORE TMP - if (wearable && type != WT_SHAPE) // force failure for shape to test recovery path. +// if (wearable && type != WT_SHAPE) // force failure for shape to test recovery path. -// if (wearable) + if (wearable) { llassert(type == wearable->getType()); wearable->setItemID(wear_data->mItemID); @@ -1580,7 +1580,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it const LLDynamicArray< LLWearable* >& wearables, BOOL remove) { - lldebugs << "setWearableOutfit() start" << llendl; + llinfos << "setWearableOutfit() start" << llendl; BOOL wearables_to_remove[WT_COUNT]; wearables_to_remove[WT_SHAPE] = FALSE; diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 9da341b669..74c45a9467 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -712,7 +712,8 @@ void LLAppearanceManager::linkAll(const LLUUID& category, void LLAppearanceManager::updateCOF(const LLUUID& category, bool append) { - llinfos << "starting" << llendl; + LLViewerInventoryCategory *pcat = gInventory.getCategory(category); + llinfos << "starting, cat " << (pcat ? pcat->getName() : "[UNKNOWN]") << llendl; const LLUUID cof = getCOF(); -- cgit v1.2.3 From 626049851d444de5c46f10d30ed476ffed74f4c1 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 19 Feb 2010 17:39:03 -0500 Subject: Work in progress on EXT-5333: Bodyparts missing from appearance and COF --- indra/newview/llappearancemgr.cpp | 373 +++++++++++++++++++++++++++++++------- 1 file changed, 309 insertions(+), 64 deletions(-) (limited to 'indra') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 74c45a9467..ae1a7a0cbe 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -324,21 +324,29 @@ void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) struct LLFoundData { - LLFoundData() : mAssetType(LLAssetType::AT_NONE), mWearable(NULL) {} + LLFoundData() : + mAssetType(LLAssetType::AT_NONE), + mWearableType(WT_INVALID), + mWearable(NULL) {} + LLFoundData(const LLUUID& item_id, - const LLUUID& asset_id, - const std::string& name, - LLAssetType::EType asset_type) : + const LLUUID& asset_id, + const std::string& name, + const LLAssetType::EType& asset_type, + const EWearableType& wearable_type + ) : mItemID(item_id), mAssetID(asset_id), mName(name), mAssetType(asset_type), + mWearableType(wearable_type), mWearable( NULL ) {} LLUUID mItemID; LLUUID mAssetID; std::string mName; LLAssetType::EType mAssetType; + EWearableType mWearableType; LLWearable* mWearable; }; @@ -349,14 +357,26 @@ public: LLWearableHoldingPattern(); ~LLWearableHoldingPattern(); - bool pollCompletion(); + bool pollFetchCompletion(); + void onFetchCompletion(); bool isFetchCompleted(); bool isTimedOut(); + + void checkMissingWearables(); + bool pollMissingWearables(); + bool isMissingCompleted(); + void recoverMissingWearable(EWearableType type); + void clearCOFLinksForMissingWearables(); + + void onAllComplete(); typedef std::list found_list_t; found_list_t mFoundList; LLInventoryModel::item_array_t mObjItems; LLInventoryModel::item_array_t mGestItems; + typedef std::set type_set_t; + type_set_t mTypesToRecover; + type_set_t mTypesToLink; S32 mResolved; LLTimer mWaitTime; bool mFired; @@ -383,13 +403,99 @@ bool LLWearableHoldingPattern::isTimedOut() return mWaitTime.getElapsedTimeF32() > max_wait_time; } -bool LLWearableHoldingPattern::pollCompletion() +void LLWearableHoldingPattern::checkMissingWearables() +{ + std::vector found_by_type(WT_COUNT,0); + std::vector requested_by_type(WT_COUNT,0); + for (found_list_t::iterator it = mFoundList.begin(); it != mFoundList.end(); ++it) + { + LLFoundData &data = *it; + if (data.mWearableType < WT_COUNT) + requested_by_type[data.mWearableType]++; + if (data.mWearable) + found_by_type[data.mWearableType]++; + } + + for (S32 type = 0; type < WT_COUNT; ++type) + { + llinfos << "type " << type << " requested " << requested_by_type[type] << " found " << found_by_type[type] << llendl; + if (found_by_type[type] > 0) + continue; + if ( + // Need to recover if at least one wearable of that type + // was requested but none was found (prevent missing + // pants) + (requested_by_type[type] > 0) || + // or if type is a body part and no wearables were found. + ((type == WT_SHAPE) || (type == WT_SKIN) || (type == WT_HAIR) || (type == WT_EYES))) + { + mTypesToRecover.insert(type); + mTypesToLink.insert(type); + recoverMissingWearable((EWearableType)type); + llwarns << "need to replace " << type << llendl; + } + } + + if (!pollMissingWearables()) + { + mWaitTime.reset(); + doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this)); + } +} + +void LLWearableHoldingPattern::onAllComplete() +{ + // Activate all gestures in this folder + if (mGestItems.count() > 0) + { + llinfos << "Activating " << mGestItems.count() << " gestures" << llendl; + + LLGestureManager::instance().activateGestures(mGestItems); + + // Update the inventory item labels to reflect the fact + // they are active. + LLViewerInventoryCategory* catp = + gInventory.getCategory(LLAppearanceManager::instance().getCOF()); + + if (catp) + { + gInventory.updateCategory(catp); + gInventory.notifyObservers(); + } + } + + // Update wearables. + llinfos << "Updating agent wearables with " << mResolved << " wearable items " << llendl; + LLAppearanceManager::instance().updateAgentWearables(this, false); + + // Update attachments to match those requested. + LLVOAvatar* avatar = gAgent.getAvatarObject(); + if( avatar ) + { + llinfos << "Updating " << mObjItems.count() << " attachments" << llendl; + LLAgentWearables::userUpdateAttachments(mObjItems); + } + + if (isFetchCompleted() && isMissingCompleted()) + { + // Only safe to delete if all wearable callbacks and all missing wearables completed. + delete this; + } +} + +void LLWearableHoldingPattern::onFetchCompletion() +{ + checkMissingWearables(); +} + +// Runs as an idle callback until all wearables are fetched (or we time out). +bool LLWearableHoldingPattern::pollFetchCompletion() { bool completed = isFetchCompleted(); bool timed_out = isTimedOut(); bool done = completed || timed_out; - llinfos << "polling, done status: " << completed << " timed out? " << timed_out << " elapsed " << mWaitTime.getElapsedTimeF32() << llendl; + llinfos << "polling, done status: " << completed << " timed out " << timed_out << " elapsed " << mWaitTime.getElapsedTimeF32() << llendl; if (done) { @@ -400,46 +506,193 @@ bool LLWearableHoldingPattern::pollCompletion() llwarns << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << llendl; } - // Activate all gestures in this folder - if (mGestItems.count() > 0) - { - llinfos << "Activating " << mGestItems.count() << " gestures" << llendl; - - LLGestureManager::instance().activateGestures(mGestItems); - - // Update the inventory item labels to reflect the fact - // they are active. - LLViewerInventoryCategory* catp = - gInventory.getCategory(LLAppearanceManager::instance().getCOF()); + onFetchCompletion(); + } + return done; +} - if (catp) - { - gInventory.updateCategory(catp); - gInventory.notifyObservers(); - } - } +class RecoveredItemLinkCB: public LLInventoryCallback +{ +public: + RecoveredItemLinkCB(EWearableType type, LLWearable *wearable, LLWearableHoldingPattern* holder): + mHolder(holder), + mWearable(wearable), + mType(type) + { + } + void fire(const LLUUID& item_id) + { + llinfos << "Recovered item link for type " << mType << llendl; + mHolder->mTypesToLink.erase(mType); + // Add wearable to FoundData for actual wearing + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; - // Update wearables. - llinfos << "Updating agent wearables with " << mResolved << " wearable items " << llendl; - LLAppearanceManager::instance().updateAgentWearables(this, false); - - // Update attachments to match those requested. - LLVOAvatar* avatar = gAgent.getAvatarObject(); - if( avatar ) + gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); + + if (item && linked_item) { - llinfos << "Updating " << mObjItems.count() << " attachments" << llendl; - LLAgentWearables::userUpdateAttachments(mObjItems); + LLFoundData found(linked_item->getUUID(), + linked_item->getAssetUUID(), + linked_item->getName(), + linked_item->getType(), + linked_item->isWearableType() ? linked_item->getWearableType() : WT_INVALID + ); + found.mWearable = mWearable; + mHolder->mFoundList.push_front(found); } + else + { + llwarns << "inventory item or link not found for recovered wearable" << llendl; + } + } +private: + LLWearableHoldingPattern* mHolder; + LLWearable *mWearable; + EWearableType mType; +}; + +class RecoveredItemCB: public LLInventoryCallback +{ +public: + RecoveredItemCB(EWearableType type, LLWearable *wearable, LLWearableHoldingPattern* holder): + mHolder(holder), + mWearable(wearable), + mType(type) + { + } + void fire(const LLUUID& item_id) + { + llinfos << "Recovered item for type " << mType << llendl; + LLViewerInventoryItem *itemp = gInventory.getItem(item_id); + LLPointer cb = new RecoveredItemLinkCB(mType,mWearable,mHolder); + mHolder->mTypesToRecover.erase(mType); + link_inventory_item( gAgent.getID(), + item_id, + LLAppearanceManager::instance().getCOF(), + itemp->getName(), + LLAssetType::AT_LINK, + cb); + } +private: + LLWearableHoldingPattern* mHolder; + LLWearable *mWearable; + EWearableType mType; +}; - if (completed) +void LLWearableHoldingPattern::recoverMissingWearable(EWearableType type) +{ + // Try to recover by replacing missing wearable with a new one. + LLNotificationsUtil::add("ReplacedMissingWearable"); + lldebugs << "Wearable " << LLWearableDictionary::getTypeLabel(type) + << " could not be downloaded. Replaced inventory item with default wearable." << llendl; + LLWearable* wearable = LLWearableList::instance().createNewWearable(type); + + // Add a new one in the lost and found folder. + const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + LLPointer cb = new RecoveredItemCB(type,wearable,this); + + create_inventory_item(gAgent.getID(), + gAgent.getSessionID(), + lost_and_found_id, + wearable->getTransactionID(), + wearable->getName(), + wearable->getDescription(), + wearable->getAssetType(), + LLInventoryType::IT_WEARABLE, + wearable->getType(), + wearable->getPermissions().getMaskNextOwner(), + cb); +} + +bool LLWearableHoldingPattern::isMissingCompleted() +{ + return mTypesToLink.size()==0 && mTypesToRecover.size()==0; +} + +void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() +{ + for (found_list_t::iterator it = mFoundList.begin(); it != mFoundList.end(); ++it) + { + LLFoundData &data = *it; + if ((data.mWearableType < WT_COUNT) && (!data.mWearable)) { - // Only safe to delete if all wearable callbacks completed. - delete this; + // Wearable link that was never resolved; remove links to it from COF + llinfos << "removing link for unresolved item " << data.mItemID.asString() << llendl; + LLAppearanceManager::instance().removeCOFItemLinks(data.mItemID,false); } } +} + +bool LLWearableHoldingPattern::pollMissingWearables() +{ + bool timed_out = isTimedOut(); + bool missing_completed = isMissingCompleted(); + bool done = timed_out || missing_completed; + + llinfos << "polling missing wearables, waiting for items " << mTypesToRecover.size() + << " links " << mTypesToLink.size() + << " wearables, timed out " << timed_out + << " elapsed " << mWaitTime.getElapsedTimeF32() + << " done " << done << llendl; + + if (done) + { + clearCOFLinksForMissingWearables(); + onAllComplete(); + } return done; } +static void onWearableAssetFetch(LLWearable* wearable, void* data) +{ + LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data; + holder->mResolved += 1; // just counting callbacks, not successes. + llinfos << "onWearableAssetFetch, resolved " << holder->mResolved << " requested " << holder->mFoundList.size() << llendl; + if (wearable) + { + llinfos << "wearable type " << wearable->getType() << llendl; + } + else + { + llinfos << "wearable: NONE" << llendl; + } + + if (holder->mFired) + { + llwarns << "called after holder fired" << llendl; + return; + } + + if (!wearable) + { + llwarns << "no wearable found" << llendl; + return; + } + +#if 0 + if ((wearable->getType() == WT_SHAPE) || (wearable->getType() == WT_JACKET)) + { + llwarns << "Forcing failure for type " << wearable->getType() << llendl; + return; + } +#endif + + for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin(); + iter != holder->mFoundList.end(); ++iter) + { + LLFoundData& data = *iter; + if(wearable->getAssetID() == data.mAssetID) + { + data.mWearable = wearable; + // Failing this means inventory or asset server are corrupted in a way we don't handle. + llassert((data.mWearableType < WT_COUNT) && (wearable->getType() == data.mWearableType)); + break; + } + } +} + + static void removeDuplicateItems(LLInventoryModel::item_array_t& items) { LLInventoryModel::item_array_t new_items; @@ -467,30 +720,6 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items) items = new_items; } -static void onWearableAssetFetch(LLWearable* wearable, void* data) -{ - LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data; - if (holder->mFired) - { - llwarns << "called after holder fired" << llendl; - } - - if(wearable) - { - for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin(); - iter != holder->mFoundList.end(); ++iter) - { - LLFoundData& data = *iter; - if(wearable->getAssetID() == data.mAssetID) - { - data.mWearable = wearable; - break; - } - } - } - holder->mResolved += 1; -} - const LLUUID LLAppearanceManager::getCOF() const { return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); @@ -888,6 +1117,8 @@ void LLAppearanceManager::updateAppearanceFromCOF() // wearables can be resolved immediately, then the // callback will be called (and this object deleted) // before the final getNextData(). + + // BAP cleanup - no point having found_container when mFoundList already has all the info. LLDynamicArray found_container; for(S32 i = 0; i < wear_items.count(); ++i) { @@ -898,7 +1129,19 @@ void LLAppearanceManager::updateAppearanceFromCOF() LLFoundData found(linked_item->getUUID(), linked_item->getAssetUUID(), linked_item->getName(), - linked_item->getType()); + linked_item->getType(), + linked_item->isWearableType() ? linked_item->getWearableType() : WT_INVALID + ); + +#if 1 + // BAP REMOVEME Force failure to test handling + if (found.mWearableType == WT_SHAPE || found.mWearableType == WT_JACKET) + { + found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB + + } +#endif + holder->mFoundList.push_front(found); found_container.put(found); } @@ -918,7 +1161,9 @@ void LLAppearanceManager::updateAppearanceFromCOF() for(S32 i = 0; i < found_container.count(); ++i) { LLFoundData& found = found_container.get(i); - + + llinfos << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << llendl; + // Fetch the wearables about to be worn. LLWearableList::instance().getAsset(found.mAssetID, found.mName, @@ -928,9 +1173,9 @@ void LLAppearanceManager::updateAppearanceFromCOF() } - if (!holder->pollCompletion()) + if (!holder->pollFetchCompletion()) { - doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollCompletion,holder)); + doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder)); } } -- cgit v1.2.3 From 79f05f9d279dc72c795ecaca6a51f976667962ae Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Sun, 21 Feb 2010 12:46:40 +0000 Subject: Remove a linux-specific #include that we don't actually use. --- indra/newview/llstartup.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'indra') diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index fa07278cb9..83f773fadc 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -200,10 +200,6 @@ #include "lldxhardware.h" #endif -#if (LL_LINUX || LL_SOLARIS) && LL_GTK -#include -#endif - // // exported globals // -- cgit v1.2.3 From 68ebf9d5a508f13487208c0e861078f4563a11b7 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 11:12:54 +0000 Subject: start of work on EXT-5601 Linux: volume adjustment of web-based media / Flash these libs are a temporary requirement - we'll dlopen() them when this is finished. --- indra/media_plugins/webkit/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra') diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt index 4512c22b5d..a9e202da99 100644 --- a/indra/media_plugins/webkit/CMakeLists.txt +++ b/indra/media_plugins/webkit/CMakeLists.txt @@ -50,6 +50,8 @@ set(media_plugin_webkit_LINK_LIBRARIES if (LINUX) list(APPEND media_plugin_webkit_LINK_LIBRARIES ${UI_LIBRARIES} # for glib/GTK + pulse + pulse-mainloop-glib ) endif (LINUX) -- cgit v1.2.3 From 3546075abf5c99e5157e3be9c540deb11609707e Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 11:28:53 +0000 Subject: start to build up this code --- .../media_plugins/webkit/linux_volume_catcher.cpp | 1009 ++++++++++++++++++++ 1 file changed, 1009 insertions(+) create mode 100644 indra/media_plugins/webkit/linux_volume_catcher.cpp (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp new file mode 100644 index 0000000000..cd68c20be1 --- /dev/null +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -0,0 +1,1009 @@ +/** + * @file linux_volume_catcher.cpp + * @brief A Linux-specific, PulseAudio-specific hack to detect and volume-adjust new audio sources + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * @endcond + */ + +#include "llqtwebkit.h" + +#include "linden_common.h" +#include "indra_constants.h" // for indra keyboard codes + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#if LL_WINDOWS +#include +#else +#include +#include +#endif + +#if LL_WINDOWS + // *NOTE:Mani - This captures the module handle fo rthe dll. This is used below + // to get the path to this dll for webkit initialization. + // I don't know how/if this can be done with apr... + namespace { HMODULE gModuleHandle;}; + BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) + { + gModuleHandle = (HMODULE) hinstDLL; + return TRUE; + } +#endif + +//////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginWebKit : + public MediaPluginBase, + public LLEmbeddedBrowserWindowObserver +{ +public: + MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginWebKit(); + + /*virtual*/ void receiveMessage(const char *message_string); + +private: + + std::string mProfileDir; + + enum + { + INIT_STATE_UNINITIALIZED, // Browser instance hasn't been set up yet + INIT_STATE_NAVIGATING, // Browser instance has been set up and initial navigate to about:blank has been issued + INIT_STATE_NAVIGATE_COMPLETE, // initial navigate to about:blank has completed + INIT_STATE_WAIT_REDRAW, // First real navigate begin has been received, waiting for page changed event to start handling redraws + INIT_STATE_WAIT_COMPLETE, // Waiting for first real navigate complete event + INIT_STATE_RUNNING // All initialization gymnastics are complete. + }; + int mBrowserWindowId; + int mInitState; + std::string mInitialNavigateURL; + bool mNeedsUpdate; + + bool mCanCut; + bool mCanCopy; + bool mCanPaste; + int mLastMouseX; + int mLastMouseY; + bool mFirstFocus; + F32 mBackgroundR; + F32 mBackgroundG; + F32 mBackgroundB; + + void setInitState(int state) + { +// std::cerr << "changing init state to " << state << std::endl; + mInitState = state; + } + + //////////////////////////////////////////////////////////////////////////////// + // + void update(int milliseconds) + { + LLQtWebKit::getInstance()->pump( milliseconds ); + + checkEditState(); + + if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) + { + if(!mInitialNavigateURL.empty()) + { + // We already have the initial navigate URL -- kick off the navigate. + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mInitialNavigateURL ); + mInitialNavigateURL.clear(); + } + } + + if ( (mInitState > INIT_STATE_WAIT_REDRAW) && mNeedsUpdate ) + { + const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId ); + + unsigned int buffer_size = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId ) * LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId ); + +// std::cerr << "webkit plugin: updating" << std::endl; + + // TODO: should get rid of this memcpy if possible + if ( mPixels && browser_pixels ) + { +// std::cerr << " memcopy of " << buffer_size << " bytes" << std::endl; + memcpy( mPixels, browser_pixels, buffer_size ); + } + + if ( mWidth > 0 && mHeight > 0 ) + { +// std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl; + setDirty( 0, 0, mWidth, mHeight ); + } + + mNeedsUpdate = false; + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + bool initBrowser() + { + // already initialized + if ( mInitState > INIT_STATE_UNINITIALIZED ) + return true; + + // not enough information to initialize the browser yet. + if ( mWidth < 0 || mHeight < 0 || mDepth < 0 || + mTextureWidth < 0 || mTextureHeight < 0 ) + { + return false; + }; + + // set up directories + char cwd[ FILENAME_MAX ]; // I *think* this is defined on all platforms we use + if (NULL == getcwd( cwd, FILENAME_MAX - 1 )) + { + llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl; + return false; + } + std::string application_dir = std::string( cwd ); + +#if LL_DARWIN + // When running under the Xcode debugger, there's a setting called "Break on Debugger()/DebugStr()" which defaults to being turned on. + // This causes the environment variable USERBREAK to be set to 1, which causes these legacy calls to break into the debugger. + // This wouldn't cause any problems except for the fact that the current release version of the Flash plugin has a call to Debugger() in it + // which gets hit when the plugin is probed by webkit. + // Unsetting the environment variable here works around this issue. + unsetenv("USERBREAK"); +#endif + +#if LL_WINDOWS + //*NOTE:Mani - On windows, at least, the component path is the + // location of this dll's image file. + std::string component_dir; + char dll_path[_MAX_PATH]; + DWORD len = GetModuleFileNameA(gModuleHandle, (LPCH)&dll_path, _MAX_PATH); + while(len && dll_path[ len ] != ('\\') ) + { + len--; + } + if(len >= 0) + { + dll_path[len] = 0; + component_dir = dll_path; + } + else + { + // *NOTE:Mani - This case should be an rare exception. + // GetModuleFileNameA should always give you a full path, no? + component_dir = application_dir; + } +#else + std::string component_dir = application_dir; +#endif + + // window handle - needed on Windows and must be app window. +#if LL_WINDOWS + char window_title[ MAX_PATH ]; + GetConsoleTitleA( window_title, MAX_PATH ); + void* native_window_handle = (void*)FindWindowA( NULL, window_title ); +#else + void* native_window_handle = 0; +#endif + + // main browser initialization + bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle ); + if ( result ) + { + // create single browser window + mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight ); +#if LL_WINDOWS + // Enable plugins + LLQtWebKit::getInstance()->enablePlugins(true); +#elif LL_DARWIN + // Enable plugins + LLQtWebKit::getInstance()->enablePlugins(true); +#elif LL_LINUX + // Enable plugins + LLQtWebKit::getInstance()->enablePlugins(true); +#endif + // Enable cookies + LLQtWebKit::getInstance()->enableCookies( true ); + + // tell LLQtWebKit about the size of the browser window + LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); + + // observer events that LLQtWebKit emits + LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this ); + + // append details to agent string + LLQtWebKit::getInstance()->setBrowserAgentId( "LLPluginMedia Web Browser" ); + + // don't flip bitmap + LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true ); + + // set background color + // convert background color channels from [0.0, 1.0] to [0, 255]; + LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, int(mBackgroundR * 255.0f), int(mBackgroundG * 255.0f), int(mBackgroundB * 255.0f) ); + + // Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns. + setInitState(INIT_STATE_NAVIGATING); + + // Don't do this here -- it causes the dreaded "white flash" when loading a browser instance. + // FIXME: Re-added this because navigating to a "page" initializes things correctly - especially + // for the HTTP AUTH dialog issues (DEV-41731). Will fix at a later date. + // Build a data URL like this: "data:text/html,%3Chtml%3E%3Cbody bgcolor=%22#RRGGBB%22%3E%3C/body%3E%3C/html%3E" + // where RRGGBB is the background color in HTML style + std::stringstream url; + + url << "data:text/html,%3Chtml%3E%3Cbody%20bgcolor=%22#"; + // convert background color channels from [0.0, 1.0] to [0, 255]; + url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundR * 255.0f); + url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundG * 255.0f); + url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f); + url << "%22%3E%3C/body%3E%3C/html%3E"; + + lldebugs << "data url is: " << url.str() << llendl; + + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() ); +// LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" ); + + return true; + }; + + return false; + }; + + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onCursorChanged(const EventType& event) + { + LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue(); + std::string name; + + switch(llqt_cursor) + { + case LLQtWebKit::C_ARROW: + name = "arrow"; + break; + case LLQtWebKit::C_IBEAM: + name = "ibeam"; + break; + case LLQtWebKit::C_SPLITV: + name = "splitv"; + break; + case LLQtWebKit::C_SPLITH: + name = "splith"; + break; + case LLQtWebKit::C_POINTINGHAND: + name = "hand"; + break; + + default: + llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl; + break; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed"); + message.setValue("name", name); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onPageChanged( const EventType& event ) + { + if(mInitState == INIT_STATE_WAIT_REDRAW) + { + setInitState(INIT_STATE_WAIT_COMPLETE); + } + + // flag that an update is required + mNeedsUpdate = true; + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onNavigateBegin(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); + message.setValue("uri", event.getEventUri()); + sendMessage(message); + + setStatus(STATUS_LOADING); + } + + if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) + { + // Skip the WAIT_REDRAW state now -- with the right background color set, it should no longer be necessary. +// setInitState(INIT_STATE_WAIT_REDRAW); + setInitState(INIT_STATE_WAIT_COMPLETE); + } + + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onNavigateComplete(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + if(mInitState < INIT_STATE_RUNNING) + { + setInitState(INIT_STATE_RUNNING); + + // Clear the history, so the "back" button doesn't take you back to "about:blank". + LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); + message.setValue("uri", event.getEventUri()); + message.setValueS32("result_code", event.getIntValue()); + message.setValue("result_string", event.getStringValue()); + message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK)); + message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD)); + sendMessage(message); + + setStatus(STATUS_LOADED); + } + else if(mInitState == INIT_STATE_NAVIGATING) + { + setInitState(INIT_STATE_NAVIGATE_COMPLETE); + } + + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onUpdateProgress(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress"); + message.setValueS32("percent", event.getIntValue()); + sendMessage(message); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onStatusTextChange(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text"); + message.setValue("status", event.getStringValue()); + sendMessage(message); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onTitleChange(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); + message.setValue("name", event.getStringValue()); + sendMessage(message); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onLocationChange(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed"); + message.setValue("uri", event.getEventUri()); + sendMessage(message); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onClickLinkHref(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href"); + message.setValue("uri", event.getStringValue()); + message.setValue("target", event.getStringValue2()); + message.setValueU32("target_type", event.getLinkType()); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onClickLinkNoFollow(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow"); + message.setValue("uri", event.getStringValue()); + sendMessage(message); + } + + LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers) + { + int result = 0; + + if(modifiers.find("shift") != std::string::npos) + result |= LLQtWebKit::KM_MODIFIER_SHIFT; + + if(modifiers.find("alt") != std::string::npos) + result |= LLQtWebKit::KM_MODIFIER_ALT; + + if(modifiers.find("control") != std::string::npos) + result |= LLQtWebKit::KM_MODIFIER_CONTROL; + + if(modifiers.find("meta") != std::string::npos) + result |= LLQtWebKit::KM_MODIFIER_META; + + return (LLQtWebKit::EKeyboardModifier)result; + } + + //////////////////////////////////////////////////////////////////////////////// + // + void deserializeKeyboardData( LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers ) + { + native_scan_code = 0; + native_virtual_key = 0; + native_modifiers = 0; + + if( native_key_data.isMap() ) + { +#if LL_DARWIN + native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger()); + native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger()); + native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); +#elif LL_WINDOWS + native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger()); + native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); + // TODO: I don't think we need to do anything with native modifiers here -- please verify +#elif LL_LINUX + native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger()); + native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); + native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); +#else + // Add other platforms here as needed +#endif + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) + { + // The incoming values for 'key' will be the ones from indra_constants.h + std::string utf8_text; + + if(key < KEY_SPECIAL) + { + // Low-ascii characters need to get passed through. + utf8_text = (char)key; + } + + // Any special-case handling we want to do for particular keys... + switch((KEY)key) + { + // ASCII codes for some standard keys + case LLQtWebKit::KEY_BACKSPACE: utf8_text = (char)8; break; + case LLQtWebKit::KEY_TAB: utf8_text = (char)9; break; + case LLQtWebKit::KEY_RETURN: utf8_text = (char)13; break; + case LLQtWebKit::KEY_PAD_RETURN: utf8_text = (char)13; break; + case LLQtWebKit::KEY_ESCAPE: utf8_text = (char)27; break; + + default: + break; + } + +// std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl; + + uint32_t native_scan_code = 0; + uint32_t native_virtual_key = 0; + uint32_t native_modifiers = 0; + deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers ); + + LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); + + checkEditState(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) + { + uint32_t key = LLQtWebKit::KEY_NONE; + +// std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl; + + if(utf8str.size() == 1) + { + // The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character. + // In this case, use it as the key value. + key = utf8str[0]; + } + + uint32_t native_scan_code = 0; + uint32_t native_virtual_key = 0; + uint32_t native_modifiers = 0; + deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers ); + + LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); + LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); + + checkEditState(); + }; + + void checkEditState(void) + { + bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT); + bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY); + bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE); + + if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste)) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state"); + + if(can_cut != mCanCut) + { + mCanCut = can_cut; + message.setValueBoolean("cut", can_cut); + } + + if(can_copy != mCanCopy) + { + mCanCopy = can_copy; + message.setValueBoolean("copy", can_copy); + } + + if(can_paste != mCanPaste) + { + mCanPaste = can_paste; + message.setValueBoolean("paste", can_paste); + } + + sendMessage(message); + + } + } + +}; + +MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) : + MediaPluginBase(host_send_func, host_user_data) +{ +// std::cerr << "MediaPluginWebKit constructor" << std::endl; + + mBrowserWindowId = 0; + mInitState = INIT_STATE_UNINITIALIZED; + mNeedsUpdate = true; + mCanCut = false; + mCanCopy = false; + mCanPaste = false; + mLastMouseX = 0; + mLastMouseY = 0; + mFirstFocus = true; + mBackgroundR = 0.0f; + mBackgroundG = 0.0f; + mBackgroundB = 0.0f; +} + +MediaPluginWebKit::~MediaPluginWebKit() +{ + // unhook observer + LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); + + // clean up + LLQtWebKit::getInstance()->reset(); + +// std::cerr << "MediaPluginWebKit destructor" << std::endl; +} + +void MediaPluginWebKit::receiveMessage(const char *message_string) +{ +// std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl; + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if(message_name == "init") + { + std::string user_data_path = message_in.getValue("user_data_path"); // n.b. always has trailing platform-specific dir-delimiter + mProfileDir = user_data_path + "browser_profile"; + + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; + message.setValueLLSD("versions", versions); + + std::string plugin_version = "Webkit media plugin, Webkit version "; + plugin_version += LLQtWebKit::getInstance()->getVersion(); + message.setValue("plugin_version", plugin_version); + sendMessage(message); + + // Plugin gets to decide the texture parameters to use. + mDepth = 4; + + message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + message.setValueS32("default_width", 1024); + message.setValueS32("default_height", 1024); + message.setValueS32("depth", mDepth); + message.setValueU32("internalformat", GL_RGBA); + message.setValueU32("format", GL_RGBA); + message.setValueU32("type", GL_UNSIGNED_BYTE); + message.setValueBoolean("coords_opengl", true); + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. + F64 time = message_in.getValueReal("time"); + + // Convert time to milliseconds for update() + update((int)(time * 1000.0f)); + } + else if(message_name == "cleanup") + { + // DTOR most likely won't be called but the recent change to the way this process + // is (not) killed means we see this message and can do what we need to here. + // Note: this cleanup is ultimately what writes cookies to the disk + LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); + LLQtWebKit::getInstance()->reset(); + } + else if(message_name == "shm_added") + { + SharedSegmentInfo info; + info.mAddress = message_in.getValuePointer("address"); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); + +// std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name +// << ", size: " << info.mSize +// << ", address: " << info.mAddress +// << std::endl; + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + + } + else if(message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + +// std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl; + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + if(mPixels == iter->second.mAddress) + { + // This is the currently active pixel buffer. Make sure we stop drawing to it. + mPixels = NULL; + mTextureSegmentName.clear(); + } + mSharedSegments.erase(iter); + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl; + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if(message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + mBackgroundR = message_in.getValueReal("background_r"); + mBackgroundG = message_in.getValueReal("background_g"); + mBackgroundB = message_in.getValueReal("background_b"); +// mBackgroundA = message_in.setValueReal("background_a"); // Ignore any alpha + + if(!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + mPixels = (unsigned char*)iter->second.mAddress; + mWidth = width; + mHeight = height; + + // initialize (only gets called once) + initBrowser(); + + // size changed so tell the browser + LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); + +// std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight +// << ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl; + + S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId); + + // The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response. + if(real_width <= texture_width) + { + texture_width = real_width; + } + else + { + // This won't work -- it'll be bigger than the allocated memory. This is a fatal error. +// std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl; + mDeleteMe = true; + return; + } + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + + }; + }; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + } + else if(message_name == "load_uri") + { + std::string uri = message_in.getValue("uri"); + +// std::cout << "loading URI: " << uri << std::endl; + + if(!uri.empty()) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri ); + } + else + { + mInitialNavigateURL = uri; + } + } + } + else if(message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + S32 button = message_in.getValueS32("button"); + mLastMouseX = message_in.getValueS32("x"); + mLastMouseY = message_in.getValueS32("y"); + std::string modifiers = message_in.getValue("modifiers"); + + // Treat unknown mouse events as mouse-moves. + LLQtWebKit::EMouseEvent mouse_event = LLQtWebKit::ME_MOUSE_MOVE; + if(event == "down") + { + mouse_event = LLQtWebKit::ME_MOUSE_DOWN; + } + else if(event == "up") + { + mouse_event = LLQtWebKit::ME_MOUSE_UP; + } + else if(event == "double_click") + { + mouse_event = LLQtWebKit::ME_MOUSE_DOUBLE_CLICK; + } + + LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, mouse_event, button, mLastMouseX, mLastMouseY, decodeModifiers(modifiers)); + checkEditState(); + } + else if(message_name == "scroll_event") + { + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + std::string modifiers = message_in.getValue("modifiers"); + + // Incoming scroll events are adjusted so that 1 detent is approximately 1 unit. + // Qt expects 1 detent to be 120 units. + // It also seems that our y scroll direction is inverted vs. what Qt expects. + + x *= 120; + y *= -120; + + LLQtWebKit::getInstance()->scrollWheelEvent(mBrowserWindowId, mLastMouseX, mLastMouseY, x, y, decodeModifiers(modifiers)); + } + else if(message_name == "key_event") + { + std::string event = message_in.getValue("event"); + S32 key = message_in.getValueS32("key"); + std::string modifiers = message_in.getValue("modifiers"); + LLSD native_key_data = message_in.getValueLLSD("native_key_data"); + + // Treat unknown events as key-up for safety. + LLQtWebKit::EKeyEvent key_event = LLQtWebKit::KE_KEY_UP; + if(event == "down") + { + key_event = LLQtWebKit::KE_KEY_DOWN; + } + else if(event == "repeat") + { + key_event = LLQtWebKit::KE_KEY_REPEAT; + } + + keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data); + } + else if(message_name == "text_event") + { + std::string text = message_in.getValue("text"); + std::string modifiers = message_in.getValue("modifiers"); + LLSD native_key_data = message_in.getValueLLSD("native_key_data"); + + unicodeInput(text, decodeModifiers(modifiers), native_key_data); + } + if(message_name == "edit_cut") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT ); + checkEditState(); + } + if(message_name == "edit_copy") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY ); + checkEditState(); + } + if(message_name == "edit_paste") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE ); + checkEditState(); + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl; + }; + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) + { + if(message_name == "focus") + { + bool val = message_in.getValueBoolean("focused"); + LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val ); + + if(mFirstFocus && val) + { + // On the first focus, post a tab key event. This fixes a problem with initial focus. + std::string empty; + keyEvent(LLQtWebKit::KE_KEY_DOWN, KEY_TAB, decodeModifiers(empty)); + keyEvent(LLQtWebKit::KE_KEY_UP, KEY_TAB, decodeModifiers(empty)); + mFirstFocus = false; + } + } + else if(message_name == "clear_cache") + { + LLQtWebKit::getInstance()->clearCache(); + } + else if(message_name == "clear_cookies") + { + LLQtWebKit::getInstance()->clearAllCookies(); + } + else if(message_name == "enable_cookies") + { + bool val = message_in.getValueBoolean("enable"); + LLQtWebKit::getInstance()->enableCookies( val ); + } + else if(message_name == "proxy_setup") + { + bool val = message_in.getValueBoolean("enable"); + std::string host = message_in.getValue("host"); + int port = message_in.getValueS32("port"); + LLQtWebKit::getInstance()->enableProxy( val, host, port ); + } + else if(message_name == "browse_stop") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP ); + } + else if(message_name == "browse_reload") + { + // foo = message_in.getValueBoolean("ignore_cache"); + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD ); + } + else if(message_name == "browse_forward") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD ); + } + else if(message_name == "browse_back") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK ); + } + else if(message_name == "set_status_redirect") + { + int code = message_in.getValueS32("code"); + std::string url = message_in.getValue("url"); + if ( 404 == code ) // browser lib only supports 404 right now + { + LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url ); + }; + } + else if(message_name == "set_user_agent") + { + std::string user_agent = message_in.getValue("user_agent"); + LLQtWebKit::getInstance()->setBrowserAgentId( user_agent ); + } + else if(message_name == "init_history") + { + // Initialize browser history + LLSD history = message_in.getValueLLSD("history"); + // First, clear the URL history + LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); + // Then, add the history items in order + LLSD::array_iterator iter_history = history.beginArray(); + LLSD::array_iterator end_history = history.endArray(); + for(; iter_history != end_history; ++iter_history) + { + std::string url = (*iter_history).asString(); + if(! url.empty()) { + LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url); + } + } + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl; + }; + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl; + }; + } +} + +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data); + *plugin_send_func = MediaPluginWebKit::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; +} + -- cgit v1.2.3 From fae5c9b64efc2f77ca10cabc6c6e3d7c583bb4b0 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 11:29:48 +0000 Subject: code code --- .../media_plugins/webkit/linux_volume_catcher.cpp | 982 +-------------------- 1 file changed, 10 insertions(+), 972 deletions(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index cd68c20be1..34f797f5b2 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -3,9 +3,9 @@ * @brief A Linux-specific, PulseAudio-specific hack to detect and volume-adjust new audio sources * * @cond - * $LicenseInfo:firstyear=2008&license=viewergpl$ + * $LicenseInfo:firstyear=2010&license=viewergpl$ * - * Copyright (c) 2008, Linden Research, Inc. + * Copyright (c) 2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -31,979 +31,17 @@ * @endcond */ -#include "llqtwebkit.h" +#include +#include +#include +#include // There's no special reason why we want the *glib* PA mainloop, but the generic non-glib implementation seems broken. -#include "linden_common.h" -#include "indra_constants.h" // for indra keyboard codes - -#include "llgl.h" - -#include "llplugininstance.h" -#include "llpluginmessage.h" -#include "llpluginmessageclasses.h" -#include "media_plugin_base.h" - -#if LL_WINDOWS -#include -#else -#include -#include -#endif - -#if LL_WINDOWS - // *NOTE:Mani - This captures the module handle fo rthe dll. This is used below - // to get the path to this dll for webkit initialization. - // I don't know how/if this can be done with apr... - namespace { HMODULE gModuleHandle;}; - BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) - { - gModuleHandle = (HMODULE) hinstDLL; - return TRUE; - } -#endif - -//////////////////////////////////////////////////////////////////////////////// -// -class MediaPluginWebKit : - public MediaPluginBase, - public LLEmbeddedBrowserWindowObserver +class LinuxVolumeCatcherImpl { public: - MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); - ~MediaPluginWebKit(); - - /*virtual*/ void receiveMessage(const char *message_string); + setVol(F32 volume); // 0.0-1.0 private: - - std::string mProfileDir; - - enum - { - INIT_STATE_UNINITIALIZED, // Browser instance hasn't been set up yet - INIT_STATE_NAVIGATING, // Browser instance has been set up and initial navigate to about:blank has been issued - INIT_STATE_NAVIGATE_COMPLETE, // initial navigate to about:blank has completed - INIT_STATE_WAIT_REDRAW, // First real navigate begin has been received, waiting for page changed event to start handling redraws - INIT_STATE_WAIT_COMPLETE, // Waiting for first real navigate complete event - INIT_STATE_RUNNING // All initialization gymnastics are complete. - }; - int mBrowserWindowId; - int mInitState; - std::string mInitialNavigateURL; - bool mNeedsUpdate; - - bool mCanCut; - bool mCanCopy; - bool mCanPaste; - int mLastMouseX; - int mLastMouseY; - bool mFirstFocus; - F32 mBackgroundR; - F32 mBackgroundG; - F32 mBackgroundB; - - void setInitState(int state) - { -// std::cerr << "changing init state to " << state << std::endl; - mInitState = state; - } - - //////////////////////////////////////////////////////////////////////////////// - // - void update(int milliseconds) - { - LLQtWebKit::getInstance()->pump( milliseconds ); - - checkEditState(); - - if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) - { - if(!mInitialNavigateURL.empty()) - { - // We already have the initial navigate URL -- kick off the navigate. - LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mInitialNavigateURL ); - mInitialNavigateURL.clear(); - } - } - - if ( (mInitState > INIT_STATE_WAIT_REDRAW) && mNeedsUpdate ) - { - const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId ); - - unsigned int buffer_size = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId ) * LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId ); - -// std::cerr << "webkit plugin: updating" << std::endl; - - // TODO: should get rid of this memcpy if possible - if ( mPixels && browser_pixels ) - { -// std::cerr << " memcopy of " << buffer_size << " bytes" << std::endl; - memcpy( mPixels, browser_pixels, buffer_size ); - } - - if ( mWidth > 0 && mHeight > 0 ) - { -// std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl; - setDirty( 0, 0, mWidth, mHeight ); - } - - mNeedsUpdate = false; - }; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - bool initBrowser() - { - // already initialized - if ( mInitState > INIT_STATE_UNINITIALIZED ) - return true; - - // not enough information to initialize the browser yet. - if ( mWidth < 0 || mHeight < 0 || mDepth < 0 || - mTextureWidth < 0 || mTextureHeight < 0 ) - { - return false; - }; - - // set up directories - char cwd[ FILENAME_MAX ]; // I *think* this is defined on all platforms we use - if (NULL == getcwd( cwd, FILENAME_MAX - 1 )) - { - llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl; - return false; - } - std::string application_dir = std::string( cwd ); - -#if LL_DARWIN - // When running under the Xcode debugger, there's a setting called "Break on Debugger()/DebugStr()" which defaults to being turned on. - // This causes the environment variable USERBREAK to be set to 1, which causes these legacy calls to break into the debugger. - // This wouldn't cause any problems except for the fact that the current release version of the Flash plugin has a call to Debugger() in it - // which gets hit when the plugin is probed by webkit. - // Unsetting the environment variable here works around this issue. - unsetenv("USERBREAK"); -#endif - -#if LL_WINDOWS - //*NOTE:Mani - On windows, at least, the component path is the - // location of this dll's image file. - std::string component_dir; - char dll_path[_MAX_PATH]; - DWORD len = GetModuleFileNameA(gModuleHandle, (LPCH)&dll_path, _MAX_PATH); - while(len && dll_path[ len ] != ('\\') ) - { - len--; - } - if(len >= 0) - { - dll_path[len] = 0; - component_dir = dll_path; - } - else - { - // *NOTE:Mani - This case should be an rare exception. - // GetModuleFileNameA should always give you a full path, no? - component_dir = application_dir; - } -#else - std::string component_dir = application_dir; -#endif - - // window handle - needed on Windows and must be app window. -#if LL_WINDOWS - char window_title[ MAX_PATH ]; - GetConsoleTitleA( window_title, MAX_PATH ); - void* native_window_handle = (void*)FindWindowA( NULL, window_title ); -#else - void* native_window_handle = 0; -#endif - - // main browser initialization - bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle ); - if ( result ) - { - // create single browser window - mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight ); -#if LL_WINDOWS - // Enable plugins - LLQtWebKit::getInstance()->enablePlugins(true); -#elif LL_DARWIN - // Enable plugins - LLQtWebKit::getInstance()->enablePlugins(true); -#elif LL_LINUX - // Enable plugins - LLQtWebKit::getInstance()->enablePlugins(true); -#endif - // Enable cookies - LLQtWebKit::getInstance()->enableCookies( true ); - - // tell LLQtWebKit about the size of the browser window - LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); - - // observer events that LLQtWebKit emits - LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this ); - - // append details to agent string - LLQtWebKit::getInstance()->setBrowserAgentId( "LLPluginMedia Web Browser" ); - - // don't flip bitmap - LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true ); - - // set background color - // convert background color channels from [0.0, 1.0] to [0, 255]; - LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, int(mBackgroundR * 255.0f), int(mBackgroundG * 255.0f), int(mBackgroundB * 255.0f) ); - - // Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns. - setInitState(INIT_STATE_NAVIGATING); - - // Don't do this here -- it causes the dreaded "white flash" when loading a browser instance. - // FIXME: Re-added this because navigating to a "page" initializes things correctly - especially - // for the HTTP AUTH dialog issues (DEV-41731). Will fix at a later date. - // Build a data URL like this: "data:text/html,%3Chtml%3E%3Cbody bgcolor=%22#RRGGBB%22%3E%3C/body%3E%3C/html%3E" - // where RRGGBB is the background color in HTML style - std::stringstream url; - - url << "data:text/html,%3Chtml%3E%3Cbody%20bgcolor=%22#"; - // convert background color channels from [0.0, 1.0] to [0, 255]; - url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundR * 255.0f); - url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundG * 255.0f); - url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f); - url << "%22%3E%3C/body%3E%3C/html%3E"; - - lldebugs << "data url is: " << url.str() << llendl; - - LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() ); -// LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" ); - - return true; - }; - - return false; - }; - - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onCursorChanged(const EventType& event) - { - LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue(); - std::string name; - - switch(llqt_cursor) - { - case LLQtWebKit::C_ARROW: - name = "arrow"; - break; - case LLQtWebKit::C_IBEAM: - name = "ibeam"; - break; - case LLQtWebKit::C_SPLITV: - name = "splitv"; - break; - case LLQtWebKit::C_SPLITH: - name = "splith"; - break; - case LLQtWebKit::C_POINTINGHAND: - name = "hand"; - break; - - default: - llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl; - break; - } - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed"); - message.setValue("name", name); - sendMessage(message); - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onPageChanged( const EventType& event ) - { - if(mInitState == INIT_STATE_WAIT_REDRAW) - { - setInitState(INIT_STATE_WAIT_COMPLETE); - } - - // flag that an update is required - mNeedsUpdate = true; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onNavigateBegin(const EventType& event) - { - if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); - message.setValue("uri", event.getEventUri()); - sendMessage(message); - - setStatus(STATUS_LOADING); - } - - if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) - { - // Skip the WAIT_REDRAW state now -- with the right background color set, it should no longer be necessary. -// setInitState(INIT_STATE_WAIT_REDRAW); - setInitState(INIT_STATE_WAIT_COMPLETE); - } - - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onNavigateComplete(const EventType& event) - { - if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) - { - if(mInitState < INIT_STATE_RUNNING) - { - setInitState(INIT_STATE_RUNNING); - - // Clear the history, so the "back" button doesn't take you back to "about:blank". - LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); - } - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); - message.setValue("uri", event.getEventUri()); - message.setValueS32("result_code", event.getIntValue()); - message.setValue("result_string", event.getStringValue()); - message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK)); - message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD)); - sendMessage(message); - - setStatus(STATUS_LOADED); - } - else if(mInitState == INIT_STATE_NAVIGATING) - { - setInitState(INIT_STATE_NAVIGATE_COMPLETE); - } - - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onUpdateProgress(const EventType& event) - { - if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress"); - message.setValueS32("percent", event.getIntValue()); - sendMessage(message); - } - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onStatusTextChange(const EventType& event) - { - if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text"); - message.setValue("status", event.getStringValue()); - sendMessage(message); - } - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onTitleChange(const EventType& event) - { - if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); - message.setValue("name", event.getStringValue()); - sendMessage(message); - } - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onLocationChange(const EventType& event) - { - if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed"); - message.setValue("uri", event.getEventUri()); - sendMessage(message); - } - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onClickLinkHref(const EventType& event) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href"); - message.setValue("uri", event.getStringValue()); - message.setValue("target", event.getStringValue2()); - message.setValueU32("target_type", event.getLinkType()); - sendMessage(message); - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onClickLinkNoFollow(const EventType& event) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow"); - message.setValue("uri", event.getStringValue()); - sendMessage(message); - } - - LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers) - { - int result = 0; - - if(modifiers.find("shift") != std::string::npos) - result |= LLQtWebKit::KM_MODIFIER_SHIFT; - - if(modifiers.find("alt") != std::string::npos) - result |= LLQtWebKit::KM_MODIFIER_ALT; - - if(modifiers.find("control") != std::string::npos) - result |= LLQtWebKit::KM_MODIFIER_CONTROL; - - if(modifiers.find("meta") != std::string::npos) - result |= LLQtWebKit::KM_MODIFIER_META; - - return (LLQtWebKit::EKeyboardModifier)result; - } - - //////////////////////////////////////////////////////////////////////////////// - // - void deserializeKeyboardData( LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers ) - { - native_scan_code = 0; - native_virtual_key = 0; - native_modifiers = 0; - - if( native_key_data.isMap() ) - { -#if LL_DARWIN - native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger()); - native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger()); - native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); -#elif LL_WINDOWS - native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger()); - native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); - // TODO: I don't think we need to do anything with native modifiers here -- please verify -#elif LL_LINUX - native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger()); - native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); - native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); -#else - // Add other platforms here as needed -#endif - }; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) - { - // The incoming values for 'key' will be the ones from indra_constants.h - std::string utf8_text; - - if(key < KEY_SPECIAL) - { - // Low-ascii characters need to get passed through. - utf8_text = (char)key; - } - - // Any special-case handling we want to do for particular keys... - switch((KEY)key) - { - // ASCII codes for some standard keys - case LLQtWebKit::KEY_BACKSPACE: utf8_text = (char)8; break; - case LLQtWebKit::KEY_TAB: utf8_text = (char)9; break; - case LLQtWebKit::KEY_RETURN: utf8_text = (char)13; break; - case LLQtWebKit::KEY_PAD_RETURN: utf8_text = (char)13; break; - case LLQtWebKit::KEY_ESCAPE: utf8_text = (char)27; break; - - default: - break; - } - -// std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl; - - uint32_t native_scan_code = 0; - uint32_t native_virtual_key = 0; - uint32_t native_modifiers = 0; - deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers ); - - LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); - - checkEditState(); - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) - { - uint32_t key = LLQtWebKit::KEY_NONE; - -// std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl; - - if(utf8str.size() == 1) - { - // The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character. - // In this case, use it as the key value. - key = utf8str[0]; - } - - uint32_t native_scan_code = 0; - uint32_t native_virtual_key = 0; - uint32_t native_modifiers = 0; - deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers ); - - LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); - LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); - - checkEditState(); - }; - - void checkEditState(void) - { - bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT); - bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY); - bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE); - - if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste)) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state"); - - if(can_cut != mCanCut) - { - mCanCut = can_cut; - message.setValueBoolean("cut", can_cut); - } - - if(can_copy != mCanCopy) - { - mCanCopy = can_copy; - message.setValueBoolean("copy", can_copy); - } - - if(can_paste != mCanPaste) - { - mCanPaste = can_paste; - message.setValueBoolean("paste", can_paste); - } - - sendMessage(message); - - } - } - -}; - -MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) : - MediaPluginBase(host_send_func, host_user_data) -{ -// std::cerr << "MediaPluginWebKit constructor" << std::endl; - - mBrowserWindowId = 0; - mInitState = INIT_STATE_UNINITIALIZED; - mNeedsUpdate = true; - mCanCut = false; - mCanCopy = false; - mCanPaste = false; - mLastMouseX = 0; - mLastMouseY = 0; - mFirstFocus = true; - mBackgroundR = 0.0f; - mBackgroundG = 0.0f; - mBackgroundB = 0.0f; + F32 mLastDesiredVolume; + pa_glib_mainloop } - -MediaPluginWebKit::~MediaPluginWebKit() -{ - // unhook observer - LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); - - // clean up - LLQtWebKit::getInstance()->reset(); - -// std::cerr << "MediaPluginWebKit destructor" << std::endl; -} - -void MediaPluginWebKit::receiveMessage(const char *message_string) -{ -// std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl; - LLPluginMessage message_in; - - if(message_in.parse(message_string) >= 0) - { - std::string message_class = message_in.getClass(); - std::string message_name = message_in.getName(); - if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) - { - if(message_name == "init") - { - std::string user_data_path = message_in.getValue("user_data_path"); // n.b. always has trailing platform-specific dir-delimiter - mProfileDir = user_data_path + "browser_profile"; - - LLPluginMessage message("base", "init_response"); - LLSD versions = LLSD::emptyMap(); - versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; - versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; - versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; - message.setValueLLSD("versions", versions); - - std::string plugin_version = "Webkit media plugin, Webkit version "; - plugin_version += LLQtWebKit::getInstance()->getVersion(); - message.setValue("plugin_version", plugin_version); - sendMessage(message); - - // Plugin gets to decide the texture parameters to use. - mDepth = 4; - - message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); - message.setValueS32("default_width", 1024); - message.setValueS32("default_height", 1024); - message.setValueS32("depth", mDepth); - message.setValueU32("internalformat", GL_RGBA); - message.setValueU32("format", GL_RGBA); - message.setValueU32("type", GL_UNSIGNED_BYTE); - message.setValueBoolean("coords_opengl", true); - sendMessage(message); - } - else if(message_name == "idle") - { - // no response is necessary here. - F64 time = message_in.getValueReal("time"); - - // Convert time to milliseconds for update() - update((int)(time * 1000.0f)); - } - else if(message_name == "cleanup") - { - // DTOR most likely won't be called but the recent change to the way this process - // is (not) killed means we see this message and can do what we need to here. - // Note: this cleanup is ultimately what writes cookies to the disk - LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); - LLQtWebKit::getInstance()->reset(); - } - else if(message_name == "shm_added") - { - SharedSegmentInfo info; - info.mAddress = message_in.getValuePointer("address"); - info.mSize = (size_t)message_in.getValueS32("size"); - std::string name = message_in.getValue("name"); - -// std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name -// << ", size: " << info.mSize -// << ", address: " << info.mAddress -// << std::endl; - - mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); - - } - else if(message_name == "shm_remove") - { - std::string name = message_in.getValue("name"); - -// std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl; - - SharedSegmentMap::iterator iter = mSharedSegments.find(name); - if(iter != mSharedSegments.end()) - { - if(mPixels == iter->second.mAddress) - { - // This is the currently active pixel buffer. Make sure we stop drawing to it. - mPixels = NULL; - mTextureSegmentName.clear(); - } - mSharedSegments.erase(iter); - } - else - { -// std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl; - } - - // Send the response so it can be cleaned up. - LLPluginMessage message("base", "shm_remove_response"); - message.setValue("name", name); - sendMessage(message); - } - else - { -// std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl; - } - } - else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) - { - if(message_name == "size_change") - { - std::string name = message_in.getValue("name"); - S32 width = message_in.getValueS32("width"); - S32 height = message_in.getValueS32("height"); - S32 texture_width = message_in.getValueS32("texture_width"); - S32 texture_height = message_in.getValueS32("texture_height"); - mBackgroundR = message_in.getValueReal("background_r"); - mBackgroundG = message_in.getValueReal("background_g"); - mBackgroundB = message_in.getValueReal("background_b"); -// mBackgroundA = message_in.setValueReal("background_a"); // Ignore any alpha - - if(!name.empty()) - { - // Find the shared memory region with this name - SharedSegmentMap::iterator iter = mSharedSegments.find(name); - if(iter != mSharedSegments.end()) - { - mPixels = (unsigned char*)iter->second.mAddress; - mWidth = width; - mHeight = height; - - // initialize (only gets called once) - initBrowser(); - - // size changed so tell the browser - LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); - -// std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight -// << ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl; - - S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId); - - // The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response. - if(real_width <= texture_width) - { - texture_width = real_width; - } - else - { - // This won't work -- it'll be bigger than the allocated memory. This is a fatal error. -// std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl; - mDeleteMe = true; - return; - } - - mTextureWidth = texture_width; - mTextureHeight = texture_height; - - }; - }; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); - message.setValue("name", name); - message.setValueS32("width", width); - message.setValueS32("height", height); - message.setValueS32("texture_width", texture_width); - message.setValueS32("texture_height", texture_height); - sendMessage(message); - - } - else if(message_name == "load_uri") - { - std::string uri = message_in.getValue("uri"); - -// std::cout << "loading URI: " << uri << std::endl; - - if(!uri.empty()) - { - if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) - { - LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri ); - } - else - { - mInitialNavigateURL = uri; - } - } - } - else if(message_name == "mouse_event") - { - std::string event = message_in.getValue("event"); - S32 button = message_in.getValueS32("button"); - mLastMouseX = message_in.getValueS32("x"); - mLastMouseY = message_in.getValueS32("y"); - std::string modifiers = message_in.getValue("modifiers"); - - // Treat unknown mouse events as mouse-moves. - LLQtWebKit::EMouseEvent mouse_event = LLQtWebKit::ME_MOUSE_MOVE; - if(event == "down") - { - mouse_event = LLQtWebKit::ME_MOUSE_DOWN; - } - else if(event == "up") - { - mouse_event = LLQtWebKit::ME_MOUSE_UP; - } - else if(event == "double_click") - { - mouse_event = LLQtWebKit::ME_MOUSE_DOUBLE_CLICK; - } - - LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, mouse_event, button, mLastMouseX, mLastMouseY, decodeModifiers(modifiers)); - checkEditState(); - } - else if(message_name == "scroll_event") - { - S32 x = message_in.getValueS32("x"); - S32 y = message_in.getValueS32("y"); - std::string modifiers = message_in.getValue("modifiers"); - - // Incoming scroll events are adjusted so that 1 detent is approximately 1 unit. - // Qt expects 1 detent to be 120 units. - // It also seems that our y scroll direction is inverted vs. what Qt expects. - - x *= 120; - y *= -120; - - LLQtWebKit::getInstance()->scrollWheelEvent(mBrowserWindowId, mLastMouseX, mLastMouseY, x, y, decodeModifiers(modifiers)); - } - else if(message_name == "key_event") - { - std::string event = message_in.getValue("event"); - S32 key = message_in.getValueS32("key"); - std::string modifiers = message_in.getValue("modifiers"); - LLSD native_key_data = message_in.getValueLLSD("native_key_data"); - - // Treat unknown events as key-up for safety. - LLQtWebKit::EKeyEvent key_event = LLQtWebKit::KE_KEY_UP; - if(event == "down") - { - key_event = LLQtWebKit::KE_KEY_DOWN; - } - else if(event == "repeat") - { - key_event = LLQtWebKit::KE_KEY_REPEAT; - } - - keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data); - } - else if(message_name == "text_event") - { - std::string text = message_in.getValue("text"); - std::string modifiers = message_in.getValue("modifiers"); - LLSD native_key_data = message_in.getValueLLSD("native_key_data"); - - unicodeInput(text, decodeModifiers(modifiers), native_key_data); - } - if(message_name == "edit_cut") - { - LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT ); - checkEditState(); - } - if(message_name == "edit_copy") - { - LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY ); - checkEditState(); - } - if(message_name == "edit_paste") - { - LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE ); - checkEditState(); - } - else - { -// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl; - }; - } - else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) - { - if(message_name == "focus") - { - bool val = message_in.getValueBoolean("focused"); - LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val ); - - if(mFirstFocus && val) - { - // On the first focus, post a tab key event. This fixes a problem with initial focus. - std::string empty; - keyEvent(LLQtWebKit::KE_KEY_DOWN, KEY_TAB, decodeModifiers(empty)); - keyEvent(LLQtWebKit::KE_KEY_UP, KEY_TAB, decodeModifiers(empty)); - mFirstFocus = false; - } - } - else if(message_name == "clear_cache") - { - LLQtWebKit::getInstance()->clearCache(); - } - else if(message_name == "clear_cookies") - { - LLQtWebKit::getInstance()->clearAllCookies(); - } - else if(message_name == "enable_cookies") - { - bool val = message_in.getValueBoolean("enable"); - LLQtWebKit::getInstance()->enableCookies( val ); - } - else if(message_name == "proxy_setup") - { - bool val = message_in.getValueBoolean("enable"); - std::string host = message_in.getValue("host"); - int port = message_in.getValueS32("port"); - LLQtWebKit::getInstance()->enableProxy( val, host, port ); - } - else if(message_name == "browse_stop") - { - LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP ); - } - else if(message_name == "browse_reload") - { - // foo = message_in.getValueBoolean("ignore_cache"); - LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD ); - } - else if(message_name == "browse_forward") - { - LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD ); - } - else if(message_name == "browse_back") - { - LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK ); - } - else if(message_name == "set_status_redirect") - { - int code = message_in.getValueS32("code"); - std::string url = message_in.getValue("url"); - if ( 404 == code ) // browser lib only supports 404 right now - { - LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url ); - }; - } - else if(message_name == "set_user_agent") - { - std::string user_agent = message_in.getValue("user_agent"); - LLQtWebKit::getInstance()->setBrowserAgentId( user_agent ); - } - else if(message_name == "init_history") - { - // Initialize browser history - LLSD history = message_in.getValueLLSD("history"); - // First, clear the URL history - LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); - // Then, add the history items in order - LLSD::array_iterator iter_history = history.beginArray(); - LLSD::array_iterator end_history = history.endArray(); - for(; iter_history != end_history; ++iter_history) - { - std::string url = (*iter_history).asString(); - if(! url.empty()) { - LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url); - } - } - } - else - { -// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl; - }; - } - else - { -// std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl; - }; - } -} - -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) -{ - MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data); - *plugin_send_func = MediaPluginWebKit::staticReceiveMessage; - *plugin_user_data = (void*)self; - - return 0; -} - -- cgit v1.2.3 From 6f98e0b9721515065b84d32428b0e55a4bde89d3 Mon Sep 17 00:00:00 2001 From: Ychebotarev ProductEngine Date: Mon, 22 Feb 2010 13:58:00 +0200 Subject: fix for EXT-5128 Groups accordions should all appear on-screen w/out scrolling (open accordion should fill space) fix is not complete since we got horizontal scrolbar which I think is not intended...need to fix croll_container. --HG-- branch : product-engine --- indra/llui/llaccordionctrl.cpp | 97 ++++++++++--- indra/llui/llaccordionctrl.h | 3 + .../skins/default/xui/en/panel_group_general.xml | 5 +- .../default/xui/en/panel_group_info_sidetray.xml | 161 ++++++++++++++------- .../default/xui/en/panel_group_land_money.xml | 3 +- .../skins/default/xui/en/panel_group_notices.xml | 5 +- .../skins/default/xui/en/panel_group_roles.xml | 5 +- 7 files changed, 193 insertions(+), 86 deletions(-) (limited to 'indra') diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index d0c73fbfbc..ae218c28c4 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -103,6 +103,13 @@ void LLAccordionCtrl::draw() LLLocalClipRect clip(local_rect); LLPanel::draw(); + /* + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); + + gl_rect_2d(0, 0 , width - 1 ,height - 1,LLColor4::green,true); + gl_line_2d(0, 0 , width - 1 ,height - 1,LLColor4::black); + */ } @@ -338,36 +345,55 @@ void LLAccordionCtrl::addCollapsibleCtrl(LLView* view) } - -void LLAccordionCtrl::arrange() +void LLAccordionCtrl::arrangeSinge() { - if( mAccordionTabs.size() == 0) - { - //We do not arrange if we do not have what should be arranged - return; - } - - //Calculate params S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel + S32 panel_height; - - if(mAccordionTabs.size() == 1) + S32 collapsed_height = 0; + + for(size_t i=0;i(mAccordionTabs[0]); - - LLRect panel_rect = accordion_tab->getRect(); + LLAccordionCtrlTab* accordion_tab = dynamic_cast(mAccordionTabs[i]); - S32 panel_height = getRect().getHeight() - 2*BORDER_MARGIN; + if(accordion_tab->getVisible() == false) //skip hidden accordion tabs + continue; + if(!accordion_tab->isExpanded() ) + { + collapsed_height+=mAccordionTabs[i]->getRect().getHeight(); + } + } - ctrlSetLeftTopAndSize(accordion_tab,panel_rect.mLeft,panel_top,panel_width,panel_height); + S32 expanded_height = getRect().getHeight() - BORDER_MARGIN - collapsed_height; + + for(size_t i=0;i(mAccordionTabs[i]); - show_hide_scrollbar(getRect().getWidth(),getRect().getHeight()); - return; - + if(accordion_tab->getVisible() == false) //skip hidden accordion tabs + continue; + if(!accordion_tab->isExpanded() ) + { + panel_height = accordion_tab->getRect().getHeight(); + } + else + { + panel_height = expanded_height; + } + ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height); + panel_top-=mAccordionTabs[i]->getRect().getHeight(); } +} + +void LLAccordionCtrl::arrangeMultiple() +{ + S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter + S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel + S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel + //Calculate params for(size_t i = 0; i < mAccordionTabs.size(); i++ ) { LLAccordionCtrlTab* accordion_tab = dynamic_cast(mAccordionTabs[i]); @@ -415,7 +441,40 @@ void LLAccordionCtrl::arrange() show_hide_scrollbar(getRect().getWidth(),getRect().getHeight()); updateLayout(getRect().getWidth(),getRect().getHeight()); +} + + +void LLAccordionCtrl::arrange() +{ + if( mAccordionTabs.size() == 0) + { + //We do not arrange if we do not have what should be arranged + return; + } + + if(mAccordionTabs.size() == 1) + { + S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel + S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel + + LLAccordionCtrlTab* accordion_tab = dynamic_cast(mAccordionTabs[0]); + + LLRect panel_rect = accordion_tab->getRect(); + + S32 panel_height = getRect().getHeight() - 2*BORDER_MARGIN; + + ctrlSetLeftTopAndSize(accordion_tab,panel_rect.mLeft,panel_top,panel_width,panel_height); + + show_hide_scrollbar(getRect().getWidth(),getRect().getHeight()); + return; + + } + + if(mSingleExpansion) + arrangeSinge (); + else + arrangeMultiple (); } //--------------------------------------------------------------------------------- diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h index d57a42df32..7c29e545b7 100644 --- a/indra/llui/llaccordionctrl.h +++ b/indra/llui/llaccordionctrl.h @@ -105,6 +105,9 @@ public: void reset (); private: + void arrangeSinge(); + void arrangeMultiple(); + // Calc Splitter's height that is necessary to display all child content S32 calcRecuiredHeight(); S32 getRecuiredHeight() const { return mInnerRect.getHeight(); } diff --git a/indra/newview/skins/default/xui/en/panel_group_general.xml b/indra/newview/skins/default/xui/en/panel_group_general.xml index 41e53be29e..f913c58cc9 100644 --- a/indra/newview/skins/default/xui/en/panel_group_general.xml +++ b/indra/newview/skins/default/xui/en/panel_group_general.xml @@ -1,9 +1,8 @@ + bg_alpha_color="DkGray2" + bg_opaque_color="DkGray2" + background_visible="true" + background_opaque="true" + name="group_accordions" + follows="all" + layout="topleft" + auto_resize="true"> - + - + + + - + + + + + - + left="0" + name="profile_scroll" + opaque="true" + height="530" + width="304" + top="0"> + + + - + - + left="0" + name="profile_scroll" + opaque="true" + height="500" + width="304" + top="0"> + + + diff --git a/indra/newview/skins/default/xui/en/panel_group_land_money.xml b/indra/newview/skins/default/xui/en/panel_group_land_money.xml index 38b0f234d5..7996a89e72 100644 --- a/indra/newview/skins/default/xui/en/panel_group_land_money.xml +++ b/indra/newview/skins/default/xui/en/panel_group_land_money.xml @@ -1,14 +1,13 @@ + width="304"> A warning appears until the Total Land in Use is less than or = to the Total Contribution. diff --git a/indra/newview/skins/default/xui/en/panel_group_notices.xml b/indra/newview/skins/default/xui/en/panel_group_notices.xml index 5f46ad7860..731b3c119c 100644 --- a/indra/newview/skins/default/xui/en/panel_group_notices.xml +++ b/indra/newview/skins/default/xui/en/panel_group_notices.xml @@ -1,13 +1,12 @@ + width="304"> Notices let you send a message and an optionally attached item. @@ -44,7 +43,7 @@ Maximum 200 per group daily right="-1" name="notice_list" top_pad="0" - width="313"> + width="304"> + width="304"> There are unsaved changes @@ -31,7 +30,7 @@ tab_height="22" tab_min_width="90" top="0" - width="313"> + width="304"> Date: Mon, 22 Feb 2010 12:03:31 +0000 Subject: fill out the interface. --- indra/media_plugins/webkit/linux_volume_catcher.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 34f797f5b2..637560eaab 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -34,14 +34,19 @@ #include #include #include -#include // There's no special reason why we want the *glib* PA mainloop, but the generic non-glib implementation seems broken. +#include // There's no special reason why we want the *glib* PA mainloop, but the generic polling implementation seems broken. class LinuxVolumeCatcherImpl { public: - setVol(F32 volume); // 0.0-1.0 + //void setVol(F32 volume); // 0.0-1.0 + //LinuxVolumeCatcherImpl *impl; private: - F32 mLastDesiredVolume; - pa_glib_mainloop + F32 mDesiredVolume; + pa_glib_mainloop *mMainloop; + pa_context *mLastContext; + bool connected; + std::set mSinkInputIndices; + std::map mSinkInputNumChannels; } -- cgit v1.2.3 From ab9ed2fd39d9a083c09e8e5b5e2f0b237da0db86 Mon Sep 17 00:00:00 2001 From: Paul Guslisty Date: Mon, 22 Feb 2010 14:03:42 +0200 Subject: Fixed major bug EXT - 5351 (Lack of Highlighting Makes Selected Me > Preferences Tab Difficult to Identify) - Pointed to correct texture name for SELECTED state of the tab --HG-- branch : product-engine --- indra/newview/skins/default/xui/en/widgets/tab_container.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/widgets/tab_container.xml b/indra/newview/skins/default/xui/en/widgets/tab_container.xml index 4a163fc1e3..8d6b0c1cfe 100644 --- a/indra/newview/skins/default/xui/en/widgets/tab_container.xml +++ b/indra/newview/skins/default/xui/en/widgets/tab_container.xml @@ -16,17 +16,17 @@ label_pad_left - padding to the left of tab button labels tab_bottom_image_unselected="Toolbar_Left_Off" tab_bottom_image_selected="Toolbar_Left_Selected" tab_left_image_unselected="SegmentedBtn_Left_Disabled" - tab_left_image_selected="SegmentedBtn_Left_Off"/> + tab_left_image_selected="SegmentedBtn_Left_Selected_Over"/> + tab_left_image_selected="SegmentedBtn_Left_Selected_Over"/> + tab_left_image_selected="SegmentedBtn_Left_Selected_Over"/> -- cgit v1.2.3 From 865a4b4c613379aa503e8da4d546cab89df6704a Mon Sep 17 00:00:00 2001 From: Eugene Mutavchi Date: Mon, 22 Feb 2010 14:07:07 +0200 Subject: Fixed normal bug EXT-4682 (Edit Linked Parts (from menu) appears to have no effect) --HG-- branch : product-engine --- indra/newview/llviewermenu.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 989cfae464..02bde51fb6 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -6897,7 +6897,8 @@ class LLToolsEditLinkedParts : public view_listener_t { bool handleEvent(const LLSD& userdata) { - BOOL select_individuals = gSavedSettings.getBOOL("EditLinkedParts"); + BOOL select_individuals = !gSavedSettings.getBOOL("EditLinkedParts"); + gSavedSettings.setBOOL( "EditLinkedParts", select_individuals ); if (select_individuals) { LLSelectMgr::getInstance()->demoteSelectionToIndividuals(); -- cgit v1.2.3 From 2ab798d681d8aec653b1727d8cc1c5f02e5bb766 Mon Sep 17 00:00:00 2001 From: Eugene Mutavchi Date: Mon, 22 Feb 2010 14:07:07 +0200 Subject: Fixed normal bug EXT-5506 (Group list in profile truncates without "more" link) --HG-- branch : product-engine --- indra/newview/skins/default/xui/en/panel_profile.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml index d72e175bc4..412485e03f 100644 --- a/indra/newview/skins/default/xui/en/panel_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_profile.xml @@ -284,10 +284,11 @@ width="300" /> Date: Mon, 22 Feb 2010 14:30:06 +0200 Subject: fix for normal "Archived Notice" field not cleared when looking at notice list of another group --HG-- branch : product-engine --- indra/newview/llpanelgroupnotices.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra') diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 6210973dae..5f913d5469 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -652,6 +652,9 @@ void LLPanelGroupNotices::setGroupID(const LLUUID& id) LLGroupDropTarget* target = getChild ("drop_target"); target->setPanel (this); target->setGroup (mGroupID); + + if(mViewMessage) + mViewMessage->clear(); activate(); } -- cgit v1.2.3 From aa654ae427a8b6566494186f72c505e371d8ca00 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 12:32:07 +0000 Subject: more work on the linux volume-catcher. --- indra/media_plugins/webkit/linux_volume_catcher.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 637560eaab..c2d8885dc0 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -31,6 +31,10 @@ * @endcond */ +#include "linden_common.h" + +#include + #include #include #include @@ -40,6 +44,7 @@ class LinuxVolumeCatcherImpl { public: //void setVol(F32 volume); // 0.0-1.0 + //void pump(void); //LinuxVolumeCatcherImpl *impl; private: @@ -50,3 +55,5 @@ private: std::set mSinkInputIndices; std::map mSinkInputNumChannels; } + + -- cgit v1.2.3 From 1b6a57564c166e9b54eba8e6a1eccc4399d387ec Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 12:36:10 +0000 Subject: more work on the volume-catcher interface. --- indra/media_plugins/webkit/linux_volume_catcher.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index c2d8885dc0..8d8600c344 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -43,9 +43,8 @@ class LinuxVolumeCatcherImpl { public: - //void setVol(F32 volume); // 0.0-1.0 - //void pump(void); - //LinuxVolumeCatcherImpl *impl; + void setVol(F32 volume); + void pump(void); private: F32 mDesiredVolume; -- cgit v1.2.3 From 83779c45a1735c551bb4e2af5bb32d8b5ef376e1 Mon Sep 17 00:00:00 2001 From: Ychebotarev ProductEngine Date: Mon, 22 Feb 2010 14:46:53 +0200 Subject: fix for normal EXT-5326 Cannot access full group options in God mode --HG-- branch : product-engine --- indra/newview/llpanelgroup.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 61463ed843..706787e824 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -337,7 +337,7 @@ void LLPanelGroup::update(LLGroupChange gc) childSetToolTip("group_name",gdatap->mName); LLGroupData agent_gdatap; - bool is_member = gAgent.getGroupData(mID,agent_gdatap); + bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlike(); bool join_btn_visible = !is_member && gdatap->mOpenEnrollment; mButtonJoin->setVisible(join_btn_visible); @@ -466,7 +466,7 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id) } LLGroupData agent_gdatap; - bool is_member = gAgent.getGroupData(mID,agent_gdatap); + bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlike(); tab_roles->setVisible(is_member); tab_notices->setVisible(is_member); -- cgit v1.2.3 From 9c66a9b6eb18276823a91e344a82787149ad7c15 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 13:12:44 +0000 Subject: Really start to fill the implementation in. --- .../media_plugins/webkit/linux_volume_catcher.cpp | 141 ++++++++++++++++++++- 1 file changed, 140 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 8d8600c344..43731fe8d0 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -40,19 +40,158 @@ #include #include // There's no special reason why we want the *glib* PA mainloop, but the generic polling implementation seems broken. +#include "linux_volume_catcher.h" + +//////////////////////////////////////////////////// + +LinuxVolumeCatcher::LinuxVolumeCatcher() +{ + pimpl = new LinuxVolumeCatcherImpl(); +} + +LinuxVolumeCatcher::LinuxVolumeCatcher~() +{ + delete pimpl; + pimpl = NULL; +} + +void LinuxVolumeCatcher::setVol(F32 volume) +{ + llassert(pimpl); + pimpl->setVol(volume); +} + +void LinuxVolumeCatcher::pump() +{ + llassert(pimpl); + pimpl->pump(); +} + +///////////////////////////////////////////////////// + +// PulseAudio requires a chain of callbacks with C linkage +extern "C" { + void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *i, int eol, void *userdata); + void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata); + void callback_context_state(pa_context *context, void *userdata); +} + + class LinuxVolumeCatcherImpl { public: + LinuxVolumeCatcherImpl(); + ~LinuxVolumeCatcherImpl(); + void setVol(F32 volume); void pump(void); private: + void init(); + void cleanup(); + + void connected_okay(); + void update_index_volume(F32 volume); + void update_all_volumes(F32 volume); + F32 mDesiredVolume; pa_glib_mainloop *mMainloop; - pa_context *mLastContext; + pa_context *mPAContext; bool connected; std::set mSinkInputIndices; std::map mSinkInputNumChannels; +}; + +LinuxVolumeCatcherImpl::LinuxVolumeCatcherImpl() + : mDesiredVolume(0.0f), + mMainloop(NULL), + mPAContext(NULL), + mConnected(false) +{ + init(); } +LinuxVolumeCatcherImpl::~LinuxVolumeCatcherImpl() +{ + cleanup(); +} + +LinuxVolumeCatcherImpl::init() +{ + // try to be as robust as possible because PA's interface is a + // bit fragile and (for our purposes) we'd rather simply not function + // than crash + mMainloop = pa_glib_mainloop_new(g_main_context_default()); + if (mMainloop) + { + pa_mainloop_api *api = pa_glib_mainloop_get_api(mMainloop); + if (api) + { + pa_proplist *proplist = pa_proplist_new(); + if (proplist) + { + pa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "multimedia-player"); + pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.secondlife.viewer.mediaplugvoladjust"); + pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "SL Plugin Volume Adjuster"); + pa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, "1"); + + // plain old pa_context_new() is broken! + mPAContext = pa_context_new_with_proplist(api, NULL, proplist); + pa_proplist_free(proplist); + } + } + } + + // Now we've set up a PA context and mainloop, try connecting the + // PA context to a PA daemon. + if (mPAContext) + { + pa_context_set_state_callback(mPAContext, callback_context_state, NULL); + pa_context_flags_t cflags = 0; // maybe add PA_CONTEXT_NOAUTOSPAWN? + if (pa_context_connect(mPAContext, NULL, cflags, NULL) >= 0) + { + // Okay! We haven't definitely connected, but we + // haven't definitely failed yet. + } + else + { + // Failed to connect to PA manager... we'll leave + // things like that. Perhaps we should try again later. + } + } +} + +LinuxVolumeCatcherImpl::cleanup() +{ + // there's some cleanup we could do, but do nothing... for now. +} + +LinuxVolumeCatcherImpl::setVol(F32 volume) +{ + mDesiredVolume = volume; + + if (mConnected && mPAContext) + { + update_all_volumes(mDesiredVolume); + } + + pump(); +} + +LinuxVolumeCatcherImpl::pump() +{ + g_main_context_iteration(g_main_context_default()); +} + +void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *i, int eol, void *userdata) +{ +} + +void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata) +{ +} + +void callback_context_state(pa_context *context, void *userdata) +{ +} -- cgit v1.2.3 From 7fb16ca505d8291448b5538b4f6203bf47bced40 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 13:52:41 +0000 Subject: pretty fleshed-out, now needs fixing-up. --- indra/media_plugins/webkit/CMakeLists.txt | 11 +- .../media_plugins/webkit/linux_volume_catcher.cpp | 202 +++++++++++++++++---- 2 files changed, 170 insertions(+), 43 deletions(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt index a9e202da99..a43680bb16 100644 --- a/indra/media_plugins/webkit/CMakeLists.txt +++ b/indra/media_plugins/webkit/CMakeLists.txt @@ -34,11 +34,6 @@ set(media_plugin_webkit_SOURCE_FILES media_plugin_webkit.cpp ) -add_library(media_plugin_webkit - SHARED - ${media_plugin_webkit_SOURCE_FILES} -) - set(media_plugin_webkit_LINK_LIBRARIES ${LLPLUGIN_LIBRARIES} ${MEDIA_PLUGIN_BASE_LIBRARIES} @@ -48,6 +43,7 @@ set(media_plugin_webkit_LINK_LIBRARIES ) if (LINUX) + list(APPEND media_plugin_webkit_SOURCE_FILES linux_volume_catcher.cpp) list(APPEND media_plugin_webkit_LINK_LIBRARIES ${UI_LIBRARIES} # for glib/GTK pulse @@ -55,6 +51,11 @@ if (LINUX) ) endif (LINUX) +add_library(media_plugin_webkit + SHARED + ${media_plugin_webkit_SOURCE_FILES} +) + target_link_libraries(media_plugin_webkit ${media_plugin_webkit_LINK_LIBRARIES}) add_dependencies(media_plugin_webkit diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 43731fe8d0..6eb5a9a30c 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -44,31 +44,6 @@ //////////////////////////////////////////////////// -LinuxVolumeCatcher::LinuxVolumeCatcher() -{ - pimpl = new LinuxVolumeCatcherImpl(); -} - -LinuxVolumeCatcher::LinuxVolumeCatcher~() -{ - delete pimpl; - pimpl = NULL; -} - -void LinuxVolumeCatcher::setVol(F32 volume) -{ - llassert(pimpl); - pimpl->setVol(volume); -} - -void LinuxVolumeCatcher::pump() -{ - llassert(pimpl); - pimpl->pump(); -} - -///////////////////////////////////////////////////// - // PulseAudio requires a chain of callbacks with C linkage extern "C" { void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *i, int eol, void *userdata); @@ -86,20 +61,21 @@ public: void setVol(F32 volume); void pump(void); -private: + // for internal use - can't be private because used from our C callbacks + void init(); void cleanup(); - void connected_okay(); - void update_index_volume(F32 volume); void update_all_volumes(F32 volume); + void update_index_volume(U32 index, F32 volume); + void connected_okay(); + std::set mSinkInputIndices; + std::map mSinkInputNumChannels; F32 mDesiredVolume; pa_glib_mainloop *mMainloop; pa_context *mPAContext; - bool connected; - std::set mSinkInputIndices; - std::map mSinkInputNumChannels; + bool mConnected; }; LinuxVolumeCatcherImpl::LinuxVolumeCatcherImpl() @@ -116,7 +92,7 @@ LinuxVolumeCatcherImpl::~LinuxVolumeCatcherImpl() cleanup(); } -LinuxVolumeCatcherImpl::init() +void LinuxVolumeCatcherImpl::init() { // try to be as robust as possible because PA's interface is a // bit fragile and (for our purposes) we'd rather simply not function @@ -146,8 +122,8 @@ LinuxVolumeCatcherImpl::init() // PA context to a PA daemon. if (mPAContext) { - pa_context_set_state_callback(mPAContext, callback_context_state, NULL); - pa_context_flags_t cflags = 0; // maybe add PA_CONTEXT_NOAUTOSPAWN? + pa_context_set_state_callback(mPAContext, callback_context_state, this); + pa_context_flags_t cflags = (pa_context_flags)0; // maybe add PA_CONTEXT_NOAUTOSPAWN? if (pa_context_connect(mPAContext, NULL, cflags, NULL) >= 0) { // Okay! We haven't definitely connected, but we @@ -161,12 +137,14 @@ LinuxVolumeCatcherImpl::init() } } -LinuxVolumeCatcherImpl::cleanup() +void LinuxVolumeCatcherImpl::cleanup() { // there's some cleanup we could do, but do nothing... for now. + + mConnected = false; } -LinuxVolumeCatcherImpl::setVol(F32 volume) +void LinuxVolumeCatcherImpl::setVol(F32 volume) { mDesiredVolume = volume; @@ -178,20 +156,168 @@ LinuxVolumeCatcherImpl::setVol(F32 volume) pump(); } -LinuxVolumeCatcherImpl::pump() +void LinuxVolumeCatcherImpl::pump() { g_main_context_iteration(g_main_context_default()); } -void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *i, int eol, void *userdata) +void LinuxVolumeCatcherImpl::connected_okay() { + pa_operation *op; + + // fetch global list of existing sinkinputs + if (op = pa_context_get_sink_input_info_list(mPAContext, + callback_discovered_sinkinput, + this)) + { + pa_operation_unref(op); + } + + // subscribe to future global sinkinput changes + pa_context_set_subscribe_callback(mPAContext, + callback_subscription_alert, + this); + if (op = pa_context_subscribe(mPAContext, (pa_subscription_mask_t) + (PA_SUBSCRIPTION_MASK_SINK_INPUT), + NULL, NULL)) + { + pa_operation_unref(op); + } +} + +void LinuxVolumeCatcherImpl::update_all_volumes(F32 volume) +{ + for (std::set::iterator it = mSinkInputIndices.begin(); + it != mSinkInputIndices.end(); ++it) + { + update_index_volume(*it, volume); + } +} + +void LinuxVolumeCatcherImpl::update_index_volume(U32 index, F32 volume) +{ + static pa_cvolume cvol; + pa_cvolume_set(&cvol, mSinkInputNumChannels[index], + pa_sw_volume_from_linear(volume)); + + pa_context *c = mPAContext; + uint32_t idx = index; + const pa_cvolume *volume = &cvol; + pa_context_success_cb_t cb = NULL; // okay as null + void *userdata = NULL; // okay as null + + if (op = pa_context_set_sink_input_volume(c, idx, volume, cb, userdata)) + { + pa_operation_unref(op); + } +} + + +void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *sii, int eol, void *userdata) +{ + LinuxVolumeCatcherImpl *impl = dynamic_cast(userdata); + llassert(impl); + + if (0 == eol) + { + pa_proplist *proplist = sii->proplist; + pid_t sinkpid = atoll(pa_proplist_gets(proplist, PA_PROP_APPLICATION_PROCESS_ID)); + fprintf(stderr, "Found sinkinput #%d, name=%s, pid=%d\t", sii->index, sii->name, int(sinkpid)); + + if (sinkpid == getpid()) // does the discovered sinkinput belong to this process? + { + bool is_new = (impl->mSinkInputIndices.find(sii->index) == + impl->mSinkInputIndices.end()); + + impl->mSinkInputIndices.insert(sii->index); + impl->mSinkInputNumChannels[sii->index] = sii->channel_map.channels; + + if (is_new) + { + // new! + fprintf(stderr, "\nJACKPOT!\n"); + impl->update_index_volume(sii->index, impl->mDesiredVolume); + } + else + { + // seen it already, do nothing. + } + } + } } void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata) { + LinuxVolumeCatcherImpl *impl = dynamic_cast(userdata); + llassert(impl); + + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == + PA_SUBSCRIPTION_EVENT_REMOVE) + { + // forget this sinkinput, if we were caring about it + impl->mSinkInputIndices.erase(index); + impl->mSinkInputNumChannels.erase(index); + } + else + { + // ask for more info about this new sinkinput + pa_operation *op; + if (op = pa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl)) + { + pa_operation_unref(o); + } + } + break; + + default:; + } } void callback_context_state(pa_context *context, void *userdata) { + LinuxVolumeCatcherImpl *impl = dynamic_cast(userdata); + llassert(impl); + + switch (pa_context_get_state(c)) + { + case PA_CONTEXT_READY: + impl->mConnected = true; + impl->connected_okay(c); + break; + case PA_CONTEXT_TERMINATED: + impl->mConnected = false; + break; + case PA_CONTEXT_FAILED: + impl->mConnected = false; + break; + default:; + } +} + +///////////////////////////////////////////////////// + +LinuxVolumeCatcher::LinuxVolumeCatcher() +{ + pimpl = new LinuxVolumeCatcherImpl(); +} + +LinuxVolumeCatcher::LinuxVolumeCatcher~() +{ + delete pimpl; + pimpl = NULL; +} + +void LinuxVolumeCatcher::setVol(F32 volume) +{ + llassert(pimpl); + pimpl->setVol(volume); +} + +void LinuxVolumeCatcher::pump() +{ + llassert(pimpl); + pimpl->pump(); } -- cgit v1.2.3 From 8c7d218f4e5cc83296dcfba0e238ca2cc57c6b74 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 13:55:19 +0000 Subject: bunch o'fixing --- indra/media_plugins/webkit/linux_volume_catcher.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 6eb5a9a30c..a6a2ec7c7a 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -158,7 +158,8 @@ void LinuxVolumeCatcherImpl::setVol(F32 volume) void LinuxVolumeCatcherImpl::pump() { - g_main_context_iteration(g_main_context_default()); + gboolean may_block = FALSE; + g_main_context_iteration(g_main_context_default(), may_block); } void LinuxVolumeCatcherImpl::connected_okay() @@ -166,9 +167,9 @@ void LinuxVolumeCatcherImpl::connected_okay() pa_operation *op; // fetch global list of existing sinkinputs - if (op = pa_context_get_sink_input_info_list(mPAContext, + if ((op = pa_context_get_sink_input_info_list(mPAContext, callback_discovered_sinkinput, - this)) + this))) { pa_operation_unref(op); } @@ -177,9 +178,9 @@ void LinuxVolumeCatcherImpl::connected_okay() pa_context_set_subscribe_callback(mPAContext, callback_subscription_alert, this); - if (op = pa_context_subscribe(mPAContext, (pa_subscription_mask_t) + if ((op = pa_context_subscribe(mPAContext, (pa_subscription_mask_t) (PA_SUBSCRIPTION_MASK_SINK_INPUT), - NULL, NULL)) + NULL, NULL))) { pa_operation_unref(op); } @@ -202,11 +203,11 @@ void LinuxVolumeCatcherImpl::update_index_volume(U32 index, F32 volume) pa_context *c = mPAContext; uint32_t idx = index; - const pa_cvolume *volume = &cvol; + const pa_cvolume *cvolumep = &cvol; pa_context_success_cb_t cb = NULL; // okay as null void *userdata = NULL; // okay as null - if (op = pa_context_set_sink_input_volume(c, idx, volume, cb, userdata)) + if ((op = pa_context_set_sink_input_volume(c, idx, cvolumep, cb, userdata))) { pa_operation_unref(op); } @@ -264,7 +265,7 @@ void callback_subscription_alert(pa_context *context, pa_subscription_event_type { // ask for more info about this new sinkinput pa_operation *op; - if (op = pa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl)) + if ((op = pa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl))) { pa_operation_unref(o); } -- cgit v1.2.3 From 551771fd90e2caf58856b746d4dfc108679cc05f Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 14:00:10 +0000 Subject: Got this building okay now. It's not hooked-up to the webkit plugin yet, so I don't know if it *works*. --- indra/media_plugins/webkit/linux_volume_catcher.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index a6a2ec7c7a..1439f1c5a5 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -206,7 +206,8 @@ void LinuxVolumeCatcherImpl::update_index_volume(U32 index, F32 volume) const pa_cvolume *cvolumep = &cvol; pa_context_success_cb_t cb = NULL; // okay as null void *userdata = NULL; // okay as null - + + pa_operation *op; if ((op = pa_context_set_sink_input_volume(c, idx, cvolumep, cb, userdata))) { pa_operation_unref(op); @@ -216,7 +217,7 @@ void LinuxVolumeCatcherImpl::update_index_volume(U32 index, F32 volume) void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *sii, int eol, void *userdata) { - LinuxVolumeCatcherImpl *impl = dynamic_cast(userdata); + LinuxVolumeCatcherImpl *impl = dynamic_cast((LinuxVolumeCatcherImpl*)userdata); llassert(impl); if (0 == eol) @@ -249,7 +250,7 @@ void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata) { - LinuxVolumeCatcherImpl *impl = dynamic_cast(userdata); + LinuxVolumeCatcherImpl *impl = dynamic_cast((LinuxVolumeCatcherImpl*)userdata); llassert(impl); switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { @@ -267,7 +268,7 @@ void callback_subscription_alert(pa_context *context, pa_subscription_event_type pa_operation *op; if ((op = pa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl))) { - pa_operation_unref(o); + pa_operation_unref(op); } } break; @@ -278,14 +279,14 @@ void callback_subscription_alert(pa_context *context, pa_subscription_event_type void callback_context_state(pa_context *context, void *userdata) { - LinuxVolumeCatcherImpl *impl = dynamic_cast(userdata); + LinuxVolumeCatcherImpl *impl = dynamic_cast((LinuxVolumeCatcherImpl*)userdata); llassert(impl); - switch (pa_context_get_state(c)) + switch (pa_context_get_state(context)) { case PA_CONTEXT_READY: impl->mConnected = true; - impl->connected_okay(c); + impl->connected_okay(); break; case PA_CONTEXT_TERMINATED: impl->mConnected = false; @@ -304,7 +305,7 @@ LinuxVolumeCatcher::LinuxVolumeCatcher() pimpl = new LinuxVolumeCatcherImpl(); } -LinuxVolumeCatcher::LinuxVolumeCatcher~() +LinuxVolumeCatcher::~LinuxVolumeCatcher() { delete pimpl; pimpl = NULL; -- cgit v1.2.3 From df43c0e18b852fb1490cf9199b7766239cd2801c Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 14:08:15 +0000 Subject: Wire the linux volume catcher into the webkit plugin. --- .../media_plugins/webkit/linux_volume_catcher.cpp | 8 ++--- indra/media_plugins/webkit/media_plugin_webkit.cpp | 34 ++++++++++++++++++++-- 2 files changed, 35 insertions(+), 7 deletions(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 1439f1c5a5..89cababdd8 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -58,7 +58,7 @@ public: LinuxVolumeCatcherImpl(); ~LinuxVolumeCatcherImpl(); - void setVol(F32 volume); + void setVolume(F32 volume); void pump(void); // for internal use - can't be private because used from our C callbacks @@ -144,7 +144,7 @@ void LinuxVolumeCatcherImpl::cleanup() mConnected = false; } -void LinuxVolumeCatcherImpl::setVol(F32 volume) +void LinuxVolumeCatcherImpl::setVolume(F32 volume) { mDesiredVolume = volume; @@ -311,10 +311,10 @@ LinuxVolumeCatcher::~LinuxVolumeCatcher() pimpl = NULL; } -void LinuxVolumeCatcher::setVol(F32 volume) +void LinuxVolumeCatcher::setVolume(F32 volume) { llassert(pimpl); - pimpl->setVol(volume); + pimpl->setVolume(volume); } void LinuxVolumeCatcher::pump() diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index 688d3bcd3d..292585caa6 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -43,11 +43,15 @@ #include "llpluginmessageclasses.h" #include "media_plugin_base.h" +#if LL_LINUX +# include "linux_volume_catcher.h" +#endif + #if LL_WINDOWS -#include +# include #else -#include -#include +# include +# include #endif #if LL_WINDOWS @@ -102,6 +106,10 @@ private: F32 mBackgroundG; F32 mBackgroundB; +#if LL_LINUX + LinuxVolumeCatcher mLinuxVolumeCatcher; +#endif + void setInitState(int state) { // std::cerr << "changing init state to " << state << std::endl; @@ -114,6 +122,10 @@ private: { LLQtWebKit::getInstance()->pump( milliseconds ); +#if LL_LINUX + mLinuxVolumeCatcher.pump(); +#endif + checkEditState(); if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) @@ -281,6 +293,7 @@ private: return false; }; + void setVolume(F32 vol); //////////////////////////////////////////////////////////////////////////////// // virtual @@ -732,6 +745,14 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) // std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl; } } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + if(message_name == "set_volume") + { + F32 volume = message_in.getValueReal("volume"); + setVolume(volume); + } + } else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) { if(message_name == "size_change") @@ -998,6 +1019,13 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) } } +void MediaPluginWebKit::setVolume(F32 volume) +{ +#if LL_LINUX + mLinuxVolumeCatcher.setVolume(volume); +#endif +} + int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) { MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data); -- cgit v1.2.3 From 235023d71122bce1fc3eadd90d8dc75cc5612f78 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 14:15:15 +0000 Subject: document the linux_volume_catcher high-level design --- indra/media_plugins/webkit/linux_volume_catcher.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 89cababdd8..024235717b 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -31,6 +31,15 @@ * @endcond */ +/* + The high-level design is as follows: + 1) Connect to the PulseAudio daemon + 2) Watch for the creation of new audio players connecting to the daemon (this includes ALSA clients running on the PulseAudio emulation layer, such as Flash plugins) + 3) Examine the audio player's PID to see if it belongs to our own process + 4) If so, tell PA to adjust the volume of that audio player ('sink input' in PA parlance) + 5) Keep a list of all living audio players that we care about, adjust the volumes of all of them when we get a new setVolume() call + */ + #include "linden_common.h" #include -- cgit v1.2.3 From 66162bfca3413cbee319e40ac577bb1f750624a9 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 14:15:57 +0000 Subject: comment tweak. --- indra/media_plugins/webkit/linux_volume_catcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 024235717b..03feaa23ff 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -35,7 +35,7 @@ The high-level design is as follows: 1) Connect to the PulseAudio daemon 2) Watch for the creation of new audio players connecting to the daemon (this includes ALSA clients running on the PulseAudio emulation layer, such as Flash plugins) - 3) Examine the audio player's PID to see if it belongs to our own process + 3) Examine any new audio player's PID to see if it belongs to our own process 4) If so, tell PA to adjust the volume of that audio player ('sink input' in PA parlance) 5) Keep a list of all living audio players that we care about, adjust the volumes of all of them when we get a new setVolume() call */ -- cgit v1.2.3 From b2fbb28dc99b19ea302a4c18656b0544572a5ebe Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 14:19:10 +0000 Subject: Well, whaddyaknow.. it works. More cleanup needed: need to dlopen()-ize the pulseaudio stuff --- indra/media_plugins/webkit/linux_volume_catcher.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 03feaa23ff..cfb78d2036 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -233,7 +233,6 @@ void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info { pa_proplist *proplist = sii->proplist; pid_t sinkpid = atoll(pa_proplist_gets(proplist, PA_PROP_APPLICATION_PROCESS_ID)); - fprintf(stderr, "Found sinkinput #%d, name=%s, pid=%d\t", sii->index, sii->name, int(sinkpid)); if (sinkpid == getpid()) // does the discovered sinkinput belong to this process? { -- cgit v1.2.3 From 95ccfd806cd5f5859d09503f60a85987eb8bb1af Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 14:29:37 +0000 Subject: Do some decent cleanup in LinuxVolumeCatcherImpl's destructor. Though I don't think media plugins are really 'destroyed' as we know it, their process just ends. --- indra/media_plugins/webkit/linux_volume_catcher.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index cfb78d2036..cc5a456c96 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -148,9 +148,20 @@ void LinuxVolumeCatcherImpl::init() void LinuxVolumeCatcherImpl::cleanup() { - // there's some cleanup we could do, but do nothing... for now. - mConnected = false; + + if (mPAContext) + { + pa_context_disconnect(mPAContext); + pa_context_unref(mPAContext); + mPAContext = NULL; + } + + if (mMainloop) + { + pa_glib_mainloop_free(mMainloop); + mMainloop = NULL; + } } void LinuxVolumeCatcherImpl::setVolume(F32 volume) -- cgit v1.2.3 From fa1bae00935b9fc64698b79ce0a6bf19cca2be25 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 14:33:26 +0000 Subject: minor comment tweak. --- indra/media_plugins/webkit/linux_volume_catcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index cc5a456c96..6068c7610b 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -103,7 +103,7 @@ LinuxVolumeCatcherImpl::~LinuxVolumeCatcherImpl() void LinuxVolumeCatcherImpl::init() { - // try to be as robust as possible because PA's interface is a + // try to be as defensive as possible because PA's interface is a // bit fragile and (for our purposes) we'd rather simply not function // than crash mMainloop = pa_glib_mainloop_new(g_main_context_default()); -- cgit v1.2.3 From 315c0021f02f8c037aeef08b3862390ff857e2da Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 15:06:06 +0000 Subject: remove dos line endings... --- indra/llui/llaccordionctrl.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'indra') diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index ae218c28c4..aa69dfe0cc 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -103,13 +103,13 @@ void LLAccordionCtrl::draw() LLLocalClipRect clip(local_rect); LLPanel::draw(); - /* - S32 width = getRect().getWidth(); - S32 height = getRect().getHeight(); - - gl_rect_2d(0, 0 , width - 1 ,height - 1,LLColor4::green,true); - gl_line_2d(0, 0 , width - 1 ,height - 1,LLColor4::black); - */ + /* + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); + + gl_rect_2d(0, 0 , width - 1 ,height - 1,LLColor4::green,true); + gl_line_2d(0, 0 , width - 1 ,height - 1,LLColor4::black); + */ } -- cgit v1.2.3 From 71efe007b233cf276d2c5a8b4fb1749f6187dd71 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 15:29:57 +0000 Subject: start dynamic sym loading work. --- indra/media_plugins/webkit/CMakeLists.txt | 2 - .../media_plugins/webkit/linux_volume_catcher.cpp | 72 +++++++++++----------- 2 files changed, 37 insertions(+), 37 deletions(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt index a43680bb16..3ab5522386 100644 --- a/indra/media_plugins/webkit/CMakeLists.txt +++ b/indra/media_plugins/webkit/CMakeLists.txt @@ -46,8 +46,6 @@ if (LINUX) list(APPEND media_plugin_webkit_SOURCE_FILES linux_volume_catcher.cpp) list(APPEND media_plugin_webkit_LINK_LIBRARIES ${UI_LIBRARIES} # for glib/GTK - pulse - pulse-mainloop-glib ) endif (LINUX) diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 6068c7610b..d61b00cf67 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -72,6 +72,7 @@ public: // for internal use - can't be private because used from our C callbacks + bool loadsyms(); void init(); void cleanup(); @@ -85,13 +86,15 @@ public: pa_glib_mainloop *mMainloop; pa_context *mPAContext; bool mConnected; + bool mGotSyms; }; LinuxVolumeCatcherImpl::LinuxVolumeCatcherImpl() : mDesiredVolume(0.0f), mMainloop(NULL), mPAContext(NULL), - mConnected(false) + mConnected(false), + mGotSyms(false) { init(); } @@ -106,23 +109,23 @@ void LinuxVolumeCatcherImpl::init() // try to be as defensive as possible because PA's interface is a // bit fragile and (for our purposes) we'd rather simply not function // than crash - mMainloop = pa_glib_mainloop_new(g_main_context_default()); + mMainloop = llpa_glib_mainloop_new(g_main_context_default()); if (mMainloop) { - pa_mainloop_api *api = pa_glib_mainloop_get_api(mMainloop); + pa_mainloop_api *api = llpa_glib_mainloop_get_api(mMainloop); if (api) { - pa_proplist *proplist = pa_proplist_new(); + pa_proplist *proplist = llpa_proplist_new(); if (proplist) { - pa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "multimedia-player"); - pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.secondlife.viewer.mediaplugvoladjust"); - pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "SL Plugin Volume Adjuster"); - pa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, "1"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "multimedia-player"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.secondlife.viewer.mediaplugvoladjust"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "SL Plugin Volume Adjuster"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, "1"); // plain old pa_context_new() is broken! - mPAContext = pa_context_new_with_proplist(api, NULL, proplist); - pa_proplist_free(proplist); + mPAContext = llpa_context_new_with_proplist(api, NULL, proplist); + llpa_proplist_free(proplist); } } } @@ -131,9 +134,9 @@ void LinuxVolumeCatcherImpl::init() // PA context to a PA daemon. if (mPAContext) { - pa_context_set_state_callback(mPAContext, callback_context_state, this); + llpa_context_set_state_callback(mPAContext, callback_context_state, this); pa_context_flags_t cflags = (pa_context_flags)0; // maybe add PA_CONTEXT_NOAUTOSPAWN? - if (pa_context_connect(mPAContext, NULL, cflags, NULL) >= 0) + if (llpa_context_connect(mPAContext, NULL, cflags, NULL) >= 0) { // Okay! We haven't definitely connected, but we // haven't definitely failed yet. @@ -152,14 +155,14 @@ void LinuxVolumeCatcherImpl::cleanup() if (mPAContext) { - pa_context_disconnect(mPAContext); - pa_context_unref(mPAContext); + llpa_context_disconnect(mPAContext); + llpa_context_unref(mPAContext); mPAContext = NULL; } if (mMainloop) { - pa_glib_mainloop_free(mMainloop); + llpa_glib_mainloop_free(mMainloop); mMainloop = NULL; } } @@ -187,22 +190,22 @@ void LinuxVolumeCatcherImpl::connected_okay() pa_operation *op; // fetch global list of existing sinkinputs - if ((op = pa_context_get_sink_input_info_list(mPAContext, - callback_discovered_sinkinput, - this))) + if ((op = llpa_context_get_sink_input_info_list(mPAContext, + callback_discovered_sinkinput, + this))) { - pa_operation_unref(op); + llpa_operation_unref(op); } // subscribe to future global sinkinput changes - pa_context_set_subscribe_callback(mPAContext, - callback_subscription_alert, - this); - if ((op = pa_context_subscribe(mPAContext, (pa_subscription_mask_t) - (PA_SUBSCRIPTION_MASK_SINK_INPUT), - NULL, NULL))) + llpa_context_set_subscribe_callback(mPAContext, + callback_subscription_alert, + this); + if ((op = llpa_context_subscribe(mPAContext, (pa_subscription_mask_t) + (PA_SUBSCRIPTION_MASK_SINK_INPUT), + NULL, NULL))) { - pa_operation_unref(op); + llpa_operation_unref(op); } } @@ -218,8 +221,8 @@ void LinuxVolumeCatcherImpl::update_all_volumes(F32 volume) void LinuxVolumeCatcherImpl::update_index_volume(U32 index, F32 volume) { static pa_cvolume cvol; - pa_cvolume_set(&cvol, mSinkInputNumChannels[index], - pa_sw_volume_from_linear(volume)); + llpa_cvolume_set(&cvol, mSinkInputNumChannels[index], + llpa_sw_volume_from_linear(volume)); pa_context *c = mPAContext; uint32_t idx = index; @@ -228,9 +231,9 @@ void LinuxVolumeCatcherImpl::update_index_volume(U32 index, F32 volume) void *userdata = NULL; // okay as null pa_operation *op; - if ((op = pa_context_set_sink_input_volume(c, idx, cvolumep, cb, userdata))) + if ((op = llpa_context_set_sink_input_volume(c, idx, cvolumep, cb, userdata))) { - pa_operation_unref(op); + llpa_operation_unref(op); } } @@ -243,7 +246,7 @@ void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info if (0 == eol) { pa_proplist *proplist = sii->proplist; - pid_t sinkpid = atoll(pa_proplist_gets(proplist, PA_PROP_APPLICATION_PROCESS_ID)); + pid_t sinkpid = atoll(llpa_proplist_gets(proplist, PA_PROP_APPLICATION_PROCESS_ID)); if (sinkpid == getpid()) // does the discovered sinkinput belong to this process? { @@ -256,7 +259,6 @@ void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info if (is_new) { // new! - fprintf(stderr, "\nJACKPOT!\n"); impl->update_index_volume(sii->index, impl->mDesiredVolume); } else @@ -285,9 +287,9 @@ void callback_subscription_alert(pa_context *context, pa_subscription_event_type { // ask for more info about this new sinkinput pa_operation *op; - if ((op = pa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl))) + if ((op = llpa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl))) { - pa_operation_unref(op); + llpa_operation_unref(op); } } break; @@ -301,7 +303,7 @@ void callback_context_state(pa_context *context, void *userdata) LinuxVolumeCatcherImpl *impl = dynamic_cast((LinuxVolumeCatcherImpl*)userdata); llassert(impl); - switch (pa_context_get_state(context)) + switch (llpa_context_get_state(context)) { case PA_CONTEXT_READY: impl->mConnected = true; -- cgit v1.2.3 From 03d3e64157e7f402fef2116c56aabfcd1eeb2a22 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 15:50:49 +0000 Subject: more work on dynamic grabbing of PA syms. --- .../media_plugins/webkit/linux_volume_catcher.cpp | 100 ++++++++++++++++++++- .../webkit/linux_volume_catcher_pa_syms.inc | 21 +++++ .../webkit/linux_volume_catcher_paglib_syms.inc | 6 ++ 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc create mode 100644 indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index d61b00cf67..4f4f3c1740 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -53,6 +53,95 @@ //////////////////////////////////////////////////// +#define DEBUGMSG(...) do {} while(0) +#define INFOMSG(...) do {} while(0) +#define WARNMSG(...) do {} while(0) + +#define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) RTN (*ll##PASYM)(__VA_ARGS__) = NULL +#include "linux_volume_catcher_pa_syms.inc" +#undef LL_PA_SYM + +static bool sSymsGrabbed = false; +static apr_pool_t *sSymPADSOMemoryPool = NULL; +static apr_dso_handle_t *sSymPADSOHandleG = NULL; + +bool grab_pa_syms(std::string pa_dso_name) +{ + if (sSymsGrabbed) + { + // already have grabbed good syms + return true; + } + + bool sym_error = false; + bool rtn = false; + apr_status_t rv; + apr_dso_handle_t *sSymPADSOHandle = NULL; + +#define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##PASYM, sSymPADSOHandle, #PASYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #PASYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #PASYM, (void*)ll##PASYM);}while(0) + + //attempt to load the shared library + apr_pool_create(&sSymPADSOMemoryPool, NULL); + + if ( APR_SUCCESS == (rv = apr_dso_load(&sSymPADSOHandle, + pa_dso_name.c_str(), + sSymPADSOMemoryPool) )) + { + INFOMSG("Found DSO: %s", pa_dso_name.c_str()); + +#include "linux_volume_catcher_pa_syms.inc" + + if ( sSymPADSOHandle ) + { + sSymPADSOHandleG = sSymPADSOHandle; + sSymPADSOHandle = NULL; + } + + rtn = !sym_error; + } + else + { + INFOMSG("Couldn't load DSO: %s", pa_dso_name.c_str()); + rtn = false; // failure + } + + if (sym_error) + { + WARNMSG("Failed to find necessary symbols in PulseAudio libraries."); + } +#undef LL_PA_SYM + + sSymsGrabbed = rtn; + return rtn; +} + + +void ungrab_pa_syms() +{ + // should be safe to call regardless of whether we've + // actually grabbed syms. + + if ( sSymPADSOHandleG ) + { + apr_dso_unload(sSymPADSOHandleG); + sSymPADSOHandleG = NULL; + } + + if ( sSymPADSOMemoryPool ) + { + apr_pool_destroy(sSymPADSOMemoryPool); + sSymPADSOMemoryPool = NULL; + } + + // NULL-out all of the symbols we'd grabbed +#define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{ll##PASYM = NULL;}while(0) +#include "linux_volume_catcher_pa_syms.inc" +#undef LL_PA_SYM + + sSymsGrabbed = false; +} +//////////////////////////////////////////////////// + // PulseAudio requires a chain of callbacks with C linkage extern "C" { void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *i, int eol, void *userdata); @@ -72,7 +161,7 @@ public: // for internal use - can't be private because used from our C callbacks - bool loadsyms(); + bool loadsyms(std::string pulse_dso_name, std::string pulse_glib_dso_name); void init(); void cleanup(); @@ -104,11 +193,20 @@ LinuxVolumeCatcherImpl::~LinuxVolumeCatcherImpl() cleanup(); } +bool LinuxVolumeCatcherImpl::loadsyms(std::string pulse_dso_name, + std::string pulse_glib_dso_name) +{ + return grab_pa_syms(pulse_dso_name, pulse_glib_dso_name); +} + void LinuxVolumeCatcherImpl::init() { // try to be as defensive as possible because PA's interface is a // bit fragile and (for our purposes) we'd rather simply not function // than crash + + mGotSyms = loadsyms("libpulse.so.0", "libpulse-mainloop-glib.so.0"); + mMainloop = llpa_glib_mainloop_new(g_main_context_default()); if (mMainloop) { diff --git a/indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc b/indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc new file mode 100644 index 0000000000..d806b48428 --- /dev/null +++ b/indra/media_plugins/webkit/linux_volume_catcher_pa_syms.inc @@ -0,0 +1,21 @@ +// required symbols to grab +LL_PA_SYM(true, pa_context_connect, int, pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api); +LL_PA_SYM(true, pa_context_disconnect, void, pa_context *c); +LL_PA_SYM(true, pa_context_get_sink_input_info, pa_operation*, pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata); +LL_PA_SYM(true, pa_context_get_sink_input_info_list, pa_operation*, pa_context *c, pa_sink_input_info_cb_t cb, void *userdata); +LL_PA_SYM(true, pa_context_get_state, pa_context_state_t, pa_context *c); +LL_PA_SYM(true, pa_context_new_with_proplist, pa_context*, pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist); +LL_PA_SYM(true, pa_context_set_sink_input_volume, pa_operation*, pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); +LL_PA_SYM(true, pa_context_set_state_callback, void, pa_context *c, pa_context_notify_cb_t cb, void *userdata); +LL_PA_SYM(true, pa_context_set_subscribe_callback, void, pa_context *c, pa_context_subscribe_cb_t cb, void *userdata); +LL_PA_SYM(true, pa_context_subscribe, pa_operation*, pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata); +LL_PA_SYM(true, pa_context_unref, void, pa_context *c); +LL_PA_SYM(true, pa_cvolume_set, pa_cvolume*, pa_cvolume *a, unsigned channels, pa_volume_t v); +LL_PA_SYM(true, pa_operation_unref, void, pa_operation *o); +LL_PA_SYM(true, pa_proplist_free, void, pa_proplist* p); +LL_PA_SYM(true, pa_proplist_gets, const char*, pa_proplist *p, const char *key); +LL_PA_SYM(true, pa_proplist_new, pa_proplist*, void); +LL_PA_SYM(true, pa_proplist_sets, int, pa_proplist *p, const char *key, const char *value); +LL_PA_SYM(true, pa_sw_volume_from_linear, pa_volume_t, double v); + +// optional symbols to grab diff --git a/indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc b/indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc new file mode 100644 index 0000000000..abf628c96c --- /dev/null +++ b/indra/media_plugins/webkit/linux_volume_catcher_paglib_syms.inc @@ -0,0 +1,6 @@ +// required symbols to grab +LL_PA_SYM(true, pa_glib_mainloop_free, void, pa_glib_mainloop* g); +LL_PA_SYM(true, pa_glib_mainloop_get_api, pa_mainloop_api*, pa_glib_mainloop* g); +LL_PA_SYM(true, pa_glib_mainloop_new, pa_glib_mainloop *, GMainContext *c); + +// optional symbols to grab -- cgit v1.2.3 From fa9811e0c5dbd249a9c6e37d95d2d842d43658a2 Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Mon, 22 Feb 2010 16:09:25 +0000 Subject: Fix Mac build with the renamed boost libs --- indra/cmake/Boost.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index 3652508b6a..7ce57a5572 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -38,9 +38,9 @@ else (STANDALONE) debug libboost_signals-vc80-mt-gd-${BOOST_VERSION}) endif (MSVC71) elseif (DARWIN) - set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt) - set(BOOST_REGEX_LIBRARY boost_regex-mt) - set(BOOST_SIGNALS_LIBRARY boost_signals-mt) + set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-xgcc40-mt) + set(BOOST_REGEX_LIBRARY boost_regex-xgcc40-mt) + set(BOOST_SIGNALS_LIBRARY boost_signals-xgcc40-mt) elseif (LINUX) set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-gcc41-mt) set(BOOST_REGEX_LIBRARY boost_regex-gcc41-mt) -- cgit v1.2.3 From dfe3b9ff1c9854919f326bb7ace14ee680367802 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 16:16:26 +0000 Subject: EXT-5601 Linux: volume adjustment of web-based media / Flash Dynamic loading of pulseaudio works now. All that's left is to package-up the pulseaudio headers... --- .../media_plugins/webkit/linux_volume_catcher.cpp | 40 +++++++++++++++------- 1 file changed, 27 insertions(+), 13 deletions(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 4f4f3c1740..7a20ab6231 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -42,6 +42,7 @@ #include "linden_common.h" +extern "C" { #include #include @@ -49,6 +50,10 @@ #include #include // There's no special reason why we want the *glib* PA mainloop, but the generic polling implementation seems broken. +#include "apr_pools.h" +#include "apr_dso.h" +} + #include "linux_volume_catcher.h" //////////////////////////////////////////////////// @@ -59,13 +64,14 @@ #define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) RTN (*ll##PASYM)(__VA_ARGS__) = NULL #include "linux_volume_catcher_pa_syms.inc" +#include "linux_volume_catcher_paglib_syms.inc" #undef LL_PA_SYM static bool sSymsGrabbed = false; static apr_pool_t *sSymPADSOMemoryPool = NULL; static apr_dso_handle_t *sSymPADSOHandleG = NULL; -bool grab_pa_syms(std::string pa_dso_name) +bool grab_pa_syms(std::string pulse_dso_name) { if (sSymsGrabbed) { @@ -84,12 +90,13 @@ bool grab_pa_syms(std::string pa_dso_name) apr_pool_create(&sSymPADSOMemoryPool, NULL); if ( APR_SUCCESS == (rv = apr_dso_load(&sSymPADSOHandle, - pa_dso_name.c_str(), + pulse_dso_name.c_str(), sSymPADSOMemoryPool) )) { - INFOMSG("Found DSO: %s", pa_dso_name.c_str()); + INFOMSG("Found DSO: %s", pulse_dso_name.c_str()); #include "linux_volume_catcher_pa_syms.inc" +#include "linux_volume_catcher_paglib_syms.inc" if ( sSymPADSOHandle ) { @@ -101,7 +108,7 @@ bool grab_pa_syms(std::string pa_dso_name) } else { - INFOMSG("Couldn't load DSO: %s", pa_dso_name.c_str()); + INFOMSG("Couldn't load DSO: %s", pulse_dso_name.c_str()); rtn = false; // failure } @@ -136,6 +143,7 @@ void ungrab_pa_syms() // NULL-out all of the symbols we'd grabbed #define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{ll##PASYM = NULL;}while(0) #include "linux_volume_catcher_pa_syms.inc" +#include "linux_volume_catcher_paglib_syms.inc" #undef LL_PA_SYM sSymsGrabbed = false; @@ -161,7 +169,7 @@ public: // for internal use - can't be private because used from our C callbacks - bool loadsyms(std::string pulse_dso_name, std::string pulse_glib_dso_name); + bool loadsyms(std::string pulse_dso_name); void init(); void cleanup(); @@ -193,10 +201,9 @@ LinuxVolumeCatcherImpl::~LinuxVolumeCatcherImpl() cleanup(); } -bool LinuxVolumeCatcherImpl::loadsyms(std::string pulse_dso_name, - std::string pulse_glib_dso_name) +bool LinuxVolumeCatcherImpl::loadsyms(std::string pulse_dso_name) { - return grab_pa_syms(pulse_dso_name, pulse_glib_dso_name); + return grab_pa_syms(pulse_dso_name); } void LinuxVolumeCatcherImpl::init() @@ -205,7 +212,12 @@ void LinuxVolumeCatcherImpl::init() // bit fragile and (for our purposes) we'd rather simply not function // than crash - mGotSyms = loadsyms("libpulse.so.0", "libpulse-mainloop-glib.so.0"); + // we cheat and rely upon libpulse-mainloop-glib.so.0 to pull-in + // libpulse.so.0 - this isn't a great assumption, and the two DSOs should + // probably be loaded separately. Our Linux DSO framework needs refactoring, + // we do this sort of thing a lot... + mGotSyms = loadsyms("libpulse-mainloop-glib.so.0"); + if (!mGotSyms) return; mMainloop = llpa_glib_mainloop_new(g_main_context_default()); if (mMainloop) @@ -251,24 +263,26 @@ void LinuxVolumeCatcherImpl::cleanup() { mConnected = false; - if (mPAContext) + if (mGotSyms && mPAContext) { llpa_context_disconnect(mPAContext); llpa_context_unref(mPAContext); - mPAContext = NULL; } + mPAContext = NULL; - if (mMainloop) + if (mGotSyms && mMainloop) { llpa_glib_mainloop_free(mMainloop); - mMainloop = NULL; } + mMainloop = NULL; } void LinuxVolumeCatcherImpl::setVolume(F32 volume) { mDesiredVolume = volume; + if (!mGotSyms) return; + if (mConnected && mPAContext) { update_all_volumes(mDesiredVolume); -- cgit v1.2.3 From 4cfbfedec5b93da83d162149ec2e568210ae0888 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 16:19:46 +0000 Subject: comment improvement. --- indra/media_plugins/webkit/linux_volume_catcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 7a20ab6231..a2a99d5728 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -215,7 +215,7 @@ void LinuxVolumeCatcherImpl::init() // we cheat and rely upon libpulse-mainloop-glib.so.0 to pull-in // libpulse.so.0 - this isn't a great assumption, and the two DSOs should // probably be loaded separately. Our Linux DSO framework needs refactoring, - // we do this sort of thing a lot... + // we do this sort of thing a lot with practically identical logic... mGotSyms = loadsyms("libpulse-mainloop-glib.so.0"); if (!mGotSyms) return; -- cgit v1.2.3 From 15513ff6d7e9958c16288bba7e94d2c44b3534d4 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 16:20:57 +0000 Subject: trivial cleanup. --- indra/media_plugins/webkit/media_plugin_webkit.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index 292585caa6..c7aba04492 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -45,7 +45,7 @@ #if LL_LINUX # include "linux_volume_catcher.h" -#endif +#endif // LL_LINUX #if LL_WINDOWS # include @@ -108,7 +108,7 @@ private: #if LL_LINUX LinuxVolumeCatcher mLinuxVolumeCatcher; -#endif +#endif // LL_LINUX void setInitState(int state) { @@ -124,7 +124,7 @@ private: #if LL_LINUX mLinuxVolumeCatcher.pump(); -#endif +#endif // LL_LINUX checkEditState(); @@ -1023,7 +1023,7 @@ void MediaPluginWebKit::setVolume(F32 volume) { #if LL_LINUX mLinuxVolumeCatcher.setVolume(volume); -#endif +#endif // LL_LINUX } int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) -- cgit v1.2.3 From 4ad449d74d44c73f326066e3327037f86b463aa4 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 16:25:30 +0000 Subject: Update Linux viewer README to cover basic Flash requirements. --- indra/newview/linux_tools/client-readme.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/linux_tools/client-readme.txt b/indra/newview/linux_tools/client-readme.txt index 92d321d8c0..287bdf1034 100644 --- a/indra/newview/linux_tools/client-readme.txt +++ b/indra/newview/linux_tools/client-readme.txt @@ -15,7 +15,7 @@ Life itself - please see . 5.3. Blank window after minimizing it 5.4. Audio 5.5. 'Alt' key for camera controls doesn't work - 5.6. In-world streaming movie/music playback + 5.6. In-world streaming movie, music and Flash playback 6. Advanced Troubleshooting 6.1. Audio 6.2. OpenGL @@ -169,12 +169,15 @@ SOLUTION:- Some window managers eat the Alt key for their own purposes; you example, the 'Windows' key!) which will allow the Alt key to function properly with mouse actions in Second Life and other applications. -PROBLEM 6:- In-world movie and/or music playback doesn't work for me. +PROBLEM 6:- In-world movie, music, or Flash playback doesn't work for me. SOLUTION:- You need to have a working installation of GStreamer 0.10; this is usually an optional package for most versions of Linux. If you have installed GStreamer 0.10 and you can play some music/movies but not others then you need to install a wider selection of GStreamer plugins, either from your vendor or an appropriate third party. + For Flash playback, you need to have Flash 10 installed for your normal + web browser (for example, Firefox). PulseAudio is required for Flash + volume control / muting to fully function inside Second Life. 6. ADVANCED TROUBLESHOOTING -- cgit v1.2.3 From 2a9232d307987b045dbeca898108aafc836ae0d6 Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 16:27:05 +0000 Subject: another minor readme tweak. --- indra/newview/linux_tools/client-readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/linux_tools/client-readme.txt b/indra/newview/linux_tools/client-readme.txt index 287bdf1034..e01b9e4bc6 100644 --- a/indra/newview/linux_tools/client-readme.txt +++ b/indra/newview/linux_tools/client-readme.txt @@ -174,7 +174,7 @@ SOLUTION:- You need to have a working installation of GStreamer 0.10; this is usually an optional package for most versions of Linux. If you have installed GStreamer 0.10 and you can play some music/movies but not others then you need to install a wider selection of GStreamer plugins, either - from your vendor or an appropriate third party. + from your vendor (i.e. the 'Ugly' plugins) or an appropriate third party. For Flash playback, you need to have Flash 10 installed for your normal web browser (for example, Firefox). PulseAudio is required for Flash volume control / muting to fully function inside Second Life. -- cgit v1.2.3 From f43a9a181ee0233adaed03a93190dc518ff0047f Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 16:50:26 +0000 Subject: Do the necessary stuff to package pulseaudio's headers and make it (in theory, not yet in practice) optional. --- indra/cmake/PulseAudio.cmake | 28 ++++++++++++++++++++++++++++ indra/media_plugins/webkit/CMakeLists.txt | 3 +++ 2 files changed, 31 insertions(+) create mode 100644 indra/cmake/PulseAudio.cmake (limited to 'indra') diff --git a/indra/cmake/PulseAudio.cmake b/indra/cmake/PulseAudio.cmake new file mode 100644 index 0000000000..f8087a8083 --- /dev/null +++ b/indra/cmake/PulseAudio.cmake @@ -0,0 +1,28 @@ +# -*- cmake -*- +include(Prebuilt) + +if (STANDALONE) + include(FindPkgConfig) + + pkg_check_modules(PULSEAUDIO REQUIRED libpulse-mainloop-glib) + +elseif (LINUX) + use_prebuilt_binary(pulseaudio) + set(PULSEAUDIO_FOUND ON FORCE BOOL) + set(PULSEAUDIO_INCLUDE_DIRS + ${LIBS_PREBUILT_DIR}/include + ) + # We don't need to explicitly link against pulseaudio itself, because + # the viewer probes for the system's copy at runtime. + set(PULSEAUDIO_LIBRARIES + # none needed! + ) +endif (STANDALONE) + +if (PULSEAUDIO_FOUND) + set(PULSEAUDIO ON CACHE BOOL "Build with PulseAudio support, if available.") +endif (PULSEAUDIO_FOUND) + +if (PULSEAUDIO) + add_definitions(-DLL_PULSEAUDIO_ENABLED=1) +endif (PULSEAUDIO) diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt index 3ab5522386..9f66a77c64 100644 --- a/indra/media_plugins/webkit/CMakeLists.txt +++ b/indra/media_plugins/webkit/CMakeLists.txt @@ -14,10 +14,12 @@ include(Linking) include(PluginAPI) include(MediaPluginBase) include(FindOpenGL) +include(PulseAudio) include(WebKitLibPlugin) include_directories( + ${PULSEAUDIO_INCLUDE_DIRS} ${LLPLUGIN_INCLUDE_DIRS} ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} @@ -40,6 +42,7 @@ set(media_plugin_webkit_LINK_LIBRARIES ${LLCOMMON_LIBRARIES} ${WEBKIT_PLUGIN_LIBRARIES} ${PLUGIN_API_WINDOWS_LIBRARIES} + ${PULSEAUDIO_LIBRARIES} ) if (LINUX) -- cgit v1.2.3 From 96ddf30a49a4ebca25816701373c34674088b2ce Mon Sep 17 00:00:00 2001 From: Tofu Linden Date: Mon, 22 Feb 2010 16:55:14 +0000 Subject: support LL_PULSEAUDIO_ENABLED=0 - probably. --- .../media_plugins/webkit/linux_volume_catcher.cpp | 29 ++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index a2a99d5728..2ba28bd4bf 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -42,6 +42,11 @@ #include "linden_common.h" +#include "linux_volume_catcher.h" + + +#if LL_PULSEAUDIO_ENABLED + extern "C" { #include @@ -54,8 +59,6 @@ extern "C" { #include "apr_dso.h" } -#include "linux_volume_catcher.h" - //////////////////////////////////////////////////// #define DEBUGMSG(...) do {} while(0) @@ -456,3 +459,25 @@ void LinuxVolumeCatcher::pump() pimpl->pump(); } +#else // !LL_PULSEAUDIO_ENABLED + +// stub. + +LinuxVolumeCatcher::LinuxVolumeCatcher() +{ + pimpl = NULL; +} + +LinuxVolumeCatcher::~LinuxVolumeCatcher() +{ +} + +void LinuxVolumeCatcher::setVolume(F32 volume) +{ +} + +void LinuxVolumeCatcher::pump() +{ +} + +#endif // LL_PULSEAUDIO_ENABLED -- cgit v1.2.3 From 00fdc0acd5e27d353c070706e838a35bf889a536 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 22 Feb 2010 14:03:29 -0500 Subject: Work in progress on EXT-5333: Cleanup. --- indra/newview/llagentwearables.cpp | 2 -- indra/newview/llappearancemgr.cpp | 24 +++++++++--------------- indra/newview/llinventorybridge.cpp | 6 ++---- 3 files changed, 11 insertions(+), 21 deletions(-) (limited to 'indra') diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 94fd5132ca..08cd101b01 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -1039,8 +1039,6 @@ void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void* { return; } -// BAP RESTORE TMP -// if (wearable && type != WT_SHAPE) // force failure for shape to test recovery path. if (wearable) { diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index ae1a7a0cbe..c9da08701d 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -648,14 +648,14 @@ static void onWearableAssetFetch(LLWearable* wearable, void* data) { LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data; holder->mResolved += 1; // just counting callbacks, not successes. - llinfos << "onWearableAssetFetch, resolved " << holder->mResolved << " requested " << holder->mFoundList.size() << llendl; + llinfos << "onWearableAssetFetch, resolved count " << holder->mResolved << " of requested " << holder->mFoundList.size() << llendl; if (wearable) { - llinfos << "wearable type " << wearable->getType() << llendl; + llinfos << "wearable found, type " << wearable->getType() << " asset " << wearable->getAssetID() << llendl; } else { - llinfos << "wearable: NONE" << llendl; + llwarns << "no wearable found" << llendl; } if (holder->mFired) @@ -666,18 +666,9 @@ static void onWearableAssetFetch(LLWearable* wearable, void* data) if (!wearable) { - llwarns << "no wearable found" << llendl; return; } -#if 0 - if ((wearable->getType() == WT_SHAPE) || (wearable->getType() == WT_JACKET)) - { - llwarns << "Forcing failure for type " << wearable->getType() << llendl; - return; - } -#endif - for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin(); iter != holder->mFoundList.end(); ++iter) { @@ -1118,7 +1109,8 @@ void LLAppearanceManager::updateAppearanceFromCOF() // callback will be called (and this object deleted) // before the final getNextData(). - // BAP cleanup - no point having found_container when mFoundList already has all the info. + // BAP future cleanup - no point having found_container when + // mFoundList already has all the info. LLDynamicArray found_container; for(S32 i = 0; i < wear_items.count(); ++i) { @@ -1133,8 +1125,10 @@ void LLAppearanceManager::updateAppearanceFromCOF() linked_item->isWearableType() ? linked_item->getWearableType() : WT_INVALID ); -#if 1 - // BAP REMOVEME Force failure to test handling +#if 0 + // Fault injection: uncomment this block to test asset + // fetch failures (should be replaced by new defaults in + // lost&found). if (found.mWearableType == WT_SHAPE || found.mWearableType == WT_JACKET) { found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 5b59f52fa5..d0513c35ce 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1925,7 +1925,7 @@ bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat, // - links to attachments // - links to gestures // - links to ensemble folders - LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); // BAP - safe? + LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); if (linked_item) { LLAssetType::EType type = linked_item->getType(); @@ -1936,7 +1936,7 @@ bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat, } else { - LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); // BAP - safe? + LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); // BAP remove AT_NONE support after ensembles are fully working? return (linked_category && ((linked_category->getPreferredType() == LLFolderType::FT_NONE) || @@ -2962,8 +2962,6 @@ void LLFolderBridge::modifyOutfit(BOOL append) LLViewerInventoryCategory* cat = getCategory(); if(!cat) return; - // BAP - was: - // wear_inventory_category_on_avatar( cat, append ); LLAppearanceManager::instance().wearInventoryCategory( cat, FALSE, append ); } -- cgit v1.2.3