diff options
author | Jonathan "Geenz" Goodman <geenz@lindenlab.com> | 2025-06-25 14:32:09 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-06-25 14:32:09 -0400 |
commit | e15a89282171251924a7c75c9007f1cfbc37a8be (patch) | |
tree | 43740d9cba9f41d2f5cdc3b60cdcc107379bfda9 /indra | |
parent | feb4494365e019efd68d6881e4ff63e939a01264 (diff) | |
parent | 6c394f02829ae11b80385d3ff1884a70e623bdef (diff) |
Merge pull request #4177 from DarlCat/hud-media-autoplay
Media changes including support for PRIM_MEDIA_FIRST_CLICK_INTERACT and HUD autoplay
Diffstat (limited to 'indra')
-rw-r--r-- | indra/newview/app_settings/settings.xml | 22 | ||||
-rw-r--r-- | indra/newview/lltoolpie.cpp | 147 | ||||
-rw-r--r-- | indra/newview/lltoolpie.h | 20 | ||||
-rw-r--r-- | indra/newview/llvovolume.cpp | 11 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/panel_preferences_sound.xml | 236 |
5 files changed, 342 insertions, 94 deletions
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 8cfe4f3d97..b515540e1e 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -16190,5 +16190,27 @@ <key>Value</key> <integer>1</integer> </map> + <key>MediaAutoPlayHuds</key> + <map> + <key>Comment</key> + <string>Automatically play HUD media</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>MediaFirstClickInteract</key> + <map> + <key>Comment</key> + <string>This setting controls which media (once loaded) does not require a first click to focus before interaction can begin. This allows clicks to be passed directly to media bypassing the focus click requirement. This setting is a bitfield, precomputed values are as follows: Disabled=0; Worn HUDs only=1; Owned objects=3; Friend objects=7; Group objects=15; Landowner objects=31; Any object=31; All MOAP=1073741824. For complete details see lltoolpie.h enum MediaFirstClickTypes.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>1</integer> + </map> </map> </llsd> diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 8cdc2e94f4..e5bbc73af0 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -72,6 +72,7 @@ #include "llweb.h" #include "pipeline.h" // setHighlightObject #include "lluiusage.h" +#include "llcallingcard.h" extern bool gDebugClicks; @@ -1501,6 +1502,140 @@ static void handle_click_action_play() } } +bool LLToolPie::shouldAllowFirstMediaInteraction(const LLPickInfo& pick, bool moap_flag) +{ + // Early failure cases + if(!pick.getObject()) + { + LL_WARNS() << "pick.getObject() is NULL" << LL_ENDL; + return false; + } + + static LLCachedControl<S32> FirstClickPref(gSavedSettings, "MediaFirstClickInteract", 1); + + // Special / early-exit cases first, then checks get more complex and needy as we go down + // Feature disabled + if(FirstClickPref == MEDIA_FIRST_CLICK_NONE) + { + LL_DEBUGS_ONCE() << "FirstClickPref == MEDIA_FIRST_CLICK_NONE" << LL_ENDL; + return false; + } + // All objects (overriding PRIM_MEDIA_FIRST_CLICK_INTERACT) + if(FirstClickPref == MEDIA_FIRST_CLICK_ALL) + { + LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_ALL" << LL_ENDL; + return true; + } + // Every check beyond this point requires PRIM_MEDIA_FIRST_CLICK_INTERACT to be TRUE + if(!moap_flag) + { + LL_DEBUGS_ONCE() << "PRIM_MEDIA_FIRST_CLICK_INTERACT not set" << LL_ENDL; + return false; + } + // Any object with PRIM_MEDIA_FIRST_CLICK_INTERACT set to TRUE + if(FirstClickPref & MEDIA_FIRST_CLICK_ANY) + { + LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_ANY" << LL_ENDL; + return true; + } + + // The following checks require some object information so we obtain that + LLPointer<LLViewerObject> object = pick.getObject(); + if(object.isNull()) + { + LL_WARNS() << "pick.getObject() is NULL" << LL_ENDL; + return false; + } + + // Own objects + if((FirstClickPref & MEDIA_FIRST_CLICK_OWN) && object->permYouOwner()) + { + LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_OWN" << LL_ENDL; + return true; + } + // HUD attachments + if((FirstClickPref & MEDIA_FIRST_CLICK_HUD) && object->isHUDAttachment()) + { + LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_HUD" << LL_ENDL; + return true; + } + + // Further object detail required beyond this point + LLPermissions* perms = LLSelectMgr::getInstance()->getHoverNode()->mPermissions; + if(perms == nullptr) + { + LL_WARNS() << "LLSelectMgr::getInstance()->getHoverNode()->mPermissions is NULL" << LL_ENDL; + return false; + } + LLUUID owner_id = perms->getOwner(); + LLUUID group_id = perms->getGroup(); + if(owner_id.isNull() && group_id.isNull()) + { + LL_WARNS() << "Owner information was not reliably obtained" << LL_ENDL; + return false; + } + + // Check if the object is owned by a friend of the agent + if(FirstClickPref & MEDIA_FIRST_CLICK_FRIEND) + { + LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_FRIEND. id: " << owner_id << LL_ENDL; + return LLAvatarTracker::instance().isBuddy(owner_id); + } + + // Check for objects set to or owned by the active group + if(FirstClickPref & MEDIA_FIRST_CLICK_GROUP) + { + // Get our active group + LLUUID active_group = gAgent.getGroupID(); + if(active_group.notNull() && (active_group == group_id || active_group == owner_id)) + { + LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_GROUP.Active group: " << active_group << ", group_id:" << group_id << ", owner_id: " << owner_id << LL_ENDL; + return true; + } + } + + // This check ensures that the following conditions are met: + // 1. The object is located in the same parcel as the agent. + // 2. One of the following is true: + // a. The object is owned by the same group as the parcel. + // b. The object is set to the same group as the parcel. + // c. The object is owned by the same owner as the parcel. + // Conditions 2a and 2b are mutually exclusive, our check is the same for both. + if(FirstClickPref & MEDIA_FIRST_CLICK_LAND) + { + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if(parcel == nullptr) + { + LL_WARNS() << "LLViewerParcelMgr::getInstance()->getAgentParcel() is NULL" << LL_ENDL; + return false; + } + + // Same parcel as the agent only + if(!LLViewerParcelMgr::getInstance()->inAgentParcel(object->getPositionGlobal())) + { + LL_WARNS_ONCE() << "Object is not in the same parcel as the agent" << LL_ENDL; + return false; + } + + LLUUID parcel_owner = parcel->getOwnerID(); + LLUUID parcel_group = parcel->getGroupID(); + + // The parcel owner and group can't both be null + if(parcel_owner.isNull() && parcel_group.isNull()) + { + LL_WARNS() << "Parcel owner and group are both null" << LL_ENDL; + return false; + } + + if(owner_id == parcel_owner || group_id == parcel_group) + { + LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_LAND. Parcel owner: " << parcel_owner << ", group_id:" << group_id << ", owner_id: " << owner_id << LL_ENDL; + return true; + } + } + return false; +} + bool LLToolPie::handleMediaClick(const LLPickInfo& pick) { //FIXME: how do we handle object in different parcel than us? @@ -1535,6 +1670,16 @@ bool LLToolPie::handleMediaClick(const LLPickInfo& pick) { // It's okay to give this a null impl LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal); + if (shouldAllowFirstMediaInteraction(pick, mep->getFirstClickInteract())) + { + if (media_impl.notNull()) + { + media_impl->mouseDown(pick.mUVCoords, gKeyboard->currentMask(true)); + mMediaMouseCaptureID = mep->getMediaID(); + setMouseCapture(true); + return true; + } + } } else { @@ -1647,7 +1792,7 @@ bool LLToolPie::handleMediaHover(const LLPickInfo& pick) } // If this is the focused media face, send mouse move events. - if (LLViewerMediaFocus::getInstance()->isFocusedOnFace(objectp, pick.mObjectFace)) + if (LLViewerMediaFocus::getInstance()->isFocusedOnFace(objectp, pick.mObjectFace) || (shouldAllowFirstMediaInteraction(pick, mep->getFirstClickInteract()))) { media_impl->mouseMove(pick.mUVCoords, gKeyboard->currentMask(true)); gViewerWindow->setCursor(media_impl->getLastSetCursor()); diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index b3884a6bfc..f88fc00b4a 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -89,6 +89,26 @@ private: void showVisualContextMenuEffect(); ECursorType cursorFromObject(LLViewerObject* object); + enum MediaFirstClickTypes + { + MEDIA_FIRST_CLICK_NONE = 0, // Special case: Feature is disabled + MEDIA_FIRST_CLICK_HUD = 1 << 0, // 0b00000001 (1) + MEDIA_FIRST_CLICK_OWN = 1 << 1, // 0b00000010 (2) + MEDIA_FIRST_CLICK_GROUP = 1 << 2, // 0b00000100 (4) + MEDIA_FIRST_CLICK_FRIEND = 1 << 3, // 0b00001000 (8) + MEDIA_FIRST_CLICK_LAND = 1 << 4, // 0b00010000 (16) + + // Covers any object with PRIM_MEDIA_FIRST_CLICK_INTERACT (combines all other flags) + MEDIA_FIRST_CLICK_ANY = MEDIA_FIRST_CLICK_HUD & + MEDIA_FIRST_CLICK_OWN & + MEDIA_FIRST_CLICK_GROUP & + MEDIA_FIRST_CLICK_FRIEND & + MEDIA_FIRST_CLICK_LAND, + + // Covers all media regardless of other rules or PRIM_MEDIA_FIRST_CLICK_INTERACT + MEDIA_FIRST_CLICK_ALL = 1 << 30 // 0b01000000000000000000000000000000 (1073741824) + }; + bool shouldAllowFirstMediaInteraction(const LLPickInfo& info, bool moap_flag); bool handleMediaClick(const LLPickInfo& info); bool handleMediaDblClick(const LLPickInfo& info); bool handleMediaHover(const LLPickInfo& info); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index fb6aa7a326..b96df0c79f 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -2643,6 +2643,17 @@ void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool m } viewer_media_t media_impl = LLViewerMedia::getInstance()->updateMediaImpl(mep, previous_url, update_from_self); + static LLCachedControl<bool> media_autoplay_huds(gSavedSettings, "MediaAutoPlayHuds", true); + bool was_loaded = media_impl->hasMedia(); + if (isHUDAttachment() && media_autoplay_huds && !was_loaded) + { + std::string url = mep->getCurrentURL(); + if (media_impl->getCurrentMediaURL() != url) + { + media_impl->navigateTo(url, "", false, true); + } + } + addMediaImpl(media_impl, texture_index) ; } else diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml index d909a56733..efe3d4fb42 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml @@ -62,20 +62,9 @@ name="mute_when_minimized" top_delta="3" left_pad="5" - width="20" /> - <!-- *HACK - After storm-1109 will be fixed: instead of using this text_box, word_wrap should be applied for "mute_when_minimized" check_box's label.--> - <text - follows="top|left" - height="15" - layout="topleft" - left_pad="0" - name="mute_chb_label" - top_delta="-1" - width="150" - wrap="true"> - Mute when minimized - </text> + width="20" + label="Mute when minimized" + word_wrap="true"/> <slider control_name="AudioLevelUI" disabled_control="MuteAudio" @@ -321,66 +310,45 @@ left_pad="5" name="enable_voice_check" width="110"/> - <!-- --> <text type="string" length="1" follows="left|top" layout="topleft" left="23" - top_delta="22" + top_delta="25" name="Listen media from" height="15" - word_wrap="true" - width="112"> - Hear media and sounds from: + width="165" + halign="right"> + Hear media and sounds from </text> - <radio_group + <combo_box control_name="MediaSoundsEarLocation" follows="left|top" - top_delta="-6" layout="topleft" - left_pad="10" - width="360" - height="40" - name="media_ear_location"> - <radio_item - height="19" - label="Camera position" - follows="left|top" - layout="topleft" - name="0" - width="200"/> - <radio_item - height="19" - follows="left|top" - label="Avatar position" - layout="topleft" - left_delta="0" - name="1" - top_delta ="18" - width="200" /> - </radio_group> - <check_box - name="media_show_on_others_btn" - control_name="MediaShowOnOthers" - value="true" - follows="left|top" - layout="topleft" - height="15" - top_pad="8" - tool_tip="Uncheck this to hide media attached to other avatars nearby" - label="Play media attached to other avatars" - left="20" - width="230"/> + left_pad="5" + width="130" + height="23" + top_delta="-4" + name="media_ear_location_combo"> + <item + label="Camera position" + name="camera_position" + value="0" /> + <item + label="Avatar position" + name="avatar_position" + value="1" /> +</combo_box> <text follows="left|top" layout="topleft" height="15" left="23" - top_pad="8" - width="120" - name="media_autoplay_label"> + width="165" + name="media_autoplay_label" + halign="right"> Auto-play media </text> <combo_box @@ -389,10 +357,10 @@ follows="left|top" layout="topleft" height="23" - left_pad="-15" + left_delta="170" top_delta="-4" name="media_auto_play_combo" - width="115"> + width="130"> <item label="Never" name="autoplay_disabled" @@ -406,23 +374,106 @@ name="autoplay_ask" value="2"/> </combo_box> + <text + follows="left|top" + layout="topleft" + height="15" + left="23" + width="165" + name="media_firstinteract_label" + halign="right"> + Media first-interact + </text> + <combo_box + control_name="MediaFirstClickInteract" + enabled_control="AudioStreamingMedia" + follows="left|top" + layout="topleft" + height="23" + left_delta="170" + top_delta="-4" + width="130" + name="media_first_interact_combo" + tool_tip="This setting controls which media (once loaded) does not require a first click to focus before interaction can begin. This allows clicks to be passed directly to media bypassing the focus click requirement. Each option also inherits the previous ones."> + <item + label="Disabled" + name="media_first_click_none" + value="0"/> + <item + label="Worn HUDs only" + name="media_first_click_hud" + value="1"/> + <item + label="Owned objects" + name="media_first_click_own" + value="3"/> + <item + label="Friend objects" + name="media_first_click_group" + value="7"/> + <item + label="Group objects" + name="media_first_click_friend" + value="15"/> + <item + label="Landowner objects" + name="media_first_click_land" + value="31"/> + <item + label="Any object" + name="media_first_interact_any" + value="31"/> + <item + label="All MOAP" + name="media_first_click_all" + value="1073741824"/> + </combo_box> + <check_box + name="media_show_on_others_btn" + control_name="MediaShowOnOthers" + enabled_control="AudioStreamingMedia" + value="true" + follows="left|top" + tool_tip="Uncheck this to hide media attached to other avatars nearby" + label="Play media attached to other avatars" + left="23" + width="15" + top_delta="30" + height="15"/> + <check_box + name="media_huds_autoplay" + control_name="MediaAutoPlayHuds" + enabled_control="AudioStreamingMedia" + value="true" + follows="left|top" + layout="topleft" + tool_tip="Uncheck this to make HUDs follow the standard media auto-play setting" + label="Auto-play media attached to your HUD" + left="260" + top_pad="-15" + width="15" + height="15"/> <text layout="topleft" + follows="left" height="15" - left="260" - top_pad="-18" - width="100" - name="noise_suppression_label"> - Noise Suppression + width="165" + name="noise_suppression_label" + left="23" + top_delta="22" + halign="right"> + Microphone Noise Suppression </text> <combo_box control_name="VoiceNoiseSuppressionLevel" + enabled_control="EnableVoiceChat" + follows="left|top" layout="topleft" + left_delta="170" + top_delta="-6" + width="130" height="23" - left_pad="10" - top_pad="-20" - name="noise_suppression_combo" - width="80"> + name="noise_suppression_combo"> <item label="Off" name="noise_suppression_none" @@ -452,48 +503,44 @@ left="23" top_delta="30" name="Listen from" - width="112"> - Hear voice from: + width="165" + height="15" + halign="right"> + Hear voice from </text> - <radio_group + <combo_box enabled_control="EnableVoiceChat" control_name="VoiceEarLocation" follows="left|top" layout="topleft" - left_pad="10" + left_delta="170" top_delta="-6" - width="360" - height="40" - name="ear_location"> - <radio_item - height="19" - label="Camera position" - follows="left|top" - layout="topleft" - name="0" - width="200"/> - <radio_item - height="19" - follows="left|top" - label="Avatar position" - layout="topleft" - left_delta="0" - name="1" - top_delta ="18" - width="200" /> - </radio_group> + width="130" + height="23" + name="ear_location_combo"> + <item + label="Camera position" + name="camera_position" + value="0" /> + <item + label="Avatar position" + name="avatar_position" + value="1" /> +</combo_box> <check_box control_name="LipSyncEnabled" + enabled_control="EnableVoiceChat" follows="left|top" height="15" label="Move avatar lips when speaking" layout="topleft" left="20" name="enable_lip_sync" - top_pad="10" + top_pad="8" width="237"/> <check_box control_name="VoiceEchoCancellation" + enabled_control="EnableVoiceChat" height="15" tool_tip="Check to enable voice echo cancellation" label="Echo Cancellation" @@ -516,6 +563,7 @@ top_pad="5"/> <check_box control_name="VoiceAutomaticGainControl" + enabled_control="EnableVoiceChat" height="15" tool_tip="Check to enable automatic gain control" label="Automatic Gain Control" @@ -537,6 +585,7 @@ left="20"/> <check_box control_name="VoiceVisualizerEnabled" + enabled_control="EnableVoiceChat" height="15" tool_tip="Check to show voice dot indicator above avatars" label="Show voice dot above avatars" @@ -547,6 +596,7 @@ width="200"/> <button control_name="ShowDeviceSettings" + enabled_control="EnableVoiceChat" follows="left|top" height="23" is_toggle="true" |