summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorJonathan "Geenz" Goodman <geenz@lindenlab.com>2026-05-20 14:14:46 -0400
committerGitHub <noreply@github.com>2026-05-20 14:14:46 -0400
commitacde43cce9700f5c5a50b03b7d96c1db18734e7e (patch)
tree885411015577dfaafa844fc8943d834c9d67bd7d /indra
parentdf844170600608b37c2725f7a263f1de3b055618 (diff)
parent7a40e2702f7d2a81e674f66f637261a09de5b9ca (diff)
Merge pull request #5844 from secondlife/geenz/26.3-to-develop
26.3 to Develop
Diffstat (limited to 'indra')
-rw-r--r--indra/cmake/Copy3rdPartyLibs.cmake60
-rw-r--r--indra/cmake/ViewerMiscLibs.cmake3
-rw-r--r--indra/llmath/v3math.h9
-rw-r--r--indra/llplugin/llpluginclassmedia.cpp12
-rw-r--r--indra/llplugin/llpluginclassmedia.h2
-rw-r--r--indra/llprimitive/llgltfmaterial.cpp65
-rw-r--r--indra/llrender/llfontfreetype.cpp141
-rw-r--r--indra/llrender/llfontfreetype.h15
-rw-r--r--indra/llrender/llfontgl.cpp13
-rw-r--r--indra/llrender/llfontgl.h3
-rw-r--r--indra/llrender/llfontregistry.cpp66
-rw-r--r--indra/llrender/llfontregistry.h31
-rw-r--r--indra/llrender/llrender.cpp63
-rw-r--r--indra/llrender/llrender.h13
-rw-r--r--indra/llui/llaccordionctrltab.cpp2
-rw-r--r--indra/llui/llbutton.cpp25
-rw-r--r--indra/llui/llbutton.h9
-rw-r--r--indra/llui/llconsole.cpp11
-rw-r--r--indra/llui/lldraghandle.cpp12
-rw-r--r--indra/llui/lldraghandle.h8
-rw-r--r--indra/llui/llfloater.cpp10
-rw-r--r--indra/llui/llfloater.h6
-rw-r--r--indra/llui/llfocusmgr.cpp5
-rw-r--r--indra/llui/llfocusmgr.h2
-rw-r--r--indra/llui/llfolderviewitem.cpp14
-rw-r--r--indra/llui/llfolderviewitem.h4
-rw-r--r--indra/llui/lllayoutstack.cpp11
-rw-r--r--indra/llui/lllayoutstack.h6
-rw-r--r--indra/llui/lllineeditor.cpp7
-rw-r--r--indra/llui/lllineeditor.h4
-rw-r--r--indra/llui/llmenugl.cpp17
-rw-r--r--indra/llui/lltabcontainer.cpp28
-rw-r--r--indra/llui/lltabcontainer.h1
-rw-r--r--indra/llui/lltextbase.cpp5
-rw-r--r--indra/llui/lltextbase.h1
-rw-r--r--indra/llui/lluictrl.cpp2
-rw-r--r--indra/llui/llviewborder.cpp2
-rw-r--r--indra/llwebrtc/llwebrtc.cpp80
-rw-r--r--indra/llwebrtc/llwebrtc.h6
-rw-r--r--indra/llwebrtc/llwebrtc_impl.h14
-rw-r--r--indra/llxml/llcontrol.cpp45
-rw-r--r--indra/llxml/llcontrol.h8
-rw-r--r--indra/newview/CMakeLists.txt18
-rw-r--r--indra/newview/VIEWER_VERSION.txt2
-rw-r--r--indra/newview/app_settings/settings.xml252
-rw-r--r--indra/newview/installers/windows/installer_template.nsi3
-rw-r--r--indra/newview/licenses-linux.txt9
-rw-r--r--indra/newview/licenses-mac.txt178
-rw-r--r--indra/newview/licenses-win32.txt178
-rw-r--r--indra/newview/llappviewer.cpp72
-rw-r--r--indra/newview/llappviewerwin32.cpp16
-rw-r--r--indra/newview/llcolorswatch.cpp18
-rw-r--r--indra/newview/llconversationloglist.cpp65
-rw-r--r--indra/newview/llconversationloglist.h10
-rw-r--r--indra/newview/lleventpoll.cpp25
-rw-r--r--indra/newview/llfilepicker_mac.mm4
-rw-r--r--indra/newview/llfloaterconversationlog.cpp8
-rw-r--r--indra/newview/llfloaterimcontainer.cpp111
-rw-r--r--indra/newview/llfloaterimcontainer.h1
-rw-r--r--indra/newview/llfloaterimsession.cpp2
-rw-r--r--indra/newview/llfloaterimsessiontab.cpp2
-rw-r--r--indra/newview/llfloatersettingsdebug.cpp42
-rw-r--r--indra/newview/llimview.cpp12
-rw-r--r--indra/newview/llmeshrepository.cpp44
-rw-r--r--indra/newview/llnearbyvoicemoderation.cpp220
-rw-r--r--indra/newview/llnearbyvoicemoderation.h50
-rw-r--r--indra/newview/llnotificationlistitem.cpp4
-rw-r--r--indra/newview/llpanelface.cpp2
-rw-r--r--indra/newview/llpanellogin.cpp154
-rw-r--r--indra/newview/llpanellogin.h12
-rw-r--r--indra/newview/llspeakers.cpp2
-rw-r--r--indra/newview/llstartup.cpp5
-rw-r--r--indra/newview/lltoastnotifypanel.cpp40
-rw-r--r--indra/newview/lltoastnotifypanel.h2
-rw-r--r--indra/newview/llvelopack.cpp230
-rw-r--r--indra/newview/llvelopack.h5
-rw-r--r--indra/newview/llviewerchat.cpp2
-rw-r--r--indra/newview/llviewermenu.cpp3
-rw-r--r--indra/newview/llviewernetwork.cpp4
-rw-r--r--indra/newview/llviewernetwork.h1
-rw-r--r--indra/newview/llviewerparcelmgr.cpp10
-rw-r--r--indra/newview/llviewerparcelmgr.h6
-rwxr-xr-xindra/newview/llviewerparceloverlay.cpp235
-rw-r--r--indra/newview/llviewerparceloverlay.h5
-rwxr-xr-xindra/newview/llviewerregion.cpp11
-rw-r--r--indra/newview/llviewerregion.h2
-rw-r--r--indra/newview/llviewerstats.cpp17
-rw-r--r--indra/newview/llviewerstats.h3
-rw-r--r--indra/newview/llviewertexturelist.cpp32
-rw-r--r--indra/newview/llviewerwindow.cpp20
-rw-r--r--indra/newview/llvoiceclient.cpp106
-rw-r--r--indra/newview/llvoiceclient.h11
-rw-r--r--indra/newview/llvoicevivox.cpp7926
-rw-r--r--indra/newview/llvoicevivox.h1093
-rw-r--r--indra/newview/llvoicewebrtc.cpp186
-rw-r--r--indra/newview/llvoicewebrtc.h7
-rw-r--r--indra/newview/llwindowlistener.cpp105
-rw-r--r--indra/newview/llwindowlistener.h1
-rw-r--r--indra/newview/skins/default/colors.xml52
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Cam_Rotate_Center.pngbin10689 -> 1816 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Cam_Rotate_In.pngbin407 -> 1794 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Cam_Tracking_Center.pngbin1714 -> 1806 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Cam_Tracking_In.pngbin328 -> 1717 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Backward_On.pngbin353 -> 1723 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Down_On.pngbin50907 -> 2091 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Forward_On.pngbin321 -> 1710 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Left_On.pngbin51806 -> 2269 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Right_On.pngbin50161 -> 2063 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_TurnLeft_On.pngbin430 -> 1806 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_TurnRight_On.pngbin427 -> 1946 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Movement_Up_On.pngbin51965 -> 2282 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl1.pngbin557 -> 1960 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl2.pngbin663 -> 2053 bytes
-rw-r--r--indra/newview/skins/default/textures/bottomtray/VoicePTT_On.pngbin451 -> 1842 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Cone_Selected.pngbin576 -> 2394 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Cube_Selected.pngbin477 -> 2278 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Cylinder_Selected.pngbin443 -> 2273 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Grass_Selected.pngbin757 -> 2538 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Hemi_Cone_Selected.pngbin531 -> 2357 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Hemi_Cylinder_Selected.pngbin463 -> 2292 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Hemi_Sphere_Selected.pngbin696 -> 2530 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Prism_Selected.pngbin485 -> 2419 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Pyramid_Selected.pngbin594 -> 2389 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Ring_Selected.pngbin738 -> 2560 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Sphere_Selected.pngbin1003 -> 2799 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Tetrahedron_Selected.pngbin558 -> 2394 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Torus_Selected.pngbin825 -> 2645 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Tree_Selected.pngbin839 -> 2794 bytes
-rw-r--r--indra/newview/skins/default/textures/build/Object_Tube_Selected.pngbin552 -> 2506 bytes
-rw-r--r--indra/newview/skins/default/textures/containers/Accordion_Selected.pngbin228 -> 15050 bytes
-rw-r--r--indra/newview/skins/default/textures/containers/TabLeft_Flat_Off.pngbin0 -> 18169 bytes
-rw-r--r--indra/newview/skins/default/textures/containers/TabLeft_Flat_Selected.pngbin0 -> 18193 bytes
-rw-r--r--indra/newview/skins/default/textures/containers/TabTop_First_Flat_Off.pngbin0 -> 18167 bytes
-rw-r--r--indra/newview/skins/default/textures/containers/TabTop_First_Flat_Selected.pngbin0 -> 18172 bytes
-rw-r--r--indra/newview/skins/default/textures/containers/TabTop_Last_Flat_Off.pngbin0 -> 18164 bytes
-rw-r--r--indra/newview/skins/default/textures/containers/TabTop_Last_Flat_Selected.pngbin0 -> 18166 bytes
-rw-r--r--indra/newview/skins/default/textures/containers/TabTop_Middle_Flat_Off.pngbin0 -> 18168 bytes
-rw-r--r--indra/newview/skins/default/textures/containers/TabTop_Middle_Flat_Selected.pngbin0 -> 18174 bytes
-rw-r--r--indra/newview/skins/default/textures/containers/Toolbar_Middle_Selected.pngbin296 -> 15778 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Info_Over.pngbin520 -> 1974 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_SysClosed.pngbin656 -> 2266 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_SysOpen.pngbin766 -> 2361 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/SL_Logo.pngbin1515 -> 1136 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/back_arrow_off.pngbin1223 -> 802 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/back_arrow_over.pngbin1256 -> 799 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/back_arrow_press.pngbin1417 -> 802 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/check_mark.pngbin1227 -> 2136 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/hand.pngbin1183 -> 2337 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/see_me_online.pngbin645 -> 1843 bytes
-rw-r--r--indra/newview/skins/default/textures/locked_image_dark.pngbin0 -> 18122 bytes
-rw-r--r--indra/newview/skins/default/textures/navbar/Favorite_Star_Active.pngbin704 -> 2241 bytes
-rw-r--r--indra/newview/skins/default/textures/navbar/Favorite_Star_Over.pngbin445 -> 1967 bytes
-rw-r--r--indra/newview/skins/default/textures/navbar/Row_Selection.pngbin231 -> 1736 bytes
-rw-r--r--indra/newview/skins/default/textures/square_selection.pngbin0 -> 18061 bytes
-rw-r--r--indra/newview/skins/default/textures/textures.xml26
-rw-r--r--indra/newview/skins/default/textures/widgets/Checkbox_Disabled.pngbin470 -> 14960 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/Checkbox_Off.pngbin480 -> 14961 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/Checkbox_On.pngbin635 -> 15341 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/Checkbox_On_Disabled.pngbin621 -> 15333 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/Checkbox_On_Press.pngbin647 -> 15245 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/Checkbox_Press.pngbin515 -> 15313 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/Checkbox_Slim_Off.pngbin0 -> 18115 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/Checkbox_Slim_On.pngbin0 -> 17762 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/ComboButton_Arrow.pngbin0 -> 16236 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/ComboButton_Disabled.pngbin575 -> 15356 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/ComboButton_Off.pngbin583 -> 15127 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/ComboButton_Selected.pngbin630 -> 15216 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/ComboButton_Transparent.pngbin0 -> 18116 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/ComboButton_UpOff.pngbin553 -> 16654 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/ComboButton_UpSelected.pngbin603 -> 16828 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/DropDown_Disabled.pngbin669 -> 15771 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/DropDown_Off.pngbin678 -> 15125 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/DropDown_On.pngbin869 -> 15433 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/DropDown_Press.pngbin702 -> 15322 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/ListItem_Over.pngbin443 -> 15029 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/ListItem_Select.pngbin460 -> 15029 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/MarketplaceBtn_Off.pngbin911 -> 15460 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/MarketplaceBtn_Selected.pngbin912 -> 15538 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/PushButton_Disabled.pngbin569 -> 15664 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/PushButton_Login.pngbin1437 -> 18568 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/PushButton_Login_Over.pngbin1516 -> 18568 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/PushButton_Login_Pressed.pngbin1493 -> 18571 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/PushButton_Off.pngbin579 -> 15660 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/PushButton_On.pngbin835 -> 15296 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/PushButton_Over.pngbin589 -> 15808 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/PushButton_Press.pngbin614 -> 15657 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/PushButton_Selected_Press.pngbin998 -> 15333 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/PushButton_Sign.pngbin0 -> 18631 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/PushButton_Sign_Over.pngbin0 -> 18631 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/PushButton_Sign_Pressed.pngbin0 -> 18631 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/RadioButton_Disabled.pngbin606 -> 15444 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/RadioButton_Off.pngbin628 -> 16378 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/RadioButton_On.pngbin679 -> 16857 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/RadioButton_On_Disabled.pngbin652 -> 15907 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/RadioButton_On_Press.pngbin688 -> 15781 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/RadioButton_Press.pngbin666 -> 15307 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/ScrollThumb_Horiz.pngbin509 -> 15228 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/ScrollThumb_Vert.pngbin494 -> 15233 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Disabled.pngbin454 -> 15261 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected.pngbin524 -> 15265 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Disabled.pngbin613 -> 15279 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Press.pngbin728 -> 15359 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/SliderThumb_Disabled.pngbin592 -> 15444 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/SliderThumb_Off.pngbin579 -> 16378 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/SliderThumb_Press.pngbin582 -> 15307 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/SliderTrack_Horiz.pngbin420 -> 15033 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/Stepper_Down_Off.pngbin477 -> 15325 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/Stepper_Down_Press.pngbin502 -> 15389 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/Stepper_Up_Off.pngbin482 -> 15315 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/Stepper_Up_Press.pngbin521 -> 15543 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/TextField_Highlight.pngbin0 -> 15490 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/TextField_Transparent.pngbin0 -> 15031 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/track_control_moon_back.pngbin1767 -> 2587 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/track_control_moon_front.pngbin2060 -> 2479 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/track_control_sphere.pngbin7537 -> 9705 bytes
-rw-r--r--indra/newview/skins/default/textures/widgets/track_control_sun_back.pngbin1626 -> 2439 bytes
-rw-r--r--indra/newview/skins/default/textures/windows/Inspector_I.pngbin547 -> 1974 bytes
-rw-r--r--indra/newview/skins/default/textures/windows/Window_Background.pngbin508 -> 15072 bytes
-rw-r--r--indra/newview/skins/default/textures/windows/Window_Foreground.pngbin517 -> 15060 bytes
-rw-r--r--indra/newview/skins/default/textures/windows/login_sl_logo_horizontal.pngbin0 -> 4366 bytes
-rw-r--r--indra/newview/skins/default/xui/da/floater_joystick.xml14
-rw-r--r--indra/newview/skins/default/xui/da/floater_whitelist_entry.xml2
-rw-r--r--indra/newview/skins/default/xui/da/panel_preferences_alerts.xml1
-rw-r--r--indra/newview/skins/default/xui/da/panel_preferences_sound.xml2
-rw-r--r--indra/newview/skins/default/xui/de/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/en/floater_about_land.xml26
-rw-r--r--indra/newview/skins/default/xui/en/floater_add_payment_method.xml6
-rw-r--r--indra/newview/skins/default/xui/en/floater_adjust_environment.xml26
-rw-r--r--indra/newview/skins/default/xui/en/floater_avatar_picker.xml4
-rw-r--r--indra/newview/skins/default/xui/en/floater_bulk_perms.xml12
-rw-r--r--indra/newview/skins/default/xui/en/floater_buy_currency.xml13
-rw-r--r--indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml6
-rw-r--r--indra/newview/skins/default/xui/en/floater_edit_hover_height.xml4
-rw-r--r--indra/newview/skins/default/xui/en/floater_font_test.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_god_tools.xml58
-rw-r--r--indra/newview/skins/default/xui/en/floater_inventory_settings.xml13
-rw-r--r--indra/newview/skins/default/xui/en/floater_live_material_editor.xml6
-rw-r--r--indra/newview/skins/default/xui/en/floater_material_editor.xml6
-rw-r--r--indra/newview/skins/default/xui/en/floater_model_preview.xml21
-rw-r--r--indra/newview/skins/default/xui/en/floater_my_environments.xml11
-rw-r--r--indra/newview/skins/default/xui/en/floater_my_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_new_feature_notification.xml4
-rw-r--r--indra/newview/skins/default/xui/en/floater_performance.xml8
-rw-r--r--indra/newview/skins/default/xui/en/floater_preferences.xml4
-rw-r--r--indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml24
-rw-r--r--indra/newview/skins/default/xui/en/floater_stats.xml58
-rw-r--r--indra/newview/skins/default/xui/en/floater_telehub.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_test_slapp.xml1
-rw-r--r--indra/newview/skins/default/xui/en/floater_test_textbox.xml4
-rw-r--r--indra/newview/skins/default/xui/en/floater_tools.xml668
-rw-r--r--indra/newview/skins/default/xui/en/floater_toybox.xml4
-rw-r--r--indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_whitelist_entry.xml6
-rw-r--r--indra/newview/skins/default/xui/en/floater_world_map.xml51
-rw-r--r--indra/newview/skins/default/xui/en/fonts.xml140
-rw-r--r--indra/newview/skins/default/xui/en/inspect_group.xml10
-rw-r--r--indra/newview/skins/default/xui/en/menu_conversation.xml107
-rw-r--r--indra/newview/skins/default/xui/en/menu_conversation_log_view.xml10
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml17
-rw-r--r--indra/newview/skins/default/xui/en/panel_avatar_list_item.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_blocked_list_item.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_chat_header.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_chiclet_bar.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_conversation_list_item.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_shape.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_experience_search.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_gltf_material.xml12
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_general.xml3
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_list_item.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_notices.xml5
-rw-r--r--indra/newview/skins/default/xui/en/panel_hint.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_hint_image.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_login.xml549
-rw-r--r--indra/newview/skins/default/xui/en/panel_login_first.xml262
-rw-r--r--indra/newview/skins/default/xui/en/panel_main_inventory.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_marketplace_listings.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_navigation_bar.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_notification_list_item.xml6
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfit_edit.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_people.xml5
-rw-r--r--indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml6
-rw-r--r--indra/newview/skins/default/xui/en/panel_performance_preferences.xml19
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_advanced.xml26
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_general.xml13
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml38
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_privacy.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_setup.xml21
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_sound.xml31
-rw-r--r--indra/newview/skins/default/xui/en/panel_region_experiences.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_region_general.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_region_terrain.xml26
-rw-r--r--indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml14
-rw-r--r--indra/newview/skins/default/xui/en/panel_status_bar.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_tools_texture.xml256
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_appearance.xml20
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/button.xml5
-rw-r--r--indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/filter_editor.xml8
-rw-r--r--indra/newview/skins/default/xui/en/widgets/floater.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/folder_view_item.xml13
-rw-r--r--indra/newview/skins/default/xui/en/widgets/gesture_combo_list.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/inbox_folder_view_item.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/inventory_list_item.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/line_editor.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml1
-rw-r--r--indra/newview/skins/default/xui/en/widgets/search_editor.xml8
-rw-r--r--indra/newview/skins/default/xui/en/widgets/simple_text_editor.xml4
-rw-r--r--indra/newview/skins/default/xui/en/widgets/tab_container.xml29
-rw-r--r--indra/newview/skins/default/xui/en/widgets/toolbar.xml7
-rw-r--r--indra/newview/skins/default/xui/en/widgets/wearable_outfit_list_item.xml10
-rw-r--r--indra/newview/skins/default/xui/es/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/fr/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/it/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/ja/fonts.xml78
-rw-r--r--indra/newview/skins/default/xui/ja/panel_login_first.xml54
-rw-r--r--indra/newview/skins/default/xui/pl/panel_login_first.xml30
-rw-r--r--indra/newview/skins/default/xui/pt/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/ru/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/tr/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/zh/panel_login_first.xml39
-rw-r--r--indra/newview/tests/llviewernetwork_test.cpp10
-rwxr-xr-xindra/newview/viewer_manifest.py28
325 files changed, 3955 insertions, 11884 deletions
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 680f2f3ac2..667a04a1c5 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -29,29 +29,6 @@ endmacro()
###################################################################
if(WINDOWS)
#*******************************
- # VIVOX - *NOTE: no debug version
- set(vivox_lib_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
-
- # ND, it seems there is no such thing defined. At least when building a viewer
- # Does this maybe matter on some LL buildserver? Otherwise this and the snippet using slvoice_src_dir
- # can all go
- if( ARCH_PREBUILT_BIN_RELEASE )
- set(slvoice_src_dir "${ARCH_PREBUILT_BIN_RELEASE}")
- endif()
- set(slvoice_files SLVoice.exe )
- if (ADDRESS_SIZE EQUAL 64)
- list(APPEND vivox_libs
- vivoxsdk_x64.dll
- ortp_x64.dll
- )
- else (ADDRESS_SIZE EQUAL 64)
- list(APPEND vivox_libs
- vivoxsdk.dll
- ortp.dll
- )
- endif (ADDRESS_SIZE EQUAL 64)
-
- #*******************************
# Misc shared libs
set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
@@ -159,12 +136,6 @@ if(WINDOWS)
endforeach()
elseif(DARWIN)
- set(vivox_lib_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
- set(slvoice_files SLVoice)
- set(vivox_libs
- libortp.dylib
- libvivoxsdk.dylib
- )
set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}")
set(debug_files
)
@@ -188,15 +159,6 @@ elseif(LINUX)
set(SHARED_LIB_STAGING_DIR_RELWITHDEBINFO "${SHARED_LIB_STAGING_DIR}")
set(SHARED_LIB_STAGING_DIR_RELEASE "${SHARED_LIB_STAGING_DIR}")
- set(vivox_lib_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
- set(vivox_libs
- libsndfile.so.1
- libortp.so
- libvivoxoal.so.1
- libvivoxsdk.so
- )
- set(slvoice_files SLVoice)
-
# *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables
# or ARCH_PREBUILT_DIRS
set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}")
@@ -226,8 +188,6 @@ elseif(LINUX)
else(WINDOWS)
message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...")
- set(vivox_lib_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-linux")
- set(vivox_libs "")
# *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables
# or ARCH_PREBUILT_DIRS
set(debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-linux/lib/debug")
@@ -249,26 +209,6 @@ endif(WINDOWS)
# Done building the file lists, now set up the copy commands.
################################################################
-# Curiously, slvoice_files are only copied to SHARED_LIB_STAGING_DIR_RELEASE.
-# It's unclear whether this is oversight or intentional, but anyway leave the
-# single copy_if_different command rather than using to_staging_dirs.
-
-if( slvoice_src_dir )
- copy_if_different(
- ${slvoice_src_dir}
- "${SHARED_LIB_STAGING_DIR_RELEASE}"
- out_targets
- ${slvoice_files}
- )
- list(APPEND third_party_targets ${out_targets})
-endif()
-
-to_staging_dirs(
- ${vivox_lib_dir}
- third_party_targets
- ${vivox_libs}
- )
-
to_staging_dirs(
${release_src_dir}
third_party_targets
diff --git a/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake
index cae68fbc11..5974a5d212 100644
--- a/indra/cmake/ViewerMiscLibs.cmake
+++ b/indra/cmake/ViewerMiscLibs.cmake
@@ -16,8 +16,7 @@ if( NOT USE_CONAN )
use_prebuilt_binary(libhunspell)
endif()
-use_prebuilt_binary(slvoice)
-
use_prebuilt_binary(nanosvg)
use_prebuilt_binary(viewer-fonts)
+use_prebuilt_binary(google-fonts)
use_prebuilt_binary(emoji_shortcodes)
diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h
index 0e11dca876..196ecdcf7d 100644
--- a/indra/llmath/v3math.h
+++ b/indra/llmath/v3math.h
@@ -155,7 +155,6 @@ class LLVector3
friend const LLVector3& operator*=(LLVector3 &a, const LLVector3 &b); // Returns a * b;
friend const LLVector3& operator*=(LLVector3 &a, F32 k); // Return a times scaler k
friend const LLVector3& operator/=(LLVector3 &a, F32 k); // Return a divided by scaler k
- friend const LLVector3& operator/=(LLVector3& a, const LLVector3& b);
friend const LLVector3& operator*=(LLVector3 &a, const LLQuaternion &b); // Returns a * b;
friend LLVector3 operator-(const LLVector3 &a); // Return vector -a
@@ -461,14 +460,6 @@ inline const LLVector3& operator/=(LLVector3& a, F32 k)
return a;
}
-inline const LLVector3& operator/=(LLVector3& a, const LLVector3& b)
-{
- a.mV[VX] /= b.mV[VX];
- a.mV[VY] /= b.mV[VY];
- a.mV[VZ] /= b.mV[VZ];
- return a;
-}
-
inline LLVector3 operator-(const LLVector3& a)
{
return LLVector3(-a.mV[VX], -a.mV[VY], -a.mV[VZ]);
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 88d428c233..4e80f4c0ca 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -1642,3 +1642,15 @@ void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history)
LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL;
}
+
+void LLPluginClassMedia::forceRenderRefresh()
+{
+ // Force layout recalculation by briefly hiding/showing the web content
+ // Used to clear black screen issues after resize, see #5607
+ const std::string refresh_script =
+ "document.documentElement.style.visibility='hidden';"
+ "document.documentElement.offsetHeight;"
+ "document.documentElement.style.visibility='';";
+
+ executeJavaScript(refresh_script);
+}
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 71522bcd7d..40f6295e55 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -350,6 +350,8 @@ public:
std::shared_ptr<LLPluginClassMedia> getSharedPtr() { return std::dynamic_pointer_cast<LLPluginClassMedia>(shared_from_this()); } // due to enable_shared_from_this
+ void forceRenderRefresh();
+
protected:
LLPluginClassMediaOwner *mOwner;
diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp
index 1c47001272..764ab222ad 100644
--- a/indra/llprimitive/llgltfmaterial.cpp
+++ b/indra/llprimitive/llgltfmaterial.cpp
@@ -937,6 +937,15 @@ void LLGLTFMaterial::updateTextureTracking()
// Case 4.
// Input: scale 1.0,1.0; Offset horizontal 0.5, Offset vertical 0.0 Rotation 0.349066;
// Expected output: scale 1.0,1.0; Offset horizontal 0.701, Offset vertical -0.141 Rotation -0.349066;
+// Case 5.
+// Input: scale 10.0,15.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation -1.57079637
+// Expected output: scale 15.0,10.0; Offset horizontal 7.5, Offset vertical -4.0 Rotation 1.57079637;
+// Case 6.
+// Input: scale 10.0,15.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation 0
+// Expected output: scale 10.0,15.0; Offset horizontal 0.5, Offset vertical .0 Rotation 0;
+// Case 7.
+// Input: scale 10.0,15.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation -0.785398163
+// Expected output: scale 12.74,12.74; Offset horizontal 0.5, Offset vertical .0 Rotation 0.785398163;
//
// Legacy offsets are right to left and top to bottom.
// PBR offsets are right to left and bottom to top.
@@ -953,16 +962,32 @@ void LLGLTFMaterial::convertTextureTransformToPBR(
LLVector2& pbr_offset,
F32& pbr_rotation)
{
- pbr_scale.set(tex_scale_s, tex_scale_t);
+ // Legacy is counter-clockwise, PBR is clockwise
pbr_rotation = -tex_rotation;
// Center of the tile
const F32 center_s = 0.5f;
const F32 center_t = 0.5f;
+ // Calculate the rotated scale
+ F32 cos_rot = cosf(tex_rotation);
+ F32 sin_rot = sinf(tex_rotation);
+ F32 cos_sq = cos_rot * cos_rot;
+ F32 sin_sq = sin_rot * sin_rot;
+
+ // GLTF scale doesn't match legacy scaling when rotation is applied.
+ // Legacy applies scale then rotation, which allows for planar aligment
+ // withoutn deformations, but gltf rotates first, so when scale gets
+ // aplied image gets deformed by rotation.
+ // It appears to be imposible to properly match legacy scale, so this
+ // is an approximation that at least matches at 0, 90, 180, 270 degree
+ // rotations, and is close enough at angles like 45.
+ pbr_scale.mV[VX] = tex_scale_s * cos_sq + tex_scale_t * sin_sq;
+ pbr_scale.mV[VY] = tex_scale_s * sin_sq + tex_scale_t * cos_sq;
+
// Center adjustment for scale
- F32 center_adjust_s = 0.5f * (1.0f - tex_scale_s);
- F32 center_adjust_t = 0.5f * (1.0f - tex_scale_t);
+ F32 center_adjust_s = 0.5f * (1.0f - pbr_scale.mV[VX]);
+ F32 center_adjust_t = 0.5f * (1.0f - pbr_scale.mV[VY]);
// 2. Offset from center
F32 pos_s = center_adjust_s - center_s;
@@ -990,17 +1015,43 @@ void LLGLTFMaterial::convertPBRTransformToTexture(
F32& tex_offset_t,
F32& tex_rotation)
{
- tex_scale_s = pbr_scale.mV[0];
- tex_scale_t = pbr_scale.mV[1];
tex_rotation = -pbr_rotation;
+ // Reverse the scale transformation
+ // From: pbr_s = tex_s * cos² + tex_t * sin²
+ // pbr_t = tex_s * sin² + tex_t * cos²
+ // Solve for tex_s and tex_t
+ F32 cos_rot = cosf(tex_rotation);
+ F32 sin_rot = sinf(tex_rotation);
+ F32 cos_sq = cos_rot * cos_rot;
+ F32 sin_sq = sin_rot * sin_rot;
+
+ F32 denom = cos_sq * cos_sq - sin_sq * sin_sq;
+
+ if (fabsf(denom) < 0.0001f) // Near 45 degrees (cos²≈sin²≈0.5)
+ {
+ // At 45°: both scales contribute equally
+ // pbr_s = pbr_t = (tex_s + tex_t) / 2
+ // So: tex_s + tex_t = 2 * pbr_avg
+ // Use the average and assume symmetric scaling
+ tex_scale_s = tex_scale_t = (pbr_scale.mV[VX] + pbr_scale.mV[VY]) / 2.f;
+ }
+ else
+ {
+ // Solve the 2x2 system:
+ // pbr_s * cos² - pbr_t * sin² = tex_s * (cos⁴ - sin⁴)
+ // pbr_t * cos² - pbr_s * sin² = tex_t * (cos⁴ - sin⁴)
+ tex_scale_s = (pbr_scale.mV[VX] * cos_sq - pbr_scale.mV[VY] * sin_sq) / denom;
+ tex_scale_t = (pbr_scale.mV[VY] * cos_sq - pbr_scale.mV[VX] * sin_sq) / denom;
+ }
+
// Center of the tile
const F32 center_s = 0.5f;
const F32 center_t = 0.5f;
// Center adjustment for scale
- F32 center_adjust_s = 0.5f * (1.0f - tex_scale_s);
- F32 center_adjust_t = 0.5f * (1.0f - tex_scale_t);
+ F32 center_adjust_s = 0.5f * (1.0f - pbr_scale.mV[VX]);
+ F32 center_adjust_t = 0.5f * (1.0f - pbr_scale.mV[VY]);
// 2. Offset from center
F32 pos_s = center_adjust_s - center_s;
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index d9857a7ad5..075c496ec5 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -39,6 +39,7 @@
// For some reason, this won't work if it's not wrapped in the ifdef
#ifdef FT_FREETYPE_H
#include FT_FREETYPE_H
+#include FT_MULTIPLE_MASTERS_H
#endif
#include "lldir.h"
@@ -116,6 +117,8 @@ LLFontGlyphInfo::LLFontGlyphInfo(U32 index, EFontGlyphType glyph_type)
mYBitmapOffset(0), // Offset to the origin in the bitmap
mXBearing(0), // Distance from baseline to left in pixels
mYBearing(0), // Distance from baseline to top in pixels
+ mLsbDelta(0),
+ mRsbDelta(0),
mBitmapEntry(std::make_pair(EFontGlyphType::Unspecified, -1)) // Which bitmap in the bitmap cache contains this glyph
{
}
@@ -131,6 +134,8 @@ LLFontGlyphInfo::LLFontGlyphInfo(const LLFontGlyphInfo& fgi)
, mYBitmapOffset(fgi.mYBitmapOffset)
, mXBearing(fgi.mXBearing)
, mYBearing(fgi.mYBearing)
+ , mLsbDelta(fgi.mLsbDelta)
+ , mRsbDelta(fgi.mRsbDelta)
{
mBitmapEntry = fgi.mBitmapEntry;
}
@@ -141,6 +146,7 @@ LLFontFreetype::LLFontFreetype()
mDescender(0.f),
mLineHeight(0.f),
mIsFallback(false),
+ mHinting(EFontHinting::FORCE_AUTOHINT),
mFTFace(nullptr),
mRenderGlyphCount(0),
mStyle(0),
@@ -164,7 +170,7 @@ LLFontFreetype::~LLFontFreetype()
// mFallbackFonts cleaned up by LLPointer destructor
}
-bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool is_fallback, S32 face_n)
+bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags)
{
// Don't leak face objects. This is also needed to deal with
// changed font file names.
@@ -188,6 +194,20 @@ bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
return false;
mIsFallback = is_fallback;
+ mHinting = hinting;
+ mFontFlags = flags;
+ mWeight = weight;
+
+ bool variable_font = false;
+ if (weight >= 0)
+ {
+ variable_font = setVariationAxis("wght", static_cast<F32>(weight));
+
+ // For Inter, also set optical size based on point size
+ // This makes text look better at different sizes
+ setVariationAxis("opsz", point_size);
+ }
+
F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi
error = FT_Set_Char_Size(mFTFace, /* handle to face object */
@@ -243,6 +263,18 @@ bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
{
mStyle |= LLFontGL::BOLD;
}
+ else if (flags & LLFontGL::BOLD)
+ {
+ // FontGL applies programmatic bolding to fonts that are a part of 'bold' descriptor but don't have the bold style set.
+ // Ex: Inter SemiBold doesn't have FT_STYLE_FLAG_BOLD and without this style it would be bolded programmatically.
+ mStyle |= LLFontGL::BOLD;
+ }
+ else if (weight >= 600 && variable_font)
+ {
+ // If the font is heavy enough, consider it bold and avoid programmatic bolding
+ // even if it doesn't have the bold style set.
+ mStyle |= LLFontGL::BOLD;
+ }
if(mFTFace->style_flags & FT_STYLE_FLAG_ITALIC)
{
@@ -341,16 +373,10 @@ F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const
//llassert(!mIsFallback);
LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left, EFontGlyphType::Unspecified);;
- U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0;
// Kern this puppy.
LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right, EFontGlyphType::Unspecified);
- U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0;
- FT_Vector delta;
-
- llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta));
-
- return delta.x*(1.f/64.f);
+ return getXKerning(left_glyph_info, right_glyph_info);
}
F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const
@@ -363,9 +389,28 @@ F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LL
FT_Vector delta;
- llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta));
+ llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, FT_KERNING_UNFITTED, &delta));
- return delta.x*(1.f/64.f);
+ // Apply the FreeType auto-hinter's subpixel side-bearing correction between
+ // adjacent glyphs. When the hinter has shifted the right side of the left
+ // glyph or the left side of the right glyph, (rsb_delta - lsb_delta) is the
+ // sub-pixel nudge that keeps spacing visually even.
+ F32 delta_correction = 0.0f;
+ if (left_glyph_info && right_glyph_info)
+ {
+ // According to FreeType docs, these delta values should only trigger
+ // discrete ±1 pixel adjustments when they cross certain thresholds.
+ // Substructing delta_diff from delta.x doesn't work as well as treating
+ // it as a thresholds
+ S32 delta_diff = left_glyph_info->mRsbDelta - right_glyph_info->mLsbDelta;
+ if (delta_diff > 32)
+ delta_correction = -1.0f;
+ else if (delta_diff < -31)
+ delta_correction = 1.0f;
+ }
+
+ // ft_kerning_unfitted mode always returns 26.6 fixed-point values
+ return (F32)(delta.x * (1.f / 64.f)) + delta_correction;
}
bool LLFontFreetype::hasGlyph(llwchar wch) const
@@ -510,6 +555,11 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l
gi->mHeight = height;
gi->mXBearing = fontp->mFTFace->glyph->bitmap_left;
gi->mYBearing = fontp->mFTFace->glyph->bitmap_top;
+ // FreeType fills these when the glyph has been auto-hinted; they describe how
+ // much the hinter nudged the left/right side bearings (in 26.6 pixels). Keep
+ // them so inter-glyph spacing can be corrected in getXKerning().
+ gi->mLsbDelta = (S32)fontp->mFTFace->glyph->lsb_delta;
+ gi->mRsbDelta = (S32)fontp->mFTFace->glyph->rsb_delta;
// Convert these from 26.6 units to float pixels.
gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f;
gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f;
@@ -635,7 +685,7 @@ void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index, ll
if (mFTFace == nullptr)
return;
- FT_Int32 load_flags = FT_LOAD_FORCE_AUTOHINT;
+ FT_Int32 load_flags = (FT_Int32)mHinting;
if (EFontGlyphType::Color == bitmap_type)
{
// We may not actually get a color render so our caller should always examine mFTFace->glyph->bitmap.pixel_mode
@@ -678,7 +728,7 @@ void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index, ll
void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi)
{
resetBitmapCache();
- loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mIsFallback, 0);
+ loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mWeight, mIsFallback, 0, mHinting, mFontFlags);
if (!mIsFallback)
{
// This is the head of the list - need to rebuild ourself and all fallbacks.
@@ -846,6 +896,73 @@ void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32
}
}
+bool LLFontFreetype::setVariationAxis(const std::string& axis_tag, F32 value)
+{
+ if (!mFTFace)
+ return false;
+
+ // Check if this is a variable font
+ FT_MM_Var* master = nullptr;
+ if (FT_Get_MM_Var(mFTFace, &master) != 0)
+ {
+ // Not a variable font - this is not an error, just silently skip
+ return false;
+ }
+
+ // Find the axis by tag (e.g., "wght" for weight)
+ FT_UInt axis_index = 0;
+ bool found = false;
+ for (FT_UInt i = 0; i < master->num_axis; i++)
+ {
+ // Compare the 4-byte tag
+ if (master->axis[i].tag == FT_MAKE_TAG(axis_tag[0], axis_tag[1], axis_tag[2], axis_tag[3]))
+ {
+ axis_index = i;
+ found = true;
+
+ // Clamp value to valid range for this axis
+ F32 min_val = master->axis[i].minimum / 65536.0f;
+ F32 max_val = master->axis[i].maximum / 65536.0f;
+ value = llclamp(value, min_val, max_val);
+
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ FT_Done_MM_Var(gFTLibrary, master);
+ LL_WARNS_ONCE("Font") << "Axis '" << axis_tag << "' not found in font: " << mName << LL_ENDL;
+ return false;
+ }
+
+ FT_UInt num_coords = master->num_axis;
+ FT_Fixed* coords = new FT_Fixed[num_coords];
+
+ // Get current coordinates
+ FT_Get_Var_Design_Coordinates(mFTFace, num_coords, coords);
+
+ // Update the specific axis
+ coords[axis_index] = (FT_Fixed)(value * 65536.0f);
+
+ // Set all coordinates
+ int error = FT_Set_Var_Design_Coordinates(mFTFace, num_coords, coords);
+
+ delete[] coords;
+ FT_Done_MM_Var(gFTLibrary, master);
+
+ if (error != 0)
+ {
+ LL_WARNS() << "Failed to set variation coordinates for " << axis_tag
+ << " = " << value << " in font: " << mName << LL_ENDL;
+ return false;
+ }
+
+ LL_DEBUGS("Font") << "Set " << axis_tag << " = " << value
+ << " for font: " << mName << LL_ENDL;
+ return true;
+}
+
namespace ll
{
diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h
index f7600e40a3..d2164e8fa2 100644
--- a/indra/llrender/llfontfreetype.h
+++ b/indra/llrender/llfontfreetype.h
@@ -43,6 +43,7 @@ struct FT_FaceRec_;
typedef struct FT_FaceRec_* LLFT_Face;
struct FT_StreamRec_;
typedef struct FT_StreamRec_ LLFT_Stream;
+enum class EFontHinting : S32;
namespace ll
{
@@ -87,6 +88,8 @@ struct LLFontGlyphInfo
S32 mYBitmapOffset; // Offset to the origin in the bitmap
S32 mXBearing; // Distance from baseline to left in pixels
S32 mYBearing; // Distance from baseline to top in pixels
+ S32 mLsbDelta; // FreeType subpixel left side bearing delta (26.6 units)
+ S32 mRsbDelta; // FreeType subpixel right side bearing delta (26.6 units)
std::pair<EFontGlyphType, S32> mBitmapEntry; // Which bitmap in the bitmap cache contains this glyph
};
@@ -100,7 +103,7 @@ public:
// is_fallback should be true for fallback fonts that aren't used
// to render directly (Unicode backup, primarily)
- bool loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool is_fallback, S32 face_n);
+ bool loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags);
S32 getNumFaces(const std::string& filename);
@@ -162,9 +165,14 @@ private:
void resetBitmapCache();
void setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride = 0) const;
bool setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U16 height, const U8* data, U32 stride) const;
+ bool setVariationAxis(const std::string& axis_tag, F32 value);
bool hasGlyph(llwchar wch) const; // Has a glyph for this character
LLFontGlyphInfo* addGlyph(llwchar wch, EFontGlyphType glyph_type) const; // Add a new character to the font if necessary
- LLFontGlyphInfo* addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType bitmap_type) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found)
+ LLFontGlyphInfo* addGlyphFromFont(
+ const LLFontFreetype *fontp,
+ llwchar wch,
+ U32 glyph_index,
+ EFontGlyphType bitmap_type) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found)
void renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index, llwchar wch) const;
void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const;
@@ -180,6 +188,9 @@ private:
LLFT_Face mFTFace;
bool mIsFallback;
+ EFontHinting mHinting;
+ S32 mFontFlags;
+ S32 mWeight = -1;
typedef std::pair<LLPointer<LLFontFreetype>, char_functor_t> fallback_font_t;
typedef std::vector<fallback_font_t> fallback_font_vector_t;
fallback_font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars)
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 16eec1fdd2..5d99c35047 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -90,14 +90,14 @@ void LLFontGL::destroyGL()
mFontFreetype->destroyGL();
}
-bool LLFontGL::loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n)
+bool LLFontGL::loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags)
{
if(mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL))
{
mFontFreetype = new LLFontFreetype;
}
- return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, is_fallback, face_n);
+ return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, weight, is_fallback, face_n, hinting, flags);
}
S32 LLFontGL::getNumFaces(const std::string& filename)
@@ -1115,7 +1115,14 @@ LLFontGL* LLFontGL::getFontSansSerifSmallItalic()
//static
LLFontGL* LLFontGL::getFontSansSerif()
{
- static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Medium",0));
+ static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",0));
+ return fontp;
+}
+
+// static
+LLFontGL* LLFontGL::getFontSansSerifMedium()
+{
+ static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif", "Medium", 0));
return fontp;
}
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index 1c8e036f58..3b82d8e43d 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -87,7 +87,7 @@ public:
void destroyGL();
- bool loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n);
+ bool loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags);
S32 getNumFaces(const std::string& filename);
S32 getCacheGeneration() const;
@@ -204,6 +204,7 @@ public:
static LLFontGL* getFontSansSerifSmallBold();
static LLFontGL* getFontSansSerifSmallItalic();
static LLFontGL* getFontSansSerif();
+ static LLFontGL* getFontSansSerifMedium();
static LLFontGL* getFontSansSerifBig();
static LLFontGL* getFontSansSerifHuge();
static LLFontGL* getFontSansSerifBold();
diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp
index c48a389f6a..890308ab54 100644
--- a/indra/llrender/llfontregistry.cpp
+++ b/indra/llrender/llfontregistry.cpp
@@ -170,7 +170,7 @@ LLFontDescriptor LLFontDescriptor::normalize() const
if (new_size != s_template_string && new_size.empty() && findSubString(new_name,"Monospace"))
new_size = "Monospace";
if (new_size.empty())
- new_size = "Medium";
+ new_size = "Small";
if (removeSubString(new_name,"Bold"))
new_style |= LLFontGL::BOLD;
@@ -181,16 +181,16 @@ LLFontDescriptor LLFontDescriptor::normalize() const
return LLFontDescriptor(new_name,new_size,new_style, getFontFiles(), getFontCollectionFiles());
}
-void LLFontDescriptor::addFontFile(const std::string& file_name, const std::string& char_functor)
+void LLFontDescriptor::addFontFile(const std::string& file_name, EFontHinting hinting, S32 flags, F32 size_delta, S32 weight, const std::string& char_functor)
{
char_functor_map_t::const_iterator it = mCharFunctors.find(char_functor);
- mFontFiles.push_back(LLFontFileInfo(file_name, (mCharFunctors.end() != it) ? it->second : nullptr));
+ mFontFiles.push_back(LLFontFileInfo(file_name, hinting, flags, size_delta, weight, (mCharFunctors.end() != it) ? it->second : nullptr));
}
-void LLFontDescriptor::addFontCollectionFile(const std::string& file_name, const std::string& char_functor)
+void LLFontDescriptor::addFontCollectionFile(const std::string& file_name, EFontHinting hinting, S32 flags, F32 size_delta, S32 weight, const std::string& char_functor)
{
char_functor_map_t::const_iterator it = mCharFunctors.find(char_functor);
- mFontCollectionFiles.push_back(LLFontFileInfo(file_name, (mCharFunctors.end() != it) ? it->second : nullptr));
+ mFontCollectionFiles.push_back(LLFontFileInfo(file_name, hinting, flags, size_delta, weight, (mCharFunctors.end() != it) ? it->second : nullptr));
}
LLFontRegistry::LLFontRegistry(bool create_gl_textures)
@@ -289,23 +289,69 @@ bool font_desc_init_from_xml(LLXMLNodePtr node, LLFontDescriptor& desc)
{
std::string font_file_name = child->getTextContents();
std::string char_functor;
+ EFontHinting hinting = EFontHinting::FORCE_AUTOHINT;
+ S32 flags = 0;
+ S32 weight = -1;
if (child->hasAttribute("functor"))
{
child->getAttributeString("functor", char_functor);
}
+ if (child->hasAttribute("font_hinting"))
+ {
+ std::string attr_hinting;
+ child->getAttributeString("font_hinting", attr_hinting);
+ LLStringUtil::toLower(attr_hinting);
+
+ if (attr_hinting == "default")
+ {
+ hinting = EFontHinting::DEFAULT;
+ }
+ else if (attr_hinting == "force_auto")
+ {
+ hinting = EFontHinting::FORCE_AUTOHINT;
+ }
+ else if (attr_hinting == "no_hinting")
+ {
+ hinting = EFontHinting::NO_HINTING;
+ }
+ }
+
+ if (child->hasAttribute("flags"))
+ {
+ std::string attr_flags;
+ child->getAttributeString("flags", attr_flags);
+ LLStringUtil::toLower(attr_flags);
+
+ if (attr_flags == "bold")
+ {
+ flags |= LLFontGL::BOLD;
+ }
+ }
+
+ F32 size_delta = 0.f;
+ if (child->hasAttribute("size_delta"))
+ {
+ child->getAttributeF32("size_delta", size_delta);
+ }
+
+ if (child->hasAttribute("font_weight"))
+ {
+ child->getAttributeS32("font_weight", weight);
+ }
+
if (child->hasAttribute("load_collection"))
{
bool col = false;
child->getAttributeBOOL("load_collection", col);
if (col)
{
- desc.addFontCollectionFile(font_file_name, char_functor);
+ desc.addFontCollectionFile(font_file_name, hinting, flags, size_delta, weight, char_functor);
}
}
- desc.addFontFile(font_file_name, char_functor);
+ desc.addFontFile(font_file_name, hinting, flags, size_delta, weight, char_functor);
}
else if (child->hasName("os"))
{
@@ -462,7 +508,7 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
// Add ultimate fallback list - generated dynamically on linux,
// null elsewhere.
std::transform(getUltimateFallbackList().begin(), getUltimateFallbackList().end(), std::back_inserter(font_files),
- [](const std::string& file_name) { return LLFontFileInfo(file_name); });
+ [](const std::string& file_name) { return LLFontFileInfo(file_name, EFontHinting::FORCE_AUTOHINT, 0, 0.f, -1); });
// Load fonts based on names.
if (font_files.empty())
@@ -517,8 +563,8 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
{
fontp = new LLFontGL;
}
- if (fontp->loadFace(font_path, point_size_scale,
- LLFontGL::sVertDPI, LLFontGL::sHorizDPI, is_fallback, i))
+ if (fontp->loadFace(font_path, point_size_scale + font_file_it->mSizeDelta,
+ LLFontGL::sVertDPI, LLFontGL::sHorizDPI, font_file_it->mWeight, is_fallback, i, font_file_it->mHinting, font_file_it->mFlags))
{
is_font_loaded = true;
if (is_first_found)
diff --git a/indra/llrender/llfontregistry.h b/indra/llrender/llfontregistry.h
index 8bbf5aa30c..fcbb2667e4 100644
--- a/indra/llrender/llfontregistry.h
+++ b/indra/llrender/llfontregistry.h
@@ -34,22 +34,45 @@ class LLFontGL;
typedef std::vector<std::string> string_vec_t;
+enum class EFontHinting : S32
+{
+ DEFAULT = 0,
+ NO_HINTING = 0x8000U,
+ FORCE_AUTOHINT = 0x20,
+};
+
struct LLFontFileInfo
{
- LLFontFileInfo(const std::string& file_name, const std::function<bool(llwchar)>& char_functor = nullptr)
+ LLFontFileInfo(const std::string& file_name, EFontHinting hinting, S32 flags, F32 size_delta, S32 weight, const std::function<bool(llwchar)>& char_functor = nullptr)
: FileName(file_name)
, CharFunctor(char_functor)
+ , mHinting(hinting)
+ , mFlags(flags)
+ , mSizeDelta(size_delta)
+ , mWeight(weight)
{
}
- LLFontFileInfo(const LLFontFileInfo& ffi)
+ LLFontFileInfo(const LLFontFileInfo& ffi, EFontHinting hinting, S32 flags, F32 size_delta, S32 weight)
: FileName(ffi.FileName)
, CharFunctor(ffi.CharFunctor)
+ , mHinting(hinting)
+ , mFlags(flags)
+ , mSizeDelta(size_delta)
+ , mWeight(weight)
{
}
std::string FileName;
std::function<bool(llwchar)> CharFunctor;
+ EFontHinting mHinting;
+ S32 mFlags;
+ S32 mWeight; // -1 - default, whatever is in the file.
+
+ // Not all fonts are the same size, Ex: dejavu is bigger than inter,
+ // so in some cases we want to adjust relative sizes to make characters
+ // from different files match.
+ F32 mSizeDelta;
};
typedef std::vector<LLFontFileInfo> font_file_info_vec_t;
@@ -71,10 +94,10 @@ public:
const std::string& getSize() const { return mSize; }
void setSize(const std::string& size) { mSize = size; }
- void addFontFile(const std::string& file_name, const std::string& char_functor = LLStringUtil::null);
+ void addFontFile(const std::string& file_name, EFontHinting hinting, S32 flags, F32 size_delta, S32 weight, const std::string& char_functor = LLStringUtil::null);
const font_file_info_vec_t & getFontFiles() const { return mFontFiles; }
void setFontFiles(const font_file_info_vec_t& font_files) { mFontFiles = font_files; }
- void addFontCollectionFile(const std::string& file_name, const std::string& char_functor = LLStringUtil::null);
+ void addFontCollectionFile(const std::string& file_name, EFontHinting hinting, S32 flags, F32 size_delta, S32 weight, const std::string& char_functor = LLStringUtil::null);
const font_file_info_vec_t& getFontCollectionFiles() const { return mFontCollectionFiles; }
void setFontCollectionFiles(const font_file_info_vec_t& font_collection_files) { mFontCollectionFiles = font_collection_files; }
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 1a3a499b20..57be8570af 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -1774,64 +1774,25 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
return;
}
- LLVector4a vert(x, y, z);
- transform(vert);
- mVerticesp[mCount] = vert;
-
- mCount++;
- mVerticesp[mCount] = mVerticesp[mCount-1];
- mColorsp[mCount] = mColorsp[mCount-1];
- mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
-}
-
-void LLRender::transform(LLVector3& vert)
-{
- if (!mUIOffset.empty())
+ if (mUIOffset.empty())
{
- vert += LLVector3(mUIOffset.back().getF32ptr());
- vert *= LLVector3(mUIScale.back().getF32ptr());
+ mVerticesp[mCount].set(x,y,z);
}
-}
-
-void LLRender::transform(LLVector4a& vert)
-{
- if (!mUIOffset.empty())
+ else
{
+ LLVector4a vert(x, y, z);
vert.add(mUIOffset.back());
vert.mul(mUIScale.back());
+ mVerticesp[mCount] = vert;
}
-}
-
-void LLRender::untransform(LLVector3& vert)
-{
- if (!mUIOffset.empty())
- {
- vert /= LLVector3(mUIScale.back().getF32ptr());
- vert -= LLVector3(mUIOffset.back().getF32ptr());
- }
-}
-
-void LLRender::batchTransform(LLVector4a* verts, U32 vert_count)
-{
- if (!mUIOffset.empty())
- {
- const LLVector4a& offset = mUIOffset.back();
- const LLVector4a& scale = mUIScale.back();
-
- for (U32 i = 0; i < vert_count; ++i)
- {
- verts[i].add(offset);
- verts[i].mul(scale);
- }
- }
-}
-void LLRender::vertexBatchPreTransformed(const std::vector<LLVector4a>& verts)
-{
- vertexBatchPreTransformed(verts.data(), narrow(verts.size()));
+ mCount++;
+ mVerticesp[mCount] = mVerticesp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
}
-void LLRender::vertexBatchPreTransformed(const LLVector4a* verts, S32 vert_count)
+void LLRender::vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count)
{
if (mCount + vert_count > 4094)
{
@@ -1852,7 +1813,7 @@ void LLRender::vertexBatchPreTransformed(const LLVector4a* verts, S32 vert_count
mVerticesp[mCount] = mVerticesp[mCount-1];
}
-void LLRender::vertexBatchPreTransformed(const LLVector4a* verts, const LLVector2* uvs, S32 vert_count)
+void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 vert_count)
{
if (mCount + vert_count > 4094)
{
@@ -1876,7 +1837,7 @@ void LLRender::vertexBatchPreTransformed(const LLVector4a* verts, const LLVector
}
}
-void LLRender::vertexBatchPreTransformed(const LLVector4a* verts, const LLVector2* uvs, const LLColor4U* colors, S32 vert_count)
+void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, LLColor4U* colors, S32 vert_count)
{
if (mCount + vert_count > 4094)
{
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index be8539433c..0801c12fb4 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -450,16 +450,9 @@ public:
void diffuseColor4ubv(const U8* c);
void diffuseColor4ub(U8 r, U8 g, U8 b, U8 a);
- void transform(LLVector3& vert);
- void transform(LLVector4a& vert);
- void untransform(LLVector3& vert);
-
- void batchTransform(LLVector4a* verts, U32 vert_count);
-
- void vertexBatchPreTransformed(const std::vector<LLVector4a>& verts);
- void vertexBatchPreTransformed(const LLVector4a* verts, S32 vert_count);
- void vertexBatchPreTransformed(const LLVector4a* verts, const LLVector2* uvs, S32 vert_count);
- void vertexBatchPreTransformed(const LLVector4a* verts, const LLVector2* uvs, const LLColor4U*, S32 vert_count);
+ void vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count);
+ void vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 vert_count);
+ void vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, LLColor4U*, S32 vert_count);
void setColorMask(bool writeColor, bool writeAlpha);
void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha);
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index 828bfb289b..fa9de1eb09 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -39,7 +39,7 @@ static const std::string DD_BUTTON_NAME = "dd_button";
static const std::string DD_TEXTBOX_NAME = "dd_textbox";
static const std::string DD_HEADER_NAME = "dd_header";
-static const S32 HEADER_HEIGHT = 23;
+static const S32 HEADER_HEIGHT = 25;
static const S32 HEADER_IMAGE_LEFT_OFFSET = 5;
static const S32 HEADER_TEXT_LEFT_OFFSET = 30;
static const F32 AUTO_OPEN_TIME = 1.f;
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 0048c44189..7f209c60a7 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -85,6 +85,7 @@ LLButton::Params::Params()
image_top_pad("image_top_pad"),
image_bottom_pad("image_bottom_pad"),
imgoverlay_label_space("imgoverlay_label_space", 1),
+ image_overlay_right_delta("image_overlay_right_delta", 0),
label_color("label_color"),
label_color_selected("label_color_selected"), // requires is_toggle true
label_color_disabled("label_color_disabled"),
@@ -109,6 +110,8 @@ LLButton::Params::Params()
commit_on_capture_lost("commit_on_capture_lost", false),
display_pressed_state("display_pressed_state", true),
use_draw_context_alpha("use_draw_context_alpha", true),
+ draw_focus_border("draw_focus_border", true),
+ hover_hand_cursor("hover_hand_cursor", false),
badge("badge"),
handle_right_mouse("handle_right_mouse"),
held_down_delay("held_down_delay"),
@@ -158,6 +161,7 @@ LLButton::LLButton(const LLButton::Params& p)
mImageOverlayTopPad(p.image_top_pad),
mImageOverlayBottomPad(p.image_bottom_pad),
mImgOverlayLabelSpace(p.imgoverlay_label_space),
+ mImageOverlayRightDelta(p.image_overlay_right_delta),
mIsToggle(p.is_toggle),
mScaleImage(p.scale_image),
mDropShadowedText(p.label_shadow),
@@ -179,6 +183,8 @@ LLButton::LLButton(const LLButton::Params& p)
mMouseUpSignal(NULL),
mHeldDownSignal(NULL),
mUseDrawContextAlpha(p.use_draw_context_alpha),
+ mDrawFocusBorder(p.draw_focus_border),
+ mHoverHandCursor(p.hover_hand_cursor),
mHandleRightMouse(p.handle_right_mouse),
mFlashingTimer(NULL)
{
@@ -653,7 +659,7 @@ bool LLButton::handleHover(S32 x, S32 y, MASK mask)
}
// We only handle the click if the click both started and ended within us
- getWindow()->setCursor(UI_CURSOR_ARROW);
+ getWindow()->setCursor(mHoverHandCursor ? UI_CURSOR_HAND : UI_CURSOR_ARROW);
LL_DEBUGS("UserInput") << "hover handled by " << getName() << LL_ENDL;
}
return true;
@@ -840,10 +846,9 @@ void LLButton::draw()
label_color = ll::ui::SearchableControl::getHighlightFontColor();
// overlay with keyboard focus border
- if (hasFocus())
+ if (hasFocus() && mDrawFocusBorder)
{
- F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
- drawBorder(imagep, gFocusMgr.getFocusColor() % alpha, ll_round(lerp(1.f, 3.f, lerp_amt)));
+ drawBorder(imagep, gFocusMgr.getFocusColor() % alpha, gFocusMgr.getFocusFlashWidth());
}
if (use_glow_effect)
@@ -930,6 +935,17 @@ void LLButton::draw()
}
overlay_color.mV[VALPHA] *= alpha;
+ if (mImageOverlayRightDelta > 0)
+ {
+ mImageOverlay->draw(getRect().getWidth() - overlay_width - mImageOverlayRightDelta,
+ center_y - (overlay_height / 2),
+ overlay_width,
+ overlay_height,
+ overlay_color);
+ }
+ else
+ {
+
switch(mImageOverlayAlignment)
{
case LLFontGL::LEFT:
@@ -964,6 +980,7 @@ void LLButton::draw()
// draw nothing
break;
}
+ }
}
// Draw label
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index f530eceb4b..0d1a28ee31 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -110,6 +110,7 @@ public:
//image overlay paddings
Optional<S32> image_top_pad;
Optional<S32> image_bottom_pad;
+ Optional<S32> image_overlay_right_delta;
/**
* Space between image_overlay and label
@@ -132,7 +133,9 @@ public:
Optional<F32> hover_glow_amount;
Optional<TimeIntervalParam> held_down_delay;
- Optional<bool> use_draw_context_alpha;
+ Optional<bool> use_draw_context_alpha,
+ draw_focus_border,
+ hover_hand_cursor;
Optional<LLBadge::Params> badge;
@@ -366,12 +369,16 @@ protected:
S32 mImageOverlayBottomPad;
bool mUseDrawContextAlpha;
+ bool mDrawFocusBorder;
+ bool mHoverHandCursor;
/*
* Space between image_overlay and label
*/
S32 mImgOverlayLabelSpace;
+ S32 mImageOverlayRightDelta;
+
F32 mHoverGlowStrength;
F32 mCurGlowStrength;
diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp
index 91e6f281da..ca512a9883 100644
--- a/indra/llui/llconsole.cpp
+++ b/indra/llui/llconsole.cpp
@@ -67,6 +67,10 @@ LLConsole::LLConsole(const LLConsole::Params& p)
{
setFontSize(p.font_size_index);
}
+ if (mFont == nullptr)
+ {
+ setFontSize(0); // sans-serif
+ }
mFadeTime = mLinePersistTime - FADE_DURATION;
setMaxLines(LLUI::getInstance()->mSettingGroups["config"]->getS32("ConsoleMaxLines"));
}
@@ -79,6 +83,13 @@ void LLConsole::setLinePersistTime(F32 seconds)
void LLConsole::reshape(S32 width, S32 height, bool called_from_parent)
{
+ if (mFont == nullptr)
+ {
+ // not initialized yet
+ LL_WARNS() << "LLConsole::reshape called before font is set" << LL_ENDL;
+ return;
+ }
+
S32 new_width = llmax(50, llmin(getRect().getWidth(), width));
S32 new_height = llmax(mFont->getLineHeight() + 15, llmin(getRect().getHeight(), height));
diff --git a/indra/llui/lldraghandle.cpp b/indra/llui/lldraghandle.cpp
index 15536178ab..b3b47084c5 100644
--- a/indra/llui/lldraghandle.cpp
+++ b/indra/llui/lldraghandle.cpp
@@ -59,7 +59,9 @@ LLDragHandle::LLDragHandle(const LLDragHandle::Params& p)
mMaxTitleWidth( 0 ),
mForeground( true ),
mDragHighlightColor(p.drag_highlight_color()),
- mDragShadowColor(p.drag_shadow_color())
+ mDragShadowColor(p.drag_shadow_color()),
+ mFont(p.font),
+ mLabelVPad(p.label_vpad())
{
static LLUICachedControl<S32> snap_margin ("SnapMargin", 0);
@@ -98,14 +100,13 @@ void LLDragHandleTop::setTitle(const std::string& title)
}
else
{
- const LLFontGL* font = LLFontGL::getFontSansSerif();
LLTextBox::Params params;
params.name("Drag Handle Title");
params.rect(getRect());
params.initial_value(trimmed_title);
- params.font(font);
+ params.font(mFont);
params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT);
- params.font_shadow(LLFontGL::DROP_SHADOW_SOFT);
+ params.font_shadow(LLFontGL::NO_SHADOW);
params.use_ellipses = true;
params.parse_urls = false; //cancel URL replacement in floater title
mTitleBox = LLUICtrlFactory::create<LLTextBox> (params);
@@ -236,7 +237,6 @@ void LLDragHandleLeft::draw()
void LLDragHandleTop::reshapeTitleBox()
{
- static LLUICachedControl<S32> title_vpad("UIFloaterTitleVPad", 0);
if( ! mTitleBox)
{
return;
@@ -248,7 +248,7 @@ void LLDragHandleTop::reshapeTitleBox()
LLRect title_rect;
title_rect.setLeftTopAndSize(
LEFT_PAD,
- getRect().getHeight() - title_vpad,
+ getRect().getHeight() - mLabelVPad,
title_width,
title_height);
diff --git a/indra/llui/lldraghandle.h b/indra/llui/lldraghandle.h
index 73211d5292..f768839749 100644
--- a/indra/llui/lldraghandle.h
+++ b/indra/llui/lldraghandle.h
@@ -43,13 +43,17 @@ public:
: public LLInitParam::Block<Params, LLView::Params>
{
Optional<std::string> label;
+ Optional<S32> label_vpad;
Optional<LLUIColor> drag_highlight_color;
Optional<LLUIColor> drag_shadow_color;
+ Optional<const LLFontGL*> font;
Params()
: label("label"),
+ label_vpad("label_vpad", 7),
drag_highlight_color("drag_highlight_color", LLUIColorTable::instance().getColor("DefaultHighlightLight")),
- drag_shadow_color("drag_shadow_color", LLUIColorTable::instance().getColor("DefaultShadowDark"))
+ drag_shadow_color("drag_shadow_color", LLUIColorTable::instance().getColor("DefaultShadowDark")),
+ font("font", LLFontGL::getFontSansSerif())
{
changeDefault(mouse_opaque, true);
changeDefault(follows.flags, FOLLOWS_ALL);
@@ -82,6 +86,8 @@ protected:
protected:
LLTextBox* mTitleBox;
+ const LLFontGL* mFont;
+ S32 mLabelVPad;
private:
LLRect mButtonsRect;
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index c60253e7fe..9361358ced 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -183,8 +183,10 @@ LLFloater::Params::Params()
show_title("show_title", true),
auto_close("auto_close", false),
positioning("positioning", LLFloaterEnums::POSITIONING_RELATIVE),
+ header_font("header_font", LLFontGL::getFontSansSerif()),
header_height("header_height", 0),
legacy_header_height("legacy_header_height", 0),
+ header_vpad("header_vpad", 7),
close_image("close_image"),
restore_image("restore_image"),
minimize_image("minimize_image"),
@@ -293,7 +295,7 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
memset(mButtonsEnabled, 0, BUTTON_COUNT * sizeof(bool));
memset(mButtons, 0, BUTTON_COUNT * sizeof(LLButton*));
- addDragHandle();
+ addDragHandle(p);
addResizeCtrls();
initFromParams(p);
@@ -336,7 +338,7 @@ void LLFloater::initFloater(const Params& p)
}
}
-void LLFloater::addDragHandle()
+void LLFloater::addDragHandle(const LLFloater::Params& floater_params)
{
if (!mDragHandle)
{
@@ -346,6 +348,8 @@ void LLFloater::addDragHandle()
p.name("drag");
p.follows.flags(FOLLOWS_ALL);
p.label(mTitle);
+ p.font(floater_params.header_font);
+ p.label_vpad(floater_params.header_vpad);
mDragHandle = LLUICtrlFactory::create<LLDragHandleLeft>(p);
}
else // drag on top
@@ -354,6 +358,8 @@ void LLFloater::addDragHandle()
p.name("Drag Handle");
p.follows.flags(FOLLOWS_ALL);
p.label(mTitle);
+ p.font(floater_params.header_font);
+ p.label_vpad(floater_params.header_vpad);
mDragHandle = LLUICtrlFactory::create<LLDragHandleTop>(p);
}
addChild(mDragHandle);
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 9e1594bdd2..bda2531b43 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -172,8 +172,10 @@ public:
Optional<LLFloaterEnums::EOpenPositioning> positioning;
+ Optional<const LLFontGL*> header_font;
Optional<S32> header_height,
- legacy_header_height; // HACK see initFromXML()
+ legacy_header_height, // HACK see initFromXML()
+ header_vpad;
Optional<F32> rel_x,
rel_y;
@@ -442,7 +444,7 @@ private:
bool offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index);
void addResizeCtrls();
void layoutResizeCtrls();
- void addDragHandle();
+ void addDragHandle(const LLFloater::Params& p);
void layoutDragHandle(); // repair layout
static void updateActiveFloaterTransparency();
diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index 7544a44478..ce0e8036e7 100644
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -464,6 +464,11 @@ F32 LLFocusMgr::getFocusFlashAmt() const
return clamp_rescale(mFocusFlashTimer.getElapsedTimeF32(), 0.f, FOCUS_FADE_TIME, 1.f, 0.f);
}
+S32 LLFocusMgr::getFocusFlashWidth() const
+{
+ return ll_round(lerp(1.f, 2.f, getFocusFlashAmt()));
+}
+
LLColor4 LLFocusMgr::getFocusColor() const
{
static LLUIColor focus_color_cached = LLUIColorTable::instance().getColor("FocusColor");
diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h
index 89fee5c9f1..2e2293196b 100644
--- a/indra/llui/llfocusmgr.h
+++ b/indra/llui/llfocusmgr.h
@@ -101,7 +101,7 @@ public:
void setKeystrokesOnly(bool keystrokes_only) { mKeystrokesOnly = keystrokes_only; }
F32 getFocusFlashAmt() const;
- S32 getFocusFlashWidth() const { return ll_round(lerp(1.f, 3.f, getFocusFlashAmt())); }
+ S32 getFocusFlashWidth() const;
LLColor4 getFocusColor() const;
void triggerFocusFlash();
bool getAppHasFocus() const { return mAppHasFocus; }
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index dafbca7433..fcc1964bd6 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -159,9 +159,11 @@ LLFolderViewItem::Params::Params()
icon_width("icon_width", 0),
text_pad("text_pad", 0),
text_pad_right("text_pad_right", 0),
+ text_pad_top("text_pad_top", 1),
single_folder_mode("single_folder_mode", false),
double_click_override("double_click_override", false),
arrow_size("arrow_size", 0),
+ arrow_pad_top("arrow_pad_top", 1),
max_folder_item_overlap("max_folder_item_overlap", 0)
{ }
@@ -201,7 +203,9 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mIconWidth(p.icon_width),
mTextPad(p.text_pad),
mTextPadRight(p.text_pad_right),
+ mTextPadTop(p.text_pad_top),
mArrowSize(p.arrow_size),
+ mArrowPadTop(p.arrow_pad_top),
mSingleFolderMode(p.single_folder_mode),
mMaxFolderItemOverlap(p.max_folder_item_overlap),
mDoubleClickOverride(p.double_click_override)
@@ -811,7 +815,7 @@ void LLFolderViewItem::drawOpenFolderArrow()
if (hasVisibleChildren() || !isFolderComplete())
{
gl_draw_scaled_rotated_image(
- mIndentation, getRect().getHeight() - mArrowSize - mTextPad - sTopPad,
+ mIndentation, getRect().getHeight() - mArrowSize - mArrowPadTop - sTopPad,
mArrowSize, mArrowSize, mControlLabelRotation, sFolderArrowImg->getImage(), sFgColor);
}
}
@@ -1045,7 +1049,7 @@ void LLFolderViewItem::draw()
S32 filter_string_length = mViewModelItem->hasFilterStringMatch() ? (S32)mViewModelItem->getFilterStringSize() : 0;
F32 right_x = 0;
- F32 y = (F32)rect_height - line_height - (F32)mTextPad - (F32)sTopPad;
+ F32 y = (F32)rect_height - line_height - (F32)mTextPadTop - (F32)sTopPad;
F32 text_left = (F32)getLabelXPos();
LLWString combined_string = mLabel + mLabelSuffix;
@@ -1124,7 +1128,7 @@ void LLFolderViewItem::draw()
if(mLabelSuffix.empty() || (font == sSuffixFont))
{
F32 match_string_left = text_left + font->getWidthF32(combined_string.c_str(), 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string.c_str(), filter_offset, filter_string_length);
- F32 yy = (F32)rect_height - line_height - (F32)mTextPad - (F32)sTopPad;
+ F32 yy = (F32)rect_height - line_height - (F32)mTextPadTop - (F32)sTopPad;
font->render(combined_string, filter_offset, match_string_left, yy,
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
filter_string_length, S32_MAX, &right_x);
@@ -1135,7 +1139,7 @@ void LLFolderViewItem::draw()
if(label_filter_length > 0)
{
F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, filter_offset + label_filter_length) - font->getWidthF32(mLabel.c_str(), filter_offset, label_filter_length);
- F32 yy = (F32)rect_height - line_height - (F32)mTextPad - (F32)sTopPad;
+ F32 yy = (F32)rect_height - line_height - (F32)mTextPadTop - (F32)sTopPad;
font->render(mLabel, filter_offset, match_string_left, yy,
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
label_filter_length, S32_MAX, &right_x);
@@ -1146,7 +1150,7 @@ void LLFolderViewItem::draw()
{
S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size());
F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, static_cast<S32>(mLabel.size())) + sSuffixFont->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset + suffix_filter_length) - sSuffixFont->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length);
- F32 yy = (F32)rect_height - sSuffixFont->getLineHeight() - (F32)mTextPad - (F32)sTopPad;
+ F32 yy = (F32)rect_height - sSuffixFont->getLineHeight() - (F32)mTextPadTop - (F32)sTopPad;
sSuffixFont->render(mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor,
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
suffix_filter_length, S32_MAX, &right_x);
diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h
index 23d794bf26..258a806b91 100644
--- a/indra/llui/llfolderviewitem.h
+++ b/indra/llui/llfolderviewitem.h
@@ -73,7 +73,9 @@ public:
icon_width,
text_pad,
text_pad_right,
+ text_pad_top,
arrow_size,
+ arrow_pad_top,
max_folder_item_overlap;
Optional<bool> single_folder_mode,
double_click_override;
@@ -117,7 +119,9 @@ protected:
mIconWidth,
mTextPad,
mTextPadRight,
+ mTextPadTop,
mArrowSize,
+ mArrowPadTop,
mMaxFolderItemOverlap;
F32 mControlLabelRotation;
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index fe0591ce4b..1dc80671cc 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -48,17 +48,21 @@ static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layo
LLLayoutPanel::Params::Params()
: expanded_min_dim("expanded_min_dim", 0),
min_dim("min_dim", -1),
+ max_dim("max_dim", -1),
user_resize("user_resize", false),
auto_resize("auto_resize", true)
{
addSynonym(min_dim, "min_width");
addSynonym(min_dim, "min_height");
+ addSynonym(max_dim, "max_width");
+ addSynonym(max_dim, "max_height");
}
LLLayoutPanel::LLLayoutPanel(const Params& p)
: LLPanel(p),
mExpandedMinDim(p.expanded_min_dim.isProvided() ? p.expanded_min_dim : p.min_dim),
mMinDim(p.min_dim),
+ mMaxDim(p.max_dim),
mAutoResize(p.auto_resize),
mUserResize(p.user_resize),
mCollapsed(false),
@@ -75,6 +79,7 @@ LLLayoutPanel::LLLayoutPanel(const Params& p)
{
mVisibleAmt = 0.f;
}
+ setMaxDim(mMaxDim);
}
void LLLayoutPanel::initFromParams(const Params& p)
@@ -113,6 +118,8 @@ S32 LLLayoutPanel::getTargetDim() const
void LLLayoutPanel::setTargetDim(S32 value)
{
+ value = llmin(value, mMaxDim);
+
LLRect new_rect(getRect());
if (mOrientation == LLLayoutStack::HORIZONTAL)
{
@@ -145,6 +152,7 @@ void LLLayoutPanel::setOrientation( LLView::EOrientation orientation )
setMinDim(layout_dim);
}
mTargetDim = llmax(layout_dim, getMinDim());
+ mTargetDim = llmin(mTargetDim, mMaxDim);
}
void LLLayoutPanel::setVisible( bool visible )
@@ -167,6 +175,7 @@ void LLLayoutPanel::reshape( S32 width, S32 height, bool called_from_parent /*=
if (!mIgnoreReshape && !mAutoResize)
{
mTargetDim = (mOrientation == LLLayoutStack::HORIZONTAL) ? width : height;
+ mTargetDim = llmin(mTargetDim, mMaxDim);
LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent());
if (stackp)
{
@@ -439,6 +448,7 @@ void LLLayoutStack::updateLayout()
F32 fraction_to_distribute = (panelp->mFractionalSize * panelp->getAutoResizeFactor()) / (total_visible_fraction);
S32 delta = ll_round((F32)space_to_distribute * fraction_to_distribute);
panelp->mTargetDim += delta;
+ panelp->mTargetDim = llmin(panelp->mTargetDim, panelp->mMaxDim);
remaining_space -= delta;
}
}
@@ -455,6 +465,7 @@ void LLLayoutStack::updateLayout()
{
S32 space_for_panel = remaining_space > 0 ? 1 : -1;
panelp->mTargetDim += space_for_panel;
+ panelp->mTargetDim = llmin(panelp->mTargetDim, panelp->mMaxDim);
remaining_space -= space_for_panel;
}
}
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index 9e3536aaff..4c78c8a289 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -140,7 +140,8 @@ public:
struct Params : public LLInitParam::Block<Params, LLPanel::Params>
{
Optional<S32> expanded_min_dim,
- min_dim;
+ min_dim,
+ max_dim;
Optional<bool> user_resize,
auto_resize;
@@ -164,6 +165,8 @@ public:
S32 getMinDim() const { return llmax(0, mMinDim); }
void setMinDim(S32 value) { mMinDim = value; }
+ void setMaxDim(S32 value) { mMaxDim = value < 0 ? S32_MAX : value; }
+
S32 getExpandedMinDim() const { return mExpandedMinDim >= 0 ? mExpandedMinDim : getMinDim(); }
void setExpandedMinDim(S32 value) { mExpandedMinDim = value; }
@@ -198,6 +201,7 @@ protected:
S32 mExpandedMinDim;
S32 mMinDim;
+ S32 mMaxDim;
bool mCollapsed;
F32 mVisibleAmt;
F32 mCollapseAmt;
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 0eef842a30..404e394ace 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -97,6 +97,7 @@ LLLineEditor::Params::Params()
ignore_tab("ignore_tab", true),
is_password("is_password", false),
allow_emoji("allow_emoji", true),
+ draw_focus_border("draw_focus_border", true),
cursor_color("cursor_color"),
use_bg_color("use_bg_color", false),
bg_color("bg_color"),
@@ -147,6 +148,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mIgnoreTab( p.ignore_tab ),
mDrawAsterixes( p.is_password ),
mAllowEmoji( p.allow_emoji ),
+ mDrawFocusBorder(p.draw_focus_border),
mSpellCheck( p.spellcheck ),
mSpellCheckStart(-1),
mSpellCheckEnd(-1),
@@ -1796,7 +1798,7 @@ void LLLineEditor::drawBackground()
if (!image) return;
// optionally draw programmatic border
- if (has_focus)
+ if (has_focus && mDrawFocusBorder)
{
LLColor4 tmp_color = gFocusMgr.getFocusColor();
tmp_color.setAlpha(alpha);
@@ -1956,12 +1958,11 @@ void LLLineEditor::draw()
width = llmin(width, mTextRightEdge - ll_round(rendered_pixels_right));
gl_rect_2d(ll_round(rendered_pixels_right), cursor_top, ll_round(rendered_pixels_right)+width, cursor_bottom, color);
- LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha );
rendered_text += mFontBufferSelection.render(
mGLFont,
mText, mScrollHPos + rendered_text,
rendered_pixels_right, text_bottom,
- tmp_color,
+ LLColor4::black,
LLFontGL::LEFT, LLFontGL::BOTTOM,
0,
LLFontGL::NO_SHADOW,
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 6384bfdc5f..fd248edda3 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -95,7 +95,8 @@ public:
show_label_focused,
is_password,
allow_emoji,
- use_bg_color;
+ use_bg_color,
+ draw_focus_border;
// colors
Optional<LLUIColor> cursor_color,
@@ -411,6 +412,7 @@ protected:
bool mAllowEmoji;
bool mUseBgColor;
+ bool mDrawFocusBorder;
LLWString mPreeditWString;
LLWString mPreeditOverwrittenWString;
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 6ba31c251e..3b21ed8f47 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -73,7 +73,7 @@ S32 MENU_BAR_WIDTH = 410;
/// Local function declarations, constants, enums, and typedefs
///============================================================================
-const S32 LABEL_BOTTOM_PAD_PIXELS = 2;
+const S32 LABEL_BOTTOM_PAD_PIXELS = 1;
const U32 LEFT_PAD_PIXELS = 3;
const U32 LEFT_WIDTH_PIXELS = 15;
@@ -519,21 +519,25 @@ void LLMenuItemGL::draw( void )
}
else
{
+ // Munus are all of the same size, so fixed offset works here,
+ // but it won't work if somebody decides to use different font
+ // todo: adjust logic to work of rect and font height
+ F32 y = (F32)MENU_ITEM_PADDING / 2.f;
if( !mDrawBoolLabel.empty() )
{
- mFont->render( mDrawBoolLabel.getWString(), 0, (F32)LEFT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color,
+ mFont->render( mDrawBoolLabel.getWString(), 0, (F32)LEFT_PAD_PIXELS, y, color,
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, false );
}
- mFont->render( mLabel.getWString(), 0, (F32)LEFT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color,
+ mFont->render( mLabel.getWString(), 0, (F32)LEFT_PLAIN_PIXELS, y, color,
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, false );
if( !mDrawAccelLabel.empty() )
{
- mFont->render( mDrawAccelLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color,
+ mFont->render( mDrawAccelLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PLAIN_PIXELS, y, color,
LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, false );
}
if( !mDrawBranchLabel.empty() )
{
- mFont->render( mDrawBranchLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f), color,
+ mFont->render( mDrawBranchLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PAD_PIXELS, y, color,
LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, false );
}
}
@@ -1638,6 +1642,9 @@ void LLMenuItemBranchDownGL::draw( void )
{
color = mDisabledColor.get();
}
+ // Munus are all of the same size, so fixed offset works here,
+ // but it won't work if somebody decides to use different font
+ // todo: adjust logic to work of rect and font height
getFont()->render( mLabel.getWString(), 0, (F32)getRect().getWidth() / 2.f, (F32)LABEL_BOTTOM_PAD_PIXELS, color,
LLFontGL::HCENTER, LLFontGL::BOTTOM, LLFontGL::NORMAL);
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 48e42d9fc0..27f1dcb03d 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -483,7 +483,7 @@ void LLTabContainer::draw()
tuple->mButton->setVisible( true );
}
- S32 max_scroll_visible = getTabCount() - getMaxScrollPos() + getScrollPos();
+ S32 max_scroll_visible = getVisibleTabCount() - getMaxScrollPos() + getScrollPos();
S32 idx = 0;
for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
{
@@ -1380,6 +1380,20 @@ S32 LLTabContainer::getTabCount() const
return static_cast<S32>(mTabList.size());
}
+S32 LLTabContainer::getVisibleTabCount() const
+{
+ S32 visible_count = 0;
+ for (tuple_list_t::const_iterator itr = mTabList.begin(); itr != mTabList.end(); ++itr)
+ {
+ const LLTabTuple* pTT = *itr;
+ if (pTT->mVisible)
+ {
+ visible_count++;
+ }
+ }
+ return visible_count;
+}
+
LLPanel* LLTabContainer::getPanelByIndex(S32 index) const
{
if (index >= 0 && index < (S32)mTabList.size())
@@ -2109,6 +2123,14 @@ void LLTabContainer::updateMaxScrollPos()
S32 tab_space = 0;
S32 available_space = 0;
tab_space = mTotalTabWidth;
+ for(tuple_list_t::const_iterator tab_it = mTabList.begin(); tab_it != mTabList.end(); ++tab_it)
+ {
+ const LLTabTuple* tuple = *tab_it;
+ if (!tuple->mVisible)
+ {
+ tab_space -= tuple->mButton->getRect().getWidth();
+ }
+ }
available_space = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_tab_h_pad);
if( tab_space > available_space )
@@ -2118,7 +2140,7 @@ void LLTabContainer::updateMaxScrollPos()
available_width_with_arrows -= tabcntr_tab_partial_width;
S32 running_tab_width = 0;
- setMaxScrollPos(getTabCount());
+ setMaxScrollPos(getVisibleTabCount());
for(tuple_list_t::reverse_iterator tab_it = mTabList.rbegin(); tab_it != mTabList.rend(); ++tab_it)
{
running_tab_width += (*tab_it)->mButton->getRect().getWidth();
@@ -2129,7 +2151,7 @@ void LLTabContainer::updateMaxScrollPos()
setMaxScrollPos(getMaxScrollPos()-1);
}
// in case last tab doesn't actually fit on screen, make it the last scrolling position
- setMaxScrollPos(llmin(getMaxScrollPos(), getTabCount() - 1));
+ setMaxScrollPos(llmin(getMaxScrollPos(), getVisibleTabCount() - 1));
no_scroll = false;
}
}
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index cbf56dc653..3095e641f8 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -188,6 +188,7 @@ public:
LLPanel* getCurrentPanel();
S32 getCurrentPanelIndex() const;
S32 getTabCount() const;
+ S32 getVisibleTabCount() const;
LLPanel* getPanelByIndex(S32 index) const;
S32 getIndexForPanel(LLPanel* panel) const;
S32 getPanelIndexByTitle(std::string_view title) const;
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 7565dafea8..802367720f 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -51,6 +51,9 @@ const F32 CURSOR_FLASH_DELAY = 1.0f; // in seconds
const S32 CURSOR_THICKNESS = 2;
const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click.
+constexpr F32 FOCUSED_SELECTION_BG_ALPHA = 1;
+constexpr F32 UNFOCUSED_SELECTION_BG_ALPHA = 0.7f;
+
LLTextBase::line_info::line_info(S32 index_start, S32 index_end, LLRect rect, S32 line_num)
: mDocIndexStart(index_start),
mDocIndexEnd(index_end),
@@ -530,7 +533,7 @@ void LLTextBase::drawSelectionBackground()
// Draw the selection box (we're using a box instead of reversing the colors on the selected text).
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
const LLColor4& color = mSelectedBGColor;
- F32 alpha = hasFocus() ? 0.7f : 0.3f;
+ F32 alpha = hasFocus() ? FOCUSED_SELECTION_BG_ALPHA : UNFOCUSED_SELECTION_BG_ALPHA;
alpha *= getDrawContext().mAlpha;
LLColor4 selection_color(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], alpha);
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 9206b3facf..bc39d9732c 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -409,6 +409,7 @@ public:
/*virtual*/ void setColor(const LLUIColor& c) override;
virtual void setReadOnlyColor(const LLUIColor& c);
/*virtual*/ void onVisibilityChange(bool new_visibility) override;
+ void setBgReadOnlyColor(const LLUIColor& c) { mReadOnlyBgColor = c; }
/*virtual*/ void setValue(const LLSD& value) override;
/*virtual*/ LLTextViewModel* getViewModel() const override;
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 05461edd82..9a27049d37 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -80,7 +80,7 @@ LLUICtrl::Params::Params()
mouseenter_callback("mouseenter_callback"),
mouseleave_callback("mouseleave_callback"),
control_name("control_name"),
- font("font", LLFontGL::getFontEmojiMedium()),
+ font("font", LLFontGL::getFontEmojiSmall()),
font_halign("halign"),
font_valign("valign"),
length("length"), // ignore LLXMLNode cruft
diff --git a/indra/llui/llviewborder.cpp b/indra/llui/llviewborder.cpp
index d53fd6eb91..68ca61681c 100644
--- a/indra/llui/llviewborder.cpp
+++ b/indra/llui/llviewborder.cpp
@@ -149,7 +149,7 @@ void LLViewBorder::drawOnePixelLines()
top_color = gFocusMgr.getFocusColor();
bottom_color = top_color;
- LLUI::setLineWidth(lerp(1.f, 3.f, gFocusMgr.getFocusFlashAmt()));
+ LLUI::setLineWidth(lerp(1.f, 2.f, gFocusMgr.getFocusFlashAmt()));
}
S32 left = 0;
diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp
index 39cecbda25..a286f75f42 100644
--- a/indra/llwebrtc/llwebrtc.cpp
+++ b/indra/llwebrtc/llwebrtc.cpp
@@ -811,6 +811,8 @@ LLWebRTCPeerConnectionImpl::LLWebRTCPeerConnectionImpl() :
mPeerConnection(nullptr),
mMute(MUTE_INITIAL),
mAnswerReceived(false),
+ mPeerConnectionState(webrtc::PeerConnectionInterface::PeerConnectionState::kNew),
+ mDisconnectCount(0),
mPendingJobs(0)
{
}
@@ -1237,11 +1239,15 @@ void LLWebRTCPeerConnectionImpl::OnIceGatheringChange(webrtc::PeerConnectionInte
}
}
+static const webrtc::TimeDelta DISCONNECT_RENEGOTIATE_DELAY = webrtc::TimeDelta::Millis(10000);
+
// Called any time the PeerConnectionState changes.
void LLWebRTCPeerConnectionImpl::OnConnectionChange(webrtc::PeerConnectionInterface::PeerConnectionState new_state)
{
RTC_LOG(LS_ERROR) << __FUNCTION__ << " Peer Connection State Change " << new_state;
+ mPeerConnectionState = new_state;
+
switch (new_state)
{
case webrtc::PeerConnectionInterface::PeerConnectionState::kConnected:
@@ -1257,13 +1263,32 @@ void LLWebRTCPeerConnectionImpl::OnConnectionChange(webrtc::PeerConnectionInterf
break;
}
case webrtc::PeerConnectionInterface::PeerConnectionState::kFailed:
- case webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected:
{
for (auto &observer : mSignalingObserverList)
{
observer->OnRenegotiationNeeded();
}
-
+ break;
+ }
+ case webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected:
+ {
+ // Wait 10 seconds before renegotiating in case the connection recovers on its own.
+ // Use a sequence count so that only the most recent disconnect transition can trigger
+ // a renegotiation, avoiding stale delayed tasks from earlier disconnect/reconnect cycles.
+ uint32_t disconnect_count = ++mDisconnectCount;
+ mWebRTCImpl->PostDelayedSignalingTask(
+ [this, disconnect_count]()
+ {
+ if (disconnect_count == mDisconnectCount
+ && mPeerConnectionState == webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected)
+ {
+ for (auto &observer : mSignalingObserverList)
+ {
+ observer->OnRenegotiationNeeded();
+ }
+ }
+ },
+ DISCONNECT_RENEGOTIATE_DELAY);
break;
}
default:
@@ -1536,6 +1561,57 @@ void LLWebRTCPeerConnectionImpl::unsetDataObserver(LLWebRTCDataObserver* observe
}
}
+class LLStatsCollectorCallback : public webrtc::RTCStatsCollectorCallback
+{
+public:
+ typedef std::function<void(const LLWebRTCStatsMap&)> StatsCallback;
+
+ LLStatsCollectorCallback(StatsCallback callback) : callback_(callback) {}
+
+ void OnStatsDelivered(const webrtc::scoped_refptr<const webrtc::RTCStatsReport>& report) override
+ {
+ if (callback_)
+ {
+ // Transform RTCStatsReport stats to simple map
+ LLWebRTCStatsMap stats_map;
+ for (const auto& stats : *report)
+ {
+ std::map<std::string, std::string> stat_attributes;
+
+ // Convert each attribute to string format
+ for (const auto& attribute : stats.Attributes())
+ {
+ stat_attributes[attribute.name()] = attribute.ToString();
+ }
+ stats_map[stats.id()] = stat_attributes;
+ }
+ callback_(stats_map);
+ }
+ }
+
+private:
+ StatsCallback callback_;
+};
+
+void LLWebRTCPeerConnectionImpl::gatherConnectionStats()
+{
+ if (!mPeerConnection)
+ {
+ return;
+ }
+
+ auto stats_callback = webrtc::make_ref_counted<LLStatsCollectorCallback>(
+ [this](const LLWebRTCStatsMap& generic_stats)
+ {
+ for (auto& observer : mSignalingObserverList)
+ {
+ observer->OnStatsDelivered(generic_stats);
+ }
+ });
+
+ mPeerConnection->GetStats(stats_callback.get());
+}
+
LLWebRTCImpl * gWebRTCImpl = nullptr;
LLWebRTCDeviceInterface * getDeviceInterface()
{
diff --git a/indra/llwebrtc/llwebrtc.h b/indra/llwebrtc/llwebrtc.h
index 7d06b7d2b4..e76e708f0c 100644
--- a/indra/llwebrtc/llwebrtc.h
+++ b/indra/llwebrtc/llwebrtc.h
@@ -38,6 +38,7 @@
#ifndef LLWEBRTC_H
#define LLWEBRTC_H
+#include <map>
#include <string>
#include <vector>
@@ -55,6 +56,7 @@
namespace llwebrtc
{
+typedef std::map<std::string, std::map<std::string, std::string>> LLWebRTCStatsMap;
class LLWebRTCLogCallback
{
@@ -240,6 +242,8 @@ class LLWebRTCSignalingObserver
// Called when the data channel has been established and data
// transfer can begin.
virtual void OnDataChannelReady(LLWebRTCDataInterface *data_interface) = 0;
+
+ virtual void OnStatsDelivered(const LLWebRTCStatsMap& stats_data) {}
};
// LLWebRTCPeerConnectionInterface representsd a connection to a peer,
@@ -273,6 +277,8 @@ class LLWebRTCPeerConnectionInterface
virtual void unsetSignalingObserver(LLWebRTCSignalingObserver* observer) = 0;
virtual void AnswerAvailable(const std::string &sdp) = 0;
+
+ virtual void gatherConnectionStats() = 0;
};
// The following define the dynamic linked library
diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h
index 01cfb17ced..bd7a2e0bcf 100644
--- a/indra/llwebrtc/llwebrtc_impl.h
+++ b/indra/llwebrtc/llwebrtc_impl.h
@@ -343,6 +343,7 @@ public:
inner_->InitRecording();
inner_->StartRecording();
}
+ inner_->InitPlayout();
inner_->StartPlayout();
}
}
@@ -479,6 +480,13 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceO
mSignalingThread->PostTask(std::move(task), location);
}
+ void PostDelayedSignalingTask(absl::AnyInvocable<void() &&> task,
+ webrtc::TimeDelta delay,
+ const webrtc::Location& location = webrtc::Location::Current())
+ {
+ mSignalingThread->PostDelayedTask(std::move(task), delay, location);
+ }
+
void PostNetworkTask(absl::AnyInvocable<void() &&> task,
const webrtc::Location& location = webrtc::Location::Current())
{
@@ -648,6 +656,8 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface,
void enableSenderTracks(bool enable);
void enableReceiverTracks(bool enable);
+ void gatherConnectionStats() override;
+
protected:
LLWebRTCImpl * mWebRTCImpl;
@@ -673,6 +683,10 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface,
std::vector<LLWebRTCDataObserver *> mDataObserverList;
webrtc::scoped_refptr<webrtc::DataChannelInterface> mDataChannel;
+ // connection state tracking for delayed renegotiation on disconnect
+ webrtc::PeerConnectionInterface::PeerConnectionState mPeerConnectionState;
+ uint32_t mDisconnectCount;
+
std::atomic<int> mPendingJobs;
};
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp
index 34643d5f5c..5a37167f18 100644
--- a/indra/llxml/llcontrol.cpp
+++ b/indra/llxml/llcontrol.cpp
@@ -37,6 +37,7 @@
#include "llstring.h"
#include "v3math.h"
#include "v3dmath.h"
+#include "v4math.h"
#include "v4coloru.h"
#include "v4color.h"
#include "v3color.h"
@@ -63,6 +64,7 @@ template <> eControlType get_control_type<std::string>();
template <> eControlType get_control_type<LLVector3>();
template <> eControlType get_control_type<LLVector3d>();
+template <> eControlType get_control_type<LLVector4>();
template <> eControlType get_control_type<LLRect>();
template <> eControlType get_control_type<LLColor4>();
template <> eControlType get_control_type<LLColor3>();
@@ -72,6 +74,7 @@ template <> eControlType get_control_type<LLSD>();
template <> LLSD convert_to_llsd<U32>(const U32& in);
template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in);
template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in);
+template <> LLSD convert_to_llsd<LLVector4>(const LLVector4& in);
template <> LLSD convert_to_llsd<LLRect>(const LLRect& in);
template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in);
template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in);
@@ -85,6 +88,7 @@ template <> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlT
template <> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, std::string_view control_name);
template <> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, std::string_view control_name);
template <> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std::string_view control_name);
+template <> LLVector4 convert_from_llsd<LLVector4>(const LLSD& sd, eControlType type, std::string_view control_name);
template <> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, std::string_view control_name);
template <> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, std::string_view control_name);
template <> LLColor4U convert_from_llsd<LLColor4U>(const LLSD& sd, eControlType type, std::string_view control_name);
@@ -124,6 +128,9 @@ bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b)
case TYPE_VEC3D:
result = LLVector3d(a) == LLVector3d(b);
break;
+ case TYPE_VEC4:
+ result = LLVector4(a) == LLVector4(b);
+ break;
case TYPE_QUAT:
result = LLQuaternion(a) == LLQuaternion(b);
break;
@@ -373,6 +380,7 @@ const std::string LLControlGroup::mTypeString[TYPE_COUNT] = { "U32"
,"Rect"
,"Color4"
,"Color3"
+ ,"Vector4"
,"LLSD"
};
@@ -532,6 +540,11 @@ LLControlVariable* LLControlGroup::declareVec3d(const std::string& name, const L
return declareControl(name, TYPE_VEC3D, initial_val.getValue(), comment, persist);
}
+LLControlVariable* LLControlGroup::declareVec4(const std::string& name, const LLVector4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist)
+{
+ return declareControl(name, TYPE_VEC4, initial_val.getValue(), comment, persist);
+}
+
LLControlVariable* LLControlGroup::declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist)
{
return declareControl(name, TYPE_QUAT, initial_val.getValue(), comment, persist);
@@ -614,6 +627,11 @@ LLVector3d LLControlGroup::getVector3d(std::string_view name)
return get<LLVector3d>(name);
}
+LLVector4 LLControlGroup::getVector4(std::string_view name)
+{
+ return get<LLVector4>(name);
+}
+
LLQuaternion LLControlGroup::getQuaternion(std::string_view name)
{
return get<LLQuaternion>(name);
@@ -714,6 +732,11 @@ void LLControlGroup::setVector3d(std::string_view name, const LLVector3d &val)
set(name, val);
}
+void LLControlGroup::setVector4(std::string_view name, const LLVector4 &val)
+{
+ set(name, val);
+}
+
void LLControlGroup::setQuaternion(std::string_view name, const LLQuaternion &val)
{
set(name, val);
@@ -1262,6 +1285,11 @@ template <> eControlType get_control_type<LLVector3d>()
return TYPE_VEC3D;
}
+template <> eControlType get_control_type<LLVector4>()
+{
+ return TYPE_VEC4;
+}
+
template <> eControlType get_control_type<LLQuaternion>()
{
return TYPE_QUAT;
@@ -1302,6 +1330,11 @@ template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in)
{
return in.getValue();
}
+template <> LLSD convert_to_llsd<LLVector4>(const LLVector4& in)
+{
+ return in.getValue();
+}
+
template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& in)
{
return in.getValue();
@@ -1419,6 +1452,18 @@ LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std:
}
template<>
+LLVector4 convert_from_llsd<LLVector4>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ if (type == TYPE_VEC4)
+ return LLVector4(sd);
+ else
+ {
+ CONTROL_ERRS << "Invalid LLVector4 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
+ return LLVector4();
+ }
+}
+
+template<>
LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, std::string_view control_name)
{
if (type == TYPE_QUAT)
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index ad283c89b1..c2a7c22bbc 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -43,6 +43,7 @@
class LLVector3;
class LLVector3d;
+class LLVector4;
class LLQuaternion;
class LLColor4;
class LLColor3;
@@ -61,6 +62,7 @@ typedef enum e_control_type
TYPE_RECT,
TYPE_COL4,
TYPE_COL3,
+ TYPE_VEC4,
TYPE_LLSD,
TYPE_COUNT
} eControlType;
@@ -196,6 +198,7 @@ public:
LLControlVariable* declareString(const std::string& name, const std::string &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareVec3(const std::string& name, const LLVector3 &initial_val,const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
+ LLControlVariable* declareVec4(const std::string& name, const LLVector4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
@@ -212,6 +215,7 @@ public:
LLWString getWString(std::string_view name);
LLVector3 getVector3(std::string_view name);
LLVector3d getVector3d(std::string_view name);
+ LLVector4 getVector4(std::string_view name);
LLRect getRect(std::string_view name);
LLSD getLLSD(std::string_view name);
LLQuaternion getQuaternion(std::string_view name);
@@ -250,6 +254,7 @@ public:
void setString(std::string_view name, const std::string& val);
void setVector3(std::string_view name, const LLVector3 &val);
void setVector3d(std::string_view name, const LLVector3d &val);
+ void setVector4(std::string_view name, const LLVector4 &val);
void setQuaternion(std::string_view name, const LLQuaternion &val);
void setRect(std::string_view name, const LLRect &val);
void setColor4(std::string_view name, const LLColor4 &val);
@@ -416,6 +421,7 @@ template <> eControlType get_control_type<bool>();
template <> eControlType get_control_type<std::string>();
template <> eControlType get_control_type<LLVector3>();
template <> eControlType get_control_type<LLVector3d>();
+template <> eControlType get_control_type<LLVector4>();
template <> eControlType get_control_type<LLQuaternion>();
template <> eControlType get_control_type<LLRect>();
template <> eControlType get_control_type<LLColor4>();
@@ -425,6 +431,7 @@ template <> eControlType get_control_type<LLSD>();
template <> LLSD convert_to_llsd<U32>(const U32& in);
template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in);
template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in);
+template <> LLSD convert_to_llsd<LLVector4>(const LLVector4& in);
template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& in);
template <> LLSD convert_to_llsd<LLRect>(const LLRect& in);
template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in);
@@ -434,6 +441,7 @@ template<> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlTy
template<> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std::string_view control_name);
+template<> LLVector4 convert_from_llsd<LLVector4>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, std::string_view control_name);
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index d2b679ee3c..18a40bcf1e 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -416,6 +416,7 @@ set(viewer_SOURCE_FILES
llfloaterimnearbychat.cpp
llfloaterimnearbychathandler.cpp
llfloaterimnearbychatlistener.cpp
+ llnearbyvoicemoderation.cpp
llnetmap.cpp
llnotificationalerthandler.cpp
llnotificationgrouphandler.cpp
@@ -722,7 +723,6 @@ set(viewer_SOURCE_FILES
llvoicechannel.cpp
llvoiceclient.cpp
llvoicevisualizer.cpp
- llvoicevivox.cpp
llvoicewebrtc.cpp
llvoinventorylistener.cpp
llvopartgroup.cpp
@@ -1093,6 +1093,7 @@ set(viewer_HEADER_FILES
llnameeditor.h
llnamelistctrl.h
llnavigationbar.h
+ llnearbyvoicemoderation.h
llnetmap.h
llnotificationhandler.h
llnotificationlistitem.h
@@ -1394,7 +1395,6 @@ set(viewer_HEADER_FILES
llvoicechannel.h
llvoiceclient.h
llvoicevisualizer.h
- llvoicevivox.h
llvoicewebrtc.h
llvoinventorylistener.h
llvopartgroup.h
@@ -1783,9 +1783,7 @@ if (WINDOWS)
${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg
${SHARED_LIB_STAGING_DIR}/openjp2.dll
${SHARED_LIB_STAGING_DIR}/llwebrtc.dll
- #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/SLVoice.exe
#${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/libsndfile-1.dll
- #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/vivoxoal.dll
${AUTOBUILD_INSTALL_DIR}/ca-bundle.crt
${CMAKE_CURRENT_SOURCE_DIR}/licenses-win32.txt
${CMAKE_CURRENT_SOURCE_DIR}/featuretable.txt
@@ -1796,18 +1794,6 @@ if (WINDOWS)
media_plugin_example
)
- if (ADDRESS_SIZE EQUAL 64)
- list(APPEND COPY_INPUT_DEPENDENCIES
- ${SHARED_LIB_STAGING_DIR}/vivoxsdk_x64.dll
- ${SHARED_LIB_STAGING_DIR}/ortp_x64.dll
- )
- else (ADDRESS_SIZE EQUAL 64)
- list(APPEND COPY_INPUT_DEPENDENCIES
- ${SHARED_LIB_STAGING_DIR}/vivoxsdk.dll
- ${SHARED_LIB_STAGING_DIR}/ortp.dll
- )
- endif (ADDRESS_SIZE EQUAL 64)
-
if (TARGET ll::discord_sdk)
list(APPEND COPY_INPUT_DEPENDENCIES
${SHARED_LIB_STAGING_DIR}/discord_partner_sdk.dll
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 124b7a2cd0..c4697fd566 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-26.1.1
+26.3.0
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 5327e5b5eb..ccaa12b8ef 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -5872,6 +5872,17 @@
<key>Value</key>
<integer>90</integer>
</map>
+ <key>ScriptToastButtonWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Default width of buttons in the Script dialog toast.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>110</integer>
+ </map>
<key>NotificationChannelRightMargin</key>
<map>
<key>Comment</key>
@@ -6103,6 +6114,39 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>OpenDebugStatVoice</key>
+ <map>
+ <key>Comment</key>
+ <string>Expand Voice (WebRTC) stats display</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>OpenDebugStatVoiceOutgoing</key>
+ <map>
+ <key>Comment</key>
+ <string>Expand Outgoing audio (Voice) stats display</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>OpenDebugStatVoiceIncoming</key>
+ <map>
+ <key>Comment</key>
+ <string>Expand Incoming audio (Voice) stats display</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>OutBandwidth</key>
<map>
<key>Comment</key>
@@ -11118,6 +11162,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>ShowBlockedConvHistory</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies whether blocked agents will be shown in Call Log</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>ShowMatureEvents</key>
<map>
<key>Comment</key>
@@ -11794,6 +11849,22 @@
<key>Value</key>
<real>20.0</real>
</map>
+ <key>TextureChannelPriority</key>
+ <map>
+ <key>Comment</key>
+ <string>Per-channel texture streaming aggressiveness. X=normals, Y=diffuse, Z=specular/metallic, W=emissive. 1.0=baseline, higher=more aggressive downrez.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector4</string>
+ <key>Value</key>
+ <array>
+ <real>5</real>
+ <real>7.5</real>
+ <real>20</real>
+ <real>7.5</real>
+ </array>
+ </map>
<key>TextureCameraBoost</key>
<map>
<key>Comment</key>
@@ -12294,17 +12365,6 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>UIFloaterTitleVPad</key>
- <map>
- <key>Comment</key>
- <string>Distance from top of floater to top of title string, pixels</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>7</real>
- </map>
<key>UIImgDefaultEyesUUID</key>
<map>
<key>Comment</key>
@@ -13482,141 +13542,8 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>VivoxAutoPostCrashDumps</key>
- <map>
- <key>Comment</key>
- <string>If true, SLVoice will automatically send crash dumps directly to Vivox.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>VivoxDebugLevel</key>
- <map>
- <key>Comment</key>
- <string>Logging level to use when launching the vivox daemon</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>0</string>
- </map>
- <key>VivoxLogDirectory</key>
- <map>
- <key>Comment</key>
- <string>Default log path is Application Support/SecondLife/logs specify alternate absolute path here.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>VivoxShutdownTimeout</key>
- <map>
- <key>Comment</key>
- <string>shutdown timeout in miliseconds. The amount of time to wait for the service to shutdown gracefully after the last disconnect</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>5</string>
- </map>
- <key>VivoxDebugSIPURIHostName</key>
- <map>
- <key>Comment</key>
- <string>Hostname portion of vivox SIP URIs (empty string for the default).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>VivoxDebugVoiceAccountServerURI</key>
- <map>
- <key>Comment</key>
- <string>URI to the vivox account management server (empty string for the default).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>VivoxVoiceHost</key>
- <map>
- <key>Comment</key>
- <string>Client SLVoice host to connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>127.0.0.1</string>
- </map>
- <key>VivoxVoicePort</key>
- <map>
- <key>Comment</key>
- <string>Client SLVoice port to connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>44125</integer>
- </map>
-
- <key>VivoxVadAuto</key>
- <map>
- <key>Comment</key>
- <string>A flag indicating if the automatic VAD is enabled (1) or disabled (0). The individual settings are ignored if the auto-mode is enabled</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VivoxVadHangover</key>
- <map>
- <key>Comment</key>
- <string>The time (in milliseconds) that it takes or the VAD to switch back to silence from speech mode after the last speech frame has been detected</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>2000</integer>
- </map>
- <key>VivoxVadNoiseFloor</key>
- <map>
- <key>Comment</key>
- <string>A dimensionless value between 0 and 20000 (default 576) that controls the maximum level at which the noise floor may be set at by the VAD's noise tracking</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>576</integer>
- </map>
- <key>VivoxVadSensitivity</key>
- <map>
- <key>Comment</key>
- <string>A dimensionless value between 0 and 100, indicating the 'sensitivity of the VAD'. Increasing this value corresponds to decreasing the sensitivity of the VAD and 0 is turned off altogether</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VoiceCallsFriendsOnly</key>
- <!-- deprecated (see SL-12871) -->
+ <key>VoiceCallsFriendsOnly</key>
+ <!-- deprecated (see SL-12871) -->
<map>
<key>Comment</key>
<string>(Deprecated) Only accept voice calls from residents on your friends list</string>
@@ -13693,17 +13620,6 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>VoiceHost</key>
- <map>
- <key>Comment</key>
- <string>Client SLVoice host to connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>127.0.0.1</string>
- </map>
<key>VoiceImageLevel0</key>
<map>
<key>Comment</key>
@@ -13792,17 +13708,6 @@
<key>Value</key>
<string>Default</string>
</map>
- <key>VoiceLogFile</key>
- <map>
- <key>Comment</key>
- <string>Log file to use when launching the voice daemon</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
<key>VoiceOutputAudioDevice</key>
<map>
<key>Comment</key>
@@ -13825,17 +13730,6 @@
<key>Value</key>
<integer>10</integer>
</map>
- <key>VoicePort</key>
- <map>
- <key>Comment</key>
- <string>Client SLVoice port to connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>44125</integer>
- </map>
<key>VoiceEchoCancellation</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 07ed0d0824..cf12be91c3 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -865,9 +865,6 @@ Delete "$INSTDIR\trial\*.html"
Delete "$INSTDIR\newview.exe"
Delete "$INSTDIR\SecondLife.exe"
-# MAINT-3099 workaround - prevent these log files, if present, from causing a user alert
-Delete "$INSTDIR\VivoxVoiceService-*.log"
-
# Remove entire help directory
RMDir /r "$INSTDIR\help"
diff --git a/indra/newview/licenses-linux.txt b/indra/newview/licenses-linux.txt
index c4286e970f..8a410d22a3 100644
--- a/indra/newview/licenses-linux.txt
+++ b/indra/newview/licenses-linux.txt
@@ -643,7 +643,6 @@ Audio coding: Polycom(R) Siren14TM (ITU-T Rec. G.722.1 Annex C)
Open Source Software Licensing
Each open source software component utilized by this product is subject to its own copyright and licensing terms, as listed below.
-
*************************************************************
*************************************************************
@@ -810,9 +809,7 @@ From Vivox:
40 Speen Street Suite 402
Framingham, MA 01701
-==============
DejaVu Fonts
-==============
MIT License
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
@@ -854,9 +851,7 @@ dealings in this Font Software without prior written authorization
from Tavmjong Bah. For further information, contact: tavmjong @ free
. fr.
-==============
Twemoji Fonts
-==============
MIT License
Applies to "EmojiOne SVGinOT Font" code only
@@ -880,9 +875,7 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.
-==============
WebRTC
-==============
Copyright (c) 2011, The WebRTC project authors. All rights reserved.
@@ -914,9 +907,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-==============
Google fonts
-==============
SIL OPEN FONT LICENSE Version 1.1
Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter)
diff --git a/indra/newview/licenses-mac.txt b/indra/newview/licenses-mac.txt
index 0a98fbd591..c2f52e3b90 100644
--- a/indra/newview/licenses-mac.txt
+++ b/indra/newview/licenses-mac.txt
@@ -516,184 +516,6 @@ supporting the PNG file format in commercial products. If you use this
source code in a product, acknowledgment is not required but would be
appreciated.
-=================
-Vivox SDK License
-=================
-
-RSA Data Security, Inc. MD5 Message-Digest Algorithm
-
-Audio coding: Polycom(R) Siren14TM (ITU-T Rec. G.722.1 Annex C)
-
-Open Source Software Licensing
-Each open source software component utilized by this product is subject to its own copyright and licensing terms, as listed below.
-
-
-*************************************************************
-*************************************************************
-
-/**
- * OpenAL cross platform audio library
- * Copyright (C) 1999-2000 by authors.
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- * Or go to http://www.gnu.org/copyleft/lgpl.html
- */
-
-*************************************************************
-*************************************************************
-RTP code under Lesser General Public License
-
-/*
- The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-************************************************************
-*************************************************************
-
-/*
- * The Vovida Software License, Version 1.0
- *
- * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The names "VOCAL", "Vovida Open Communication Application Library",
- * and "Vovida Open Communication Application Library (VOCAL)" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact vocal@vovida.org.
- *
- * 4. Products derived from this software may not be called "VOCAL", nor
- * may "VOCAL" appear in their name, without prior written
- * permission of Vovida Networks, Inc.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
- * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
- * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
- * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- *
- * This software consists of voluntary contributions made by Vovida
- * Networks, Inc. and many individuals on behalf of Vovida Networks,
- * Inc. For more information on Vovida Networks, Inc., please see
- *
- *
- */
-*************************************************************
-*************************************************************
-
-Internet Software Consortium code
-
-/* This is from the BIND 4.9.4 release, modified to compile by itself */
-/* Copyright (c) 1996 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
- * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
- * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
-
-*************************************************************
-
-*************************************************************
-
-************************************************************
-
-http://tinyxpath.sourceforge.net/
-
-TinyXPath is covered by the zlib license :
-
- www.sourceforge.net/projects/tinyxpath
- Copyright (c) 2002-2006 Yves Berquin (yvesb@users.sourceforge.net)
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any
- damages arising from the use of this software.
-
- Permission is granted to anyone to use this software for any
- purpose, including commercial applications, and to alter it and
- redistribute it freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must
- not claim that you wrote the original software. If you use this
- software in a product, an acknowledgment in the product documentation
- would be appreciated but is not required.
-
- 2. Altered source versions must be plainly marked as such, and
- must not be misrepresented as being the original software.
-
- 3. This notice may not be removed or altered from any source distribution.
-
-
-************************************************************
-************************************************************
-
-THE FREE SOFTWARE FOUNDATION
-
-Any customer may request the source code for all open source portions of this product which are covered by the Free Software Foundation's General Public License (GPL), for a period of three years from purchase. Please contact the vendor from whom you obtained this product for instructions. A fee equivalent to the cost of making the code available may be charged. Alternatively, customers may choose to download desired GPL components directly from their original vendors. Specifically, this product contains the following GPL-licensed components:
-
-
-From Vivox:
- - Assorted software components. To request source, contact Vivox at:
- Vivox, Inc.
- Attn: customer support
- 40 Speen Street Suite 402
- Framingham, MA 01701
-
=============
meshoptimizer
diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt
index 7219c0c9af..2d4bd8a4b6 100644
--- a/indra/newview/licenses-win32.txt
+++ b/indra/newview/licenses-win32.txt
@@ -558,184 +558,6 @@ supporting the PNG file format in commercial products. If you use this
source code in a product, acknowledgment is not required but would be
appreciated.
-=================
-Vivox SDK License
-=================
-
-RSA Data Security, Inc. MD5 Message-Digest Algorithm
-
-Audio coding: Polycom(R) Siren14TM (ITU-T Rec. G.722.1 Annex C)
-
-Open Source Software Licensing
-Each open source software component utilized by this product is subject to its own copyright and licensing terms, as listed below.
-
-
-*************************************************************
-*************************************************************
-
-/**
- * OpenAL cross platform audio library
- * Copyright (C) 1999-2000 by authors.
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- * Or go to http://www.gnu.org/copyleft/lgpl.html
- */
-
-*************************************************************
-*************************************************************
-RTP code under Lesser General Public License
-
-/*
- The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-************************************************************
-*************************************************************
-
-/*
- * The Vovida Software License, Version 1.0
- *
- * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The names "VOCAL", "Vovida Open Communication Application Library",
- * and "Vovida Open Communication Application Library (VOCAL)" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact vocal@vovida.org.
- *
- * 4. Products derived from this software may not be called "VOCAL", nor
- * may "VOCAL" appear in their name, without prior written
- * permission of Vovida Networks, Inc.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
- * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
- * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
- * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- *
- * This software consists of voluntary contributions made by Vovida
- * Networks, Inc. and many individuals on behalf of Vovida Networks,
- * Inc. For more information on Vovida Networks, Inc., please see
- *
- *
- */
-*************************************************************
-*************************************************************
-
-Internet Software Consortium code
-
-/* This is from the BIND 4.9.4 release, modified to compile by itself */
-/* Copyright (c) 1996 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
- * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
- * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
-
-*************************************************************
-
-*************************************************************
-
-************************************************************
-
-http://tinyxpath.sourceforge.net/
-
-TinyXPath is covered by the zlib license :
-
- www.sourceforge.net/projects/tinyxpath
- Copyright (c) 2002-2006 Yves Berquin (yvesb@users.sourceforge.net)
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any
- damages arising from the use of this software.
-
- Permission is granted to anyone to use this software for any
- purpose, including commercial applications, and to alter it and
- redistribute it freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must
- not claim that you wrote the original software. If you use this
- software in a product, an acknowledgment in the product documentation
- would be appreciated but is not required.
-
- 2. Altered source versions must be plainly marked as such, and
- must not be misrepresented as being the original software.
-
- 3. This notice may not be removed or altered from any source distribution.
-
-
-************************************************************
-************************************************************
-
-THE FREE SOFTWARE FOUNDATION
-
-Any customer may request the source code for all open source portions of this product which are covered by the Free Software Foundation's General Public License (GPL), for a period of three years from purchase. Please contact the vendor from whom you obtained this product for instructions. A fee equivalent to the cost of making the code available may be charged. Alternatively, customers may choose to download desired GPL components directly from their original vendors. Specifically, this product contains the following GPL-licensed components:
-
-
-From Vivox:
- - Assorted software components. To request source, contact Vivox at:
- Vivox, Inc.
- Attn: customer support
- 40 Speen Street Suite 402
- Framingham, MA 01701
-
========================
google-perftools license
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 098a345a9c..79752d2315 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3103,7 +3103,6 @@ bool LLAppViewer::initConfiguration()
{
// This is the second instance of SL. Mute voice,
// but make sure the setting is *not* persisted.
- // Also see LLVivoxVoiceClient::voiceEnabled()
LLControlVariable* enable_voice = gSavedSettings.getControl("EnableVoiceChat");
if (enable_voice)
{
@@ -4200,6 +4199,12 @@ void LLAppViewer::processMarkerFiles()
LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL;
}
LLAPRFile::remove(error_marker_file);
+ if (LLAPRFile::isExist(watchdog_marker_file, NULL, LL_APR_RB))
+ {
+ // If viewer crashed after a freeze was detected,
+ // crash still takes precendence. Just clear watchdog.
+ removeWatchdogMarker();
+ }
}
else
{
@@ -4725,13 +4730,66 @@ void LLAppViewer::purgeCefStaleCaches()
LL_PROFILE_ZONE_SCOPED;
// TODO: we really shouldn't use a hard coded name for the cache folder here...
const std::string browser_parent_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "cef_cache");
- if (LLFile::isdir(browser_parent_cache))
+ if (!LLFile::isdir(browser_parent_cache))
+ {
+ return;
+ }
+ // We are using a fixed name to not leave stale folders
+ // around in case something goes wrong on startup.
+ const std::string holder_cache_name = browser_parent_cache + "_rename";
+
+ // Try to rename the entire directory first
+ if (LLFile::rename(browser_parent_cache, holder_cache_name) == 0)
+ {
+ LL_DEBUGS("AppInit") << "Successfully renamed CEF cache folder for deletion" << LL_ENDL;
+ }
+ else
+ {
+ // Rename failed (likely another instance has files open in the cache)
+ // Create holder folder and move individual subfolders instead
+ LL_DEBUGS("AppInit") << "Could not rename CEF cache folder (may be in use), moving individual folders" << LL_ENDL;
+
+ if (!LLFile::isdir(holder_cache_name) && LLFile::mkdir(holder_cache_name) != 0)
+ {
+ LL_WARNS() << "Failed to create holder folder: " << holder_cache_name << LL_ENDL;
+ // Attept normal cleanup
+ gDirUtilp->deleteDirAndContents(browser_parent_cache);
+ return;
+ }
+
+ // Iterate through subdirectories in the cache folder
+ LLDirIterator dir_iter(browser_parent_cache, "*");
+ std::string subfolder_name;
+ while (dir_iter.next(subfolder_name))
+ {
+ if (subfolder_name == "." || subfolder_name == "..")
+ {
+ continue;
+ }
+
+ std::string source_path = browser_parent_cache + gDirUtilp->getDirDelimiter() + subfolder_name;
+ std::string dest_path = holder_cache_name + gDirUtilp->getDirDelimiter() + subfolder_name;
+
+ // If folder is in use, move will fail, don't delete it.
+ LLFile::rename(source_path, dest_path);
+ }
+ }
+
+ // Post deletion task to the General work queue to avoid blocking the main thread
+ if (auto queue = LL::WorkQueue::getInstance("General"))
+ {
+ // Alternatively throw it at LLPurgeDiskCacheThread to clean
+ // it during periodic purges.
+ queue->post([holder_cache_name]()
+ {
+ LL_PROFILE_ZONE_NAMED("cef_cache_cleanup");
+ gDirUtilp->deleteDirAndContents(holder_cache_name);
+ });
+ }
+ else
{
- // This is a sledgehammer approach - nukes the cef_cache dir entirely
- // which is then recreated the first time a CEF instance creates an
- // individual cache folder. If we ever decide to retain some folders
- // e.g. Search UI cache - then we will need a more granular approach.
- gDirUtilp->deleteDirAndContents(browser_parent_cache);
+ LL_WARNS() << "Failed to get General work queue, deleting CEF cache synchronously" << LL_ENDL;
+ gDirUtilp->deleteDirAndContents(holder_cache_name);
}
}
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 4e443ee189..5184b0f025 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -447,22 +447,8 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
// commands and exit the process before we do anything else.
if (!velopack_initialize())
{
+ // Obsolete? Always return true
// Velopack handled the invocation (install/uninstall hook)
-
- // Drop install related settings
- gDirUtilp->initAppDirs("SecondLife");
-
- std::string user_settings_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml");
- LLControlGroup settings("global");
- if (settings.loadFromFile(user_settings_path))
- {
- // If user reinstalls or updates, we want to recheck for nsis leftovers.
- if (settings.controlExists("PreviousInstallChecked"))
- {
- settings.setBOOL("PreviousInstallChecked", false);
- }
- settings.saveToFile(user_settings_path, true);
- }
return 0;
}
#endif
diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp
index 97d2345778..ce236dec66 100644
--- a/indra/newview/llcolorswatch.cpp
+++ b/indra/newview/llcolorswatch.cpp
@@ -200,13 +200,14 @@ void LLColorSwatchCtrl::draw()
F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
mBorder->setKeyboardFocusHighlight(hasFocus());
- // Draw border
- LLRect border( 0, getRect().getHeight(), getRect().getWidth(), mLabelHeight );
- gl_rect_2d( border, mBorderColor.get(), false );
- LLRect interior = border;
+ LLRect gl_border(0, getRect().getHeight(), getRect().getWidth(), mLabelHeight);
+ LLColor4 gl_border_color = mBorderColor.get();
+ LLRect interior = gl_border;
interior.stretch( -1 );
+ bool show_border_ctrl = true;
+
// Check state
if ( mValid )
{
@@ -239,7 +240,9 @@ void LLColorSwatchCtrl::draw()
{
if (mFallbackImage.notNull())
{
- mFallbackImage->draw(interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), LLColor4::white % alpha);
+ mFallbackImage->draw(interior.mLeft - 1, interior.mBottom - 1, mFallbackImage->getWidth(), mFallbackImage->getHeight(), LLColor4::white % alpha);
+ gl_border_color = LLUIColorTable::instance().getColor("ColorSwatchBorderColorGray").get();
+ show_border_ctrl = false;
}
else
{
@@ -250,6 +253,11 @@ void LLColorSwatchCtrl::draw()
}
}
+ mBorder->setVisible(show_border_ctrl);
+
+ // Draw border
+ gl_rect_2d(gl_border, gl_border_color, false);
+
LLUICtrl::draw();
}
diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp
index 65863f0a5e..e9c6df3ed8 100644
--- a/indra/newview/llconversationloglist.cpp
+++ b/indra/newview/llconversationloglist.cpp
@@ -45,6 +45,7 @@ LLConversationLogList::LLConversationLogList(const Params& p)
mIsDirty(true)
{
LLConversationLog::instance().addObserver(this);
+ LLMuteList::instance().addObserver(this);
// Set up context menu.
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
@@ -65,6 +66,15 @@ LLConversationLogList::LLConversationLogList(const Params& p)
}
mIsFriendsOnTop = gSavedSettings.getBOOL("SortFriendsFirst");
+ LLControlVariable* cntrl_ptr = gSavedSettings.getControl("ShowBlockedConvHistory");
+ if (cntrl_ptr)
+ {
+ mShowBlockedSignal = cntrl_ptr->getCommitSignal()->connect(
+ [this](LLControlVariable* control, const LLSD& value, const LLSD& previous)
+ {
+ setDirty(true);
+ });
+ }
}
LLConversationLogList::~LLConversationLogList()
@@ -74,6 +84,7 @@ LLConversationLogList::~LLConversationLogList()
mContextMenu.get()->die();
}
+ LLMuteList::getInstance()->removeObserver(this);
LLConversationLog::instance().removeObserver(this);
}
@@ -178,6 +189,44 @@ void LLConversationLogList::changed(const LLUUID& session_id, U32 mask)
}
}
+// inherited from LLMuteListObserver
+void LLConversationLogList::onChange()
+{
+}
+
+// inherited from LLMuteListObserver
+void LLConversationLogList::onChangeDetailed(const LLMute& mute)
+{
+ if (isDirty())
+ {
+ // Going to refresh either way.
+ return;
+ }
+
+ static LLCachedControl<bool> show_blocked(gSavedSettings, "ShowBlockedConvHistory", false);
+ if (!show_blocked())
+ {
+ // Check if any conversation in the log has this participant
+ const std::vector<LLConversation>& conversations = LLConversationLog::instance().getConversations();
+
+ // Note sure if actually need this update. List can be rather large
+ // and rebuilding it on every event can be expensive.
+ // But 'mute' events are also rare, so maybe not a problem.
+ // There also might be a way to react only to relevant changes,
+ // instead of reacting to everything, like ignoring voice only mutes,
+ // which are not relevant for this log by themselves.
+ for (const LLConversation& conversation : conversations)
+ {
+ if (conversation.getParticipantID() == mute.mID)
+ {
+ setDirty(true);
+ break;
+ }
+ }
+ }
+ // else don't need to hide anything
+}
+
void LLConversationLogList::addNewItem(const LLConversation* conversation)
{
LLConversationLogListItem* item = new LLConversationLogListItem(&*conversation);
@@ -207,6 +256,9 @@ void LLConversationLogList::rebuildList()
const std::vector<LLConversation>& conversations = log_instance.getConversations();
std::vector<LLConversation>::const_iterator iter = conversations.begin();
+ LLMuteList* mutes = LLMuteList::getInstance();
+
+ static LLCachedControl<bool> show_blocked(gSavedSettings, "ShowBlockedConvHistory", false);
for (; iter != conversations.end(); ++iter)
{
@@ -214,6 +266,11 @@ void LLConversationLogList::rebuildList()
if (not_found)
continue;
+ if (!show_blocked() && mutes->isMuted(iter->getParticipantID()))
+ {
+ continue;
+ }
+
addNewItem(&*iter);
}
@@ -517,8 +574,8 @@ bool LLConversationLogListNameComparator::doCompare(const LLConversationLogListI
LLStringUtil::toUpper(name1);
LLStringUtil::toUpper(name2);
- bool friends_first = gSavedSettings.getBOOL("SortFriendsFirst");
- if (friends_first && (LLAvatarActions::isFriend(id1) ^ LLAvatarActions::isFriend(id2)))
+ static LLCachedControl<bool> sort_friends_first(gSavedSettings, "SortFriendsFirst", true);
+ if (sort_friends_first() && (LLAvatarActions::isFriend(id1) ^ LLAvatarActions::isFriend(id2)))
{
return LLAvatarActions::isFriend(id1);
}
@@ -533,8 +590,8 @@ bool LLConversationLogListDateComparator::doCompare(const LLConversationLogListI
const LLUUID& id1 = conversation1->getConversation()->getParticipantID();
const LLUUID& id2 = conversation2->getConversation()->getParticipantID();
- bool friends_first = gSavedSettings.getBOOL("SortFriendsFirst");
- if (friends_first && (LLAvatarActions::isFriend(id1) ^ LLAvatarActions::isFriend(id2)))
+ static LLCachedControl<bool> sort_friends_first(gSavedSettings, "SortFriendsFirst", true);
+ if (sort_friends_first() && (LLAvatarActions::isFriend(id1) ^ LLAvatarActions::isFriend(id2)))
{
return LLAvatarActions::isFriend(id1);
}
diff --git a/indra/newview/llconversationloglist.h b/indra/newview/llconversationloglist.h
index 6372f6c9a3..39f129c9f1 100644
--- a/indra/newview/llconversationloglist.h
+++ b/indra/newview/llconversationloglist.h
@@ -39,7 +39,7 @@ class LLConversationLogListItem;
* it's always in actual state.
*/
-class LLConversationLogList: public LLFlatListViewEx, public LLConversationLogObserver
+class LLConversationLogList: public LLFlatListViewEx, public LLConversationLogObserver, public LLMuteListObserver
{
LOG_CLASS(LLConversationLogList);
public:
@@ -76,6 +76,12 @@ public:
virtual void changed();
virtual void changed(const LLUUID& session_id, U32 mask);
+ /**
+ * Changes from LLMuteListObserver
+ */
+ virtual void onChange();
+ virtual void onChangeDetailed(const LLMute& mute);
+
private:
void setDirty(bool dirty = true) { mIsDirty = dirty; }
@@ -104,6 +110,8 @@ private:
bool mIsDirty;
bool mIsFriendsOnTop;
std::string mNameFilter;
+
+ boost::signals2::scoped_connection mShowBlockedSignal;
};
/**
diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp
index a18fdf74c1..836ff63429 100644
--- a/indra/newview/lleventpoll.cpp
+++ b/indra/newview/lleventpoll.cpp
@@ -73,9 +73,9 @@ namespace Details
// We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error.
// This means we attempt to recover relatively quickly but back off giving more time to recover
// until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts.
- constexpr F32 EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout.
- constexpr F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout.
- constexpr S32 MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules.
+ constexpr F32 EVENT_POLL_ERROR_RETRY_SECONDS = 1.f;
+ constexpr F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC = 3.f;
+ constexpr S32 MAX_EVENT_POLL_ERRORS = 15; // ~5 minutes, by the above rules.
constexpr F64 MIN_SECONDS_PASSED = 10.0; // Minimum time we expect the server to hold the request.
int LLEventPollImpl::sNextCounter = 1;
@@ -238,23 +238,26 @@ namespace Details
}
else if (!status.isHttpStatus())
{
- /// Some LLCore or LIBCurl error was returned. This is unlikely to be recoverable
- LL_WARNS("LLEventPollImpl") << "<" << counter << "> Critical error from poll request returned from libraries. Canceling coroutine." << LL_ENDL;
- break;
+ // Some LLCore or LIBCurl error was returned.
+ LL_WARNS("LLEventPollImpl") << "<" << counter << "> Error from poll request returned from libraries. " << status.toTerseString() << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS("LLEventPollImpl") << "<" << counter << "> Error result from LLCoreHttpUtil::HttpCoroHandler. Code "
+ << status.toTerseString() << ": '" << httpResults["message"] << "'" << LL_ENDL;
}
- LL_WARNS("LLEventPollImpl") << "<" << counter << "> Error result from LLCoreHttpUtil::HttpCoroHandler. Code "
- << status.toTerseString() << ": '" << httpResults["message"] << "'" << LL_ENDL;
- if (errorCount < MAX_EVENT_POLL_HTTP_ERRORS)
+ if (errorCount < MAX_EVENT_POLL_ERRORS)
{ // An unanticipated error has been received from our poll
// request. Calculate a timeout and wait for it to expire(sleep)
- // before trying again. The sleep time is increased by 5 seconds
+ // before trying again. The sleep time is increased by 3 seconds
// for each consecutive error.
- ++errorCount;
F32 waitToRetry = EVENT_POLL_ERROR_RETRY_SECONDS
+ errorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC;
+ ++errorCount;
+
LL_WARNS("LLEventPollImpl") << "<" << counter << "> Retrying in " << waitToRetry <<
" seconds, error count is now " << errorCount << LL_ENDL;
diff --git a/indra/newview/llfilepicker_mac.mm b/indra/newview/llfilepicker_mac.mm
index 7262d18483..99e93bafbf 100644
--- a/indra/newview/llfilepicker_mac.mm
+++ b/indra/newview/llfilepicker_mac.mm
@@ -245,8 +245,8 @@ void doSaveDialogModeless(const std::string* file,
NSURL *last_url = [[NSUserDefaults standardUserDefaults] URLForKey:@"NSNavLastRootDirectory"];
if(!last_url)
{
- NSURL *documents_url = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask].firstObject;
- [panel setDirectoryURL:documents_url];
+ NSURL *downloads_url = [[NSFileManager defaultManager] URLsForDirectory:NSDownloadsDirectory inDomains:NSUserDomainMask].firstObject;
+ [panel setDirectoryURL:downloads_url];
}
[panel beginWithCompletionHandler:^(NSModalResponse result)
diff --git a/indra/newview/llfloaterconversationlog.cpp b/indra/newview/llfloaterconversationlog.cpp
index 97399c9cf7..40e2d2bf1e 100644
--- a/indra/newview/llfloaterconversationlog.cpp
+++ b/indra/newview/llfloaterconversationlog.cpp
@@ -100,6 +100,10 @@ void LLFloaterConversationLog::onCustomAction (const LLSD& userdata)
{
mConversationLogList->toggleSortFriendsOnTop();
}
+ else if ("show_blocked" == command_name)
+ {
+ gSavedSettings.setBOOL("ShowBlockedConvHistory", !gSavedSettings.getBOOL("ShowBlockedConvHistory"));
+ }
else if ("view_nearby_chat_history" == command_name)
{
LLFloaterReg::showInstance("preview_conversation", LLSD(LLUUID::null), true);
@@ -129,6 +133,10 @@ bool LLFloaterConversationLog::isActionChecked(const LLSD& userdata)
{
return gSavedSettings.getBOOL("SortFriendsFirst");
}
+ else if ("show_blocked" == command_name)
+ {
+ return gSavedSettings.getBOOL("ShowBlockedConvHistory");
+ }
return false;
}
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 10c56bdb46..c2a9008420 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -57,6 +57,8 @@
#include "llsdserialize.h"
#include "llviewermenu.h" // is_agent_mappable
#include "llviewerobjectlist.h"
+#include "llvoavatar.h"
+#include "llnearbyvoicemoderation.h"
const S32 EVENTS_PER_IDLE_LOOP_CURRENT_SESSION = 80;
@@ -90,6 +92,7 @@ LLFloaterIMContainer::LLFloaterIMContainer(const LLSD& seed, const Params& param
mAutoResize = false;
LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::IM, this);
+ LLNearbyVoiceModeration::getInstance();
}
LLFloaterIMContainer::~LLFloaterIMContainer()
@@ -538,6 +541,33 @@ void LLFloaterIMContainer::idleUpdate()
mGeneralTitleInUse = !needs_override;
setTitle(needs_override ? conversation_floaterp->getTitle() : mGeneralTitle);
}
+ const LLConversationItem* nearby_session = getSessionModel(LLUUID());
+ if (nearby_session)
+ {
+ LLSpeakerMgr* speaker_mgr = (LLSpeakerMgr*)(LLLocalSpeakerMgr::getInstance());
+
+ LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = nearby_session->getChildrenBegin();
+ LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = nearby_session->getChildrenEnd();
+ while (current_participant_model != end_participant_model)
+ {
+ LLConversationItemParticipant* participant_model =
+ dynamic_cast<LLConversationItemParticipant*>((*current_participant_model).get());
+ if (participant_model)
+ {
+ bool show_moderator_options = LLNearbyVoiceModeration::getInstance()->isNearbyChatModerator();
+ LLUUID participant_id = participant_model->getUUID();
+ if (participant_id != gAgentID)
+ {
+ // Don't show moderator options if participant is not connected to the same spatial channel
+ LLSpeaker* speakerp = speaker_mgr->findSpeaker(participant_id).get();
+ show_moderator_options &= speakerp && speakerp->isInVoiceChannel();
+ }
+ participant_model->setModeratorOptionsVisible(show_moderator_options);
+ }
+
+ current_participant_model++;
+ }
+ }
}
mParticipantRefreshTimer.setTimerExpirySec(1.0f);
@@ -1693,6 +1723,10 @@ bool LLFloaterIMContainer::visibleContextMenuItem(const LLSD& userdata)
{
return isMuted(conversation_item->getUUID());
}
+ else if ("can_allow_text_chat" == item)
+ {
+ return !isNearbyChatSpeakerSelected();
+ }
return true;
}
@@ -2022,9 +2056,27 @@ LLConversationViewParticipant* LLFloaterIMContainer::createConversationViewParti
bool LLFloaterIMContainer::enableModerateContextMenuItem(const std::string& userdata, bool is_self)
{
- // only group moderators can perform actions related to this "enable callback"
- if (!isGroupModerator())
+ if (LLNearbyVoiceModeration::getInstance()->isNearbyChatModerator() && isNearbyChatSpeakerSelected())
{
+ // Determine here which actions are allowed
+ if ("can_moderate_voice" == userdata)
+ {
+ return true;
+ }
+ else if (("can_mute" == userdata))
+ {
+ return !is_self;
+ }
+ else if ("can_unmute" == userdata)
+ {
+ return true;
+ }
+
+ return false;
+ }
+ else if (!isGroupModerator())
+ {
+ // only group moderators can perform actions related to this "enable callback"
return false;
}
@@ -2157,7 +2209,35 @@ void LLFloaterIMContainer::banSelectedMember(const LLUUID& participant_uuid)
void LLFloaterIMContainer::moderateVoice(const std::string& command, const LLUUID& userID)
{
- if (!gAgent.getRegion()) return;
+ if (!gAgent.getRegion())
+ {
+ return;
+ }
+
+ if (isNearbyChatSpeakerSelected())
+ {
+ if ("selected" == command)
+ {
+ // Request a mute/unmute using a capability request via the simulator
+ LLNearbyVoiceModeration::getInstance()->requestMuteIndividual(userID, !isMuted(userID));
+ }
+ else
+ if ("mute_all" == command)
+ {
+ // Send the mute_all request to the server
+ const bool mute_state = true;
+ LLNearbyVoiceModeration::getInstance()->requestMuteAll(mute_state);
+ }
+ else
+ if ("unmute_all" == command)
+ {
+ // Send the unmute_all request to the server
+ const bool mute_state = false;
+ LLNearbyVoiceModeration::getInstance()->requestMuteAll(mute_state);
+ }
+
+ return;
+ }
if (command.compare("selected"))
{
@@ -2275,6 +2355,31 @@ LLSpeaker * LLFloaterIMContainer::getSpeakerOfSelectedParticipant(LLSpeakerMgr *
return speaker_managerp->findSpeaker(participant_itemp->getUUID());
}
+bool LLFloaterIMContainer::isNearbyChatSpeakerSelected()
+{
+ LLFolderViewItem *selectedItem = mConversationsRoot->getCurSelectedItem();
+ if (!selectedItem)
+ {
+ LL_WARNS() << "Current selected item is null" << LL_ENDL;
+ return NULL;
+ }
+
+ conversations_widgets_map::const_iterator iter = mConversationsWidgets.begin();
+ conversations_widgets_map::const_iterator end = mConversationsWidgets.end();
+ const LLUUID * conversation_uuidp = NULL;
+ while(iter != end)
+ {
+ if (iter->second == selectedItem || iter->second == selectedItem->getParentFolder())
+ {
+ conversation_uuidp = &iter->first;
+ break;
+ }
+ ++iter;
+ }
+ // Nearby chat ID is LLUUID::null
+ return conversation_uuidp->isNull();
+}
+
void LLFloaterIMContainer::toggleAllowTextChat(const LLUUID& participant_uuid)
{
LLIMSpeakerMgr * speaker_managerp = dynamic_cast<LLIMSpeakerMgr*>(getSpeakerMgrForSelectedParticipant());
diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h
index 30eed8be36..9f1690a9b9 100644
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -178,6 +178,7 @@ private:
void banSelectedMember(const LLUUID& participant_uuid);
void openNearbyChat();
bool isParticipantListExpanded();
+ bool isNearbyChatSpeakerSelected();
void idleUpdate(); // for convenience (self) from static idle
void idleProcessEvents();
diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp
index 6d642638b3..73bce6f2fd 100644
--- a/indra/newview/llfloaterimsession.cpp
+++ b/indra/newview/llfloaterimsession.cpp
@@ -1056,7 +1056,7 @@ void LLFloaterIMSession::processAgentListUpdates(const LLSD& body)
if (moderator_muted_text)
label = LLTrans::getString("IM_muted_text_label");
else
- label = LLTrans::getString("IM_to_label") + " " + LLIMModel::instance().getName(mSessionID);
+ label = LLIMModel::instance().getName(mSessionID);
mInputEditor->setLabel(label);
if (moderator_muted_text)
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index 453161b792..b70d21e2c5 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -935,7 +935,7 @@ void LLFloaterIMSessionTab::hideOrShowTitle()
void LLFloaterIMSessionTab::updateSessionName(const std::string& name)
{
- mInputEditor->setLabel(LLTrans::getString("IM_to_label") + " " + name);
+ mInputEditor->setLabel(name);
}
void LLFloaterIMSessionTab::updateChatIcon(const LLUUID& id)
diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp
index 01108b5cfa..92b3c92165 100644
--- a/indra/newview/llfloatersettingsdebug.cpp
+++ b/indra/newview/llfloatersettingsdebug.cpp
@@ -106,6 +106,7 @@ void LLFloaterSettingsDebug::onCommitSettings()
LLVector3 vector;
LLVector3d vectord;
+ LLVector4 vector4;
LLQuaternion quat;
LLRect rect;
LLColor4 col4;
@@ -142,6 +143,13 @@ void LLFloaterSettingsDebug::onCommitSettings()
vectord.mdV[VZ] = mValSpinner3->getValue().asReal();
controlp->set(vectord.getValue());
break;
+ case TYPE_VEC4:
+ vector4.mV[VX] = (F32)mValSpinner1->getValue().asReal();
+ vector4.mV[VY] = (F32)mValSpinner2->getValue().asReal();
+ vector4.mV[VZ] = (F32)mValSpinner3->getValue().asReal();
+ vector4.mV[VW] = (F32)mValSpinner4->getValue().asReal();
+ controlp->set(vector4.getValue());
+ break;
case TYPE_QUAT:
quat.mQ[VX] = mValSpinner1->getValueF32();
quat.mQ[VY] = mValSpinner2->getValueF32();
@@ -352,6 +360,40 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp)
}
break;
}
+ case TYPE_VEC4:
+ {
+ LLVector4 v;
+ v.setValue(sd);
+ mValSpinner1->setVisible(true);
+ mValSpinner1->setLabel(std::string("X"));
+ mValSpinner2->setVisible(true);
+ mValSpinner2->setLabel(std::string("Y"));
+ mValSpinner3->setVisible(true);
+ mValSpinner3->setLabel(std::string("Z"));
+ mValSpinner4->setVisible(true);
+ mValSpinner4->setLabel(std::string("W"));
+ if (!mValSpinner1->hasFocus())
+ {
+ mValSpinner1->setPrecision(3);
+ mValSpinner1->setValue(v[VX]);
+ }
+ if (!mValSpinner2->hasFocus())
+ {
+ mValSpinner2->setPrecision(3);
+ mValSpinner2->setValue(v[VY]);
+ }
+ if (!mValSpinner3->hasFocus())
+ {
+ mValSpinner3->setPrecision(3);
+ mValSpinner3->setValue(v[VZ]);
+ }
+ if (!mValSpinner4->hasFocus())
+ {
+ mValSpinner4->setPrecision(3);
+ mValSpinner4->setValue(v[VW]);
+ }
+ break;
+ }
case TYPE_QUAT:
{
LLQuaternion q;
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 1d3668de92..f8cc6885c4 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -89,8 +89,7 @@ const S32 XL8_PADDING = 3; // XL8_START_TAG.size() + XL8_END_TAG.size()
const static U32 SESSION_INITIALIZATION_TIMEOUT = 30;
// This enum corresponds to the sim's and adds P2P_CHAT_SESSION,
-// as webrtc uses the multiagent chat mechanism for p2p calls,
-// instead of relying on vivox calling.
+// as webrtc uses the multiagent chat mechanism for p2p calls.
// Don't change this without consulting a server developer.
enum EMultiAgentChatSessionType
{
@@ -1943,12 +1942,6 @@ void LLIMModel::sendMessage(const std::string& utf8_text,
info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id);
U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE;
- // Old call to send messages to SLim client, no longer supported.
- //if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id)))
- //{
- // // User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice.
- // sent = LLVoiceClient::getInstance()->sendTextMessage(other_participant_id, utf8_text);
- //}
if(!sent)
{
@@ -3088,8 +3081,7 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload
{
if (type == IM_SESSION_P2P_INVITE)
{
- // decline p2p voice, either via the vivox-style call mechanism
- // or via the webrtc-style "decline p2p" mechanism.
+ // decline p2p voice, via the webrtc-style "decline p2p" mechanism.
LLVoiceP2PIncomingCallInterfacePtr call = LLVoiceClient::getInstance()->getIncomingCallInterface(payload["voice_channel_info"]);
if (call)
{
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 20bda5039d..fb6ecedcbf 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -2847,8 +2847,44 @@ void LLMeshUploadThread::packModelIntance(
texture_index.find(texture) == texture_index.end())
{
texture_index[texture] = texture_num;
- std::string str = texture_str.str();
- res["texture_list"][texture_num] = LLSD::Binary(str.begin(), str.end());
+ if (include_textures)
+ {
+ std::string str = texture_str.str();
+ res["texture_list"][texture_num] = LLSD::Binary(str.begin(), str.end());
+ }
+ else
+ { // When not including the whole texture, we need to send some metadata about the image
+ // to ensure accurate price estimation. If not included, the server will assume all
+ // textures are 1024 x 1024, which could lead to a low estimate.
+ LLSD info = LLSD::emptyMap();
+
+ S32 texture_width = 0;
+ S32 texture_height = 0;
+ if (texture->hasSavedRawImage())
+ {
+ LLImageDataLock lock(texture->getSavedRawImage());
+
+ LLPointer<LLImageJ2C> upload_file = LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
+
+ if (!upload_file.isNull() && upload_file->getDataSize() && !upload_file->isBufferInvalid())
+ {
+ texture_width = upload_file->getWidth();
+ texture_height = upload_file->getHeight();
+ }
+ }
+
+ if ((texture_width <= 0) || (texture_height <= 0))
+ {
+ // Fall back to the texture's stored dimensions if we can't get dimensions from the raw image.
+ texture_width = texture->getFullWidth();
+ texture_height = texture->getFullHeight();
+ }
+
+ info["width"] = texture_width;
+ info["height"] = texture_height;
+ res["texture_info"][texture_num] = info;
+ res["texture_list"][texture_num] = LLSD::Binary(); // empty binary to indicate texture is not included, for older server compatibility
+ }
// store indexes for error handling;
texture_list_dest.push_back(material.mDiffuseMapFilename);
texture_num++;
@@ -2881,8 +2917,8 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, std::vector<std::string>&
LLSD res;
if (mDestinationFolderId.isNull())
{
- result["folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_OBJECT);
- result["texture_folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE);
+ result["folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_OBJECT);
+ result["texture_folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE);
}
else
{
diff --git a/indra/newview/llnearbyvoicemoderation.cpp b/indra/newview/llnearbyvoicemoderation.cpp
new file mode 100644
index 0000000000..a5ee0e9423
--- /dev/null
+++ b/indra/newview/llnearbyvoicemoderation.cpp
@@ -0,0 +1,220 @@
+/**
+ * @file llnearbyvoicemoderation.cpp
+ *
+ * $LicenseInfo:firstyear=2008&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llagent.h"
+#include "llnotificationsutil.h"
+#include "llviewerregion.h"
+#include "llvoavatar.h"
+#include "llvoicechannel.h"
+#include "llvoiceclient.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "roles_constants.h"
+
+#include "llnearbyvoicemoderation.h"
+
+LLNearbyVoiceModeration::LLNearbyVoiceModeration()
+{
+}
+
+LLNearbyVoiceModeration::~LLNearbyVoiceModeration()
+{
+}
+
+LLVOAvatar* LLNearbyVoiceModeration::getVOAvatarFromId(const LLUUID& agent_id)
+{
+ LLViewerObject *obj = gObjectList.findObject(agent_id);
+ while (obj && obj->isAttachment())
+ {
+ obj = (LLViewerObject*)obj->getParent();
+ }
+
+ if (obj && obj->isAvatar())
+ {
+ return (LLVOAvatar*)obj;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+const std::string LLNearbyVoiceModeration::getCapUrlFromRegion(LLViewerRegion* region)
+{
+ if (! region || ! region->capabilitiesReceived())
+ {
+ return std::string();
+ }
+
+ std::string url = region->getCapability("SpatialVoiceModerationRequest");
+ if (url.empty())
+ {
+ LL_INFOS() << "Capability URL for region " << region->getName() << " is empty" << LL_ENDL;
+ return std::string();
+ }
+ LL_INFOS() << "Capability URL for region " << region->getName() << " is " << url << LL_ENDL;
+
+ return url;
+}
+
+void LLNearbyVoiceModeration::requestMuteIndividual(const LLUUID& agent_id, bool mute)
+{
+ LLVOAvatar* avatar = getVOAvatarFromId(agent_id);
+ if (avatar)
+ {
+ const std::string cap_url = getCapUrlFromRegion(avatar->getRegion());
+ if (cap_url.length())
+ {
+ const std::string operand = mute ? "mute" : "unmute";
+
+ LLSD body;
+ body["operand"] = operand;
+ body["agent_id"] = agent_id;
+
+ const std::string agent_name = avatar->getFullname();
+ LL_INFOS() << "Resident " << agent_name
+ << " (" << agent_id << ")" << " applying " << operand << LL_ENDL;
+
+ std::string success_msg =
+ STRINGIZE("Resident " << agent_name
+ << " (" << agent_id << ")" << " nearby voice was set to " << operand);
+
+ std::string failure_msg =
+ STRINGIZE("Unable to change voice muting for resident "
+ << agent_name << " (" << agent_id << ")");
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(
+ cap_url,
+ body,
+ success_msg,
+ failure_msg);
+ }
+ }
+}
+
+void LLNearbyVoiceModeration::requestMuteAll(bool mute)
+{
+ // Use our own avatar to get the region name
+ LLViewerRegion* region = gAgent.getRegion();
+
+ const std::string cap_url = getCapUrlFromRegion(region);
+ if (cap_url.length())
+ {
+ const std::string operand = mute ? "mute_all" : "unmute_all";
+
+ LLSD body;
+ body["operand"] = operand;
+
+ LL_INFOS() << "For all residents in this region, applying: " << operand << LL_ENDL;
+
+ std::string success_msg =
+ STRINGIZE("Nearby voice for all residents was set to: " << operand);
+
+ std::string failure_msg =
+ STRINGIZE("Unable to set nearby voice for all residents to: " << operand);
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(
+ cap_url,
+ body,
+ success_msg,
+ failure_msg);
+ }
+}
+
+void LLNearbyVoiceModeration::setMutedInfo(const std::string& channelID, bool mute)
+{
+ auto it = mChannelMuteMap.find(channelID);
+ if (it == mChannelMuteMap.end())
+ {
+ if (mute)
+ {
+ // Channel is new and being muted
+ showMutedNotification(true);
+ }
+ mChannelMuteMap[channelID] = mute;
+ }
+ else
+ {
+ if (it->second != mute)
+ {
+ // Flag changed
+ showMutedNotification(mute);
+ it->second = mute;
+ }
+ }
+ if (mute && LLVoiceClient::getInstance()->getUserPTTState())
+ {
+ LLVoiceClient::getInstance()->setUserPTTState(false);
+ }
+}
+
+bool LLNearbyVoiceModeration::showNotificationIfNeeded()
+{
+ if (LLVoiceClient::getInstance()->inProximalChannel() &&
+ LLVoiceClient::getInstance()->getIsModeratorMuted(gAgentID))
+ {
+ return showMutedNotification(true);
+ }
+ return false;
+}
+
+bool LLNearbyVoiceModeration::showMutedNotification(bool is_muted)
+{
+ // Check if the current voice channel is nearby chat
+ if (LLVoiceClient::getInstance()->inProximalChannel())
+ {
+ LLNotificationsUtil::add(is_muted ? "NearbyVoiceMutedByModerator" : "NearbyVoiceUnmutedByModerator");
+ return true;
+ }
+ return false;
+}
+
+bool LLNearbyVoiceModeration::isNearbyChatModerator()
+{
+ // Region doesn't support WebRTC voice
+ if (!gAgent.getRegion() || !gAgent.getRegion()->isRegionWebRTCEnabled())
+ {
+ return false;
+ }
+
+ // Only show moderator options when connected to spatial voice chat
+ LLVoiceChannel* channel = LLVoiceChannel::getCurrentVoiceChannel();
+ if (!channel || channel->getSessionID().notNull() || !LLAgent::isActionAllowed("speak"))
+ {
+ return false;
+ }
+
+ if (LLViewerParcelMgr::getInstance()->isVoiceRestricted())
+ {
+ // Only the parcel owner should have access to moderate parcel voice space
+ return LLViewerParcelMgr::getInstance()->allowVoiceModeration();
+ }
+ else
+ {
+ return gAgent.canManageEstate();
+ }
+}
diff --git a/indra/newview/llnearbyvoicemoderation.h b/indra/newview/llnearbyvoicemoderation.h
new file mode 100644
index 0000000000..619f169883
--- /dev/null
+++ b/indra/newview/llnearbyvoicemoderation.h
@@ -0,0 +1,50 @@
+/**
+ * @file llnearbyvoicemoderation.h
+ *
+ * $LicenseInfo:firstyear=2008&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#pragma once
+
+class LLVOAvatar;
+
+class LLNearbyVoiceModeration : public LLSingleton <LLNearbyVoiceModeration> {
+ LLSINGLETON(LLNearbyVoiceModeration);
+ ~LLNearbyVoiceModeration();
+
+ public:
+ void requestMuteIndividual(const LLUUID& userID, bool mute);
+ void requestMuteAll(bool mute);
+
+ void setMutedInfo(const std::string& channelID, bool mute);
+ bool showMutedNotification(bool is_muted);
+ bool showNotificationIfNeeded();
+
+ bool isNearbyChatModerator();
+
+ private:
+ LLVOAvatar* getVOAvatarFromId(const LLUUID& id);
+ const std::string getCapUrlFromRegion(LLViewerRegion* region);
+
+ boost::signals2::connection mParcelCallbackConnection;
+ std::map<std::string, bool> mChannelMuteMap;
+};
diff --git a/indra/newview/llnotificationlistitem.cpp b/indra/newview/llnotificationlistitem.cpp
index 9a33bcb1b9..4939cd5fbb 100644
--- a/indra/newview/llnotificationlistitem.cpp
+++ b/indra/newview/llnotificationlistitem.cpp
@@ -175,13 +175,15 @@ void LLNotificationListItem::onMouseEnter(S32 x, S32 y, MASK mask)
{
mCondensedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "ScrollHoveredColor" ));
mExpandedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "ScrollHoveredColor" ));
+ mNoticeTextExp->setBgReadOnlyColor(LLUIColorTable::instance().getColor("SelectedBgReadOnlyColor"));
}
void LLNotificationListItem::onMouseLeave(S32 x, S32 y, MASK mask)
{
mCondensedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "SysWellItemUnselected" ));
mExpandedViewPanel->setTransparentColor(LLUIColorTable::instance().getColor( "SysWellItemUnselected" ));
-}
+ mNoticeTextExp->setBgReadOnlyColor(LLUIColorTable::instance().getColor("TextBgReadOnlyColor"));
+ }
//static
LLNotificationListItem* LLNotificationListItem::create(const Params& p)
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 26f1392758..3488685f14 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -1961,7 +1961,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
if (mColorSwatch)
{
mColorSwatch->setEnabled( false );
- mColorSwatch->setFallbackImage(LLUI::getUIImage("locked_image.j2c") );
+ mColorSwatch->setFallbackImage(LLUI::getUIImage("locked_image") );
mColorSwatch->setValid(false);
}
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 0cfb3ec49a..15cc8b421c 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -51,6 +51,7 @@
#include "llstartup.h"
#include "lltextbox.h"
#include "llui.h"
+#include "llframetimer.h"
#include "lluiconstants.h"
#include "llslurl.h"
#include "llversioninfo.h"
@@ -177,6 +178,19 @@ public:
};
LLLoginLocationAutoHandler gLoginLocationAutoHandler;
+std::string getShortGridLabel(const std::string& slurl_grid)
+{
+ if (slurl_grid == MAINGRID)
+ {
+ return LLTrans::getString("AgniGridLabelShort");
+ }
+ if (slurl_grid == BETAGRID)
+ {
+ return LLTrans::getString("AditiGridLabelShort");
+ }
+ return LLGridManager::getInstance()->getGridLabel(slurl_grid);
+}
+
//---------------------------------------------------------------------------
// Public methods
//---------------------------------------------------------------------------
@@ -187,7 +201,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
mCallback(callback),
mCallbackData(cb_data),
mListener(std::make_unique<LLPanelLoginListener>(this)),
- mFirstLoginThisInstall(gSavedSettings.getBOOL("FirstLoginThisInstall")),
mUsernameLength(0),
mPasswordLength(0),
mLocationLength(0),
@@ -207,15 +220,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
login_holder->addChild(this);
}
- if (mFirstLoginThisInstall)
- {
- buildFromFile( "panel_login_first.xml");
- }
- else
- {
- buildFromFile( "panel_login.xml");
- }
-
+ buildFromFile( "panel_login.xml");
reshape(rect.getWidth(), rect.getHeight());
LLLineEditor* password_edit(getChild<LLLineEditor>("password_edit"));
@@ -224,17 +229,19 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
password_edit->setCommitCallback(boost::bind(&LLPanelLogin::onClickConnect, false));
childSetAction("connect_btn", onClickConnect, this);
+ childSetAction("sign_btn", onClickSignUp, this);
mLoginBtn = getChild<LLButton>("connect_btn");
setDefaultBtn(mLoginBtn);
// change z sort of clickable text to be behind buttons
sendChildToBack(getChildView("forgot_password_text"));
- sendChildToBack(getChildView("sign_up_text"));
+
+ mLoginStack = getChild<LLLayoutStack>("login_stack");
+ mGridPanel = getChild<LLLayoutPanel>("grid_panel");
std::string current_grid = LLGridManager::getInstance()->getGrid();
- if (!mFirstLoginThisInstall)
- {
+
LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo");
updateLocationSelectorsVisibility(); // separate so that it can be called from preferences
favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, false));
@@ -254,17 +261,16 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
if (!grid_choice->first.empty() && current_grid != grid_choice->first)
{
LL_DEBUGS("AppInit") << "adding " << grid_choice->first << LL_ENDL;
- server_choice_combo->add(grid_choice->second, grid_choice->first);
+ server_choice_combo->add(getShortGridLabel(grid_choice->first), grid_choice->first);
}
}
server_choice_combo->sortByName();
LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL;
- server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(),
+ server_choice_combo->add(getShortGridLabel(current_grid),
current_grid,
ADD_TOP);
server_choice_combo->selectFirstItem();
- }
LLSLURL start_slurl(LLStartUp::getStartSLURL());
// The StartSLURL might have been set either by an explicit command-line
@@ -311,12 +317,9 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
LLTextBox* forgot_password_text = getChild<LLTextBox>("forgot_password_text");
forgot_password_text->setClickedCallback(onClickForgotPassword, NULL);
- LLTextBox* sign_up_text = getChild<LLTextBox>("sign_up_text");
- sign_up_text->setClickedCallback(onClickSignUp, NULL);
-
// get the web browser control
- LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
- web_browser->addObserver(this);
+ mWebBrowser = getChild<LLMediaCtrl>("login_html");
+ mWebBrowser->addObserver(this);
loadLoginPage();
@@ -337,15 +340,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
void LLPanelLogin::addFavoritesToStartLocation()
{
- if (mFirstLoginThisInstall)
- {
- // first login panel has no favorites, just update name length and buttons
- std::string user_defined_name = getChild<LLComboBox>("username_combo")->getSimple();
- mUsernameLength = static_cast<unsigned int>(user_defined_name.length());
- updateLoginButtons();
- return;
- }
-
// Clear the combo.
LLComboBox* combo = getChild<LLComboBox>("start_location_combo");
if (!combo) return;
@@ -565,16 +559,8 @@ void LLPanelLogin::resetFields()
// function is used to reset list in case of changes by external sources
return;
}
- if (sInstance->mFirstLoginThisInstall)
- {
- // no list to populate
- LL_WARNS() << "Shouldn't happen, user should have no ability to modify list on first install" << LL_ENDL;
- }
- else
- {
- LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
- sInstance->populateUserList(cred);
- }
+ LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
+ sInstance->populateUserList(cred);
}
// static
@@ -755,6 +741,11 @@ void LLPanelLogin::updateLocationSelectorsVisibility()
{
server_combo->setVisible(show_server);
}
+ if (LLTextBox* grid_txt = sInstance->getChild<LLTextBox>("grid_text"))
+ {
+ grid_txt->setVisible(show_server);
+ }
+ sInstance->collapseGridPanel(!show_server);
}
}
@@ -790,7 +781,7 @@ void LLPanelLogin::onUpdateStartSLURL(const LLSLURL& new_start_slurl)
// update the grid selector to match the slurl
LLComboBox* server_combo = sInstance->getChild<LLComboBox>("server_combo");
- std::string server_label(LLGridManager::getInstance()->getGridLabel(slurl_grid));
+ std::string server_label(getShortGridLabel(slurl_grid));
server_combo->setSimple(server_label);
updateServer(); // to change the links and splash screen
@@ -863,11 +854,9 @@ void LLPanelLogin::setAlwaysRefresh(bool refresh)
{
if (sInstance && LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)
{
- LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
-
- if (web_browser)
+ if (sInstance->mWebBrowser)
{
- web_browser->setAlwaysRefresh(refresh);
+ sInstance->mWebBrowser->setAlwaysRefresh(refresh);
}
}
}
@@ -924,16 +913,35 @@ void LLPanelLogin::loadLoginPage()
gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());
- LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
- if (web_browser->getCurrentNavUrl() != login_uri.asString())
+ if (sInstance->mWebBrowser)
+ {
+ if (sInstance->mWebBrowser->getCurrentNavUrl() != login_uri.asString())
+ {
+ LL_DEBUGS("AppInit") << "loading: " << login_uri << LL_ENDL;
+ sInstance->mWebBrowser->navigateTo(login_uri.asString(), "text/html");
+ }
+ }
+ else
{
- LL_DEBUGS("AppInit") << "loading: " << login_uri << LL_ENDL;
- web_browser->navigateTo( login_uri.asString(), "text/html" );
+ LL_WARNS("AppInit") << "No web browser control for login panel" << LL_ENDL;
}
}
-void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event)
+void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
{
+ constexpr F32 REFRESH_DELAY = 2.f;
+ switch (event)
+ {
+ case MEDIA_EVENT_SIZE_CHANGED:
+ {
+ mForceRefreshTimer.reset();
+ mForceRefreshTimer.setTimerExpirySec(REFRESH_DELAY);
+ mForceRefresh = true;
+ break;
+ }
+ default:
+ break;
+ }
}
//---------------------------------------------------------------------------
@@ -1100,8 +1108,7 @@ void LLPanelLogin::onRememberUserCheck(void*)
LLComboBox* user_combo(sInstance->getChild<LLComboBox>("username_combo"));
bool remember = remember_name->getValue().asBoolean();
- if (!sInstance->mFirstLoginThisInstall
- && user_combo->getCurrentIndex() != -1
+ if (user_combo->getCurrentIndex() != -1
&& !remember)
{
remember = true;
@@ -1214,17 +1221,14 @@ void LLPanelLogin::updateLoginButtons()
{
mLoginBtn->setEnabled(mUsernameLength != 0 && mPasswordLength != 0 && !mAlertNotif);
- if (!mFirstLoginThisInstall)
+ LLComboBox* user_combo = getChild<LLComboBox>("username_combo");
+ LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name");
+ if (user_combo->getCurrentIndex() != -1)
{
- LLComboBox* user_combo = getChild<LLComboBox>("username_combo");
- LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name");
- if (user_combo->getCurrentIndex() != -1)
- {
- remember_name->setValue(true);
- LLCheckBoxCtrl* remember_pass = getChild<LLCheckBoxCtrl>("remember_password");
- remember_pass->setEnabled(true);
- } // Note: might be good idea to do "else remember_name->setValue(mRememberedState)" but it might behave 'weird' to user
- }
+ remember_name->setValue(true);
+ LLCheckBoxCtrl* remember_pass = getChild<LLCheckBoxCtrl>("remember_password");
+ remember_pass->setEnabled(true);
+ } // Note: might be good idea to do "else remember_name->setValue(mRememberedState)" but it might behave 'weird' to user
}
void LLPanelLogin::populateUserList(LLPointer<LLCredential> credential)
@@ -1403,3 +1407,29 @@ bool LLPanelLogin::onUpdateNotification(const LLSD& notify)
}
return false;
}
+
+void LLPanelLogin::collapseGridPanel(bool collapse)
+{
+ if (mGridPanel->isCollapsed() == collapse)
+ {
+ return;
+ }
+ mLoginStack->collapsePanel(mGridPanel, collapse);
+ mLoginStack->updateLayout();
+}
+
+void LLPanelLogin::draw()
+{
+ LLPanel::draw();
+
+ // Workaround for the black screen issue (see #5607)
+ // Should be removed after the proper fix for resizing is implemented
+ if (mForceRefresh && mForceRefreshTimer.hasExpired())
+ {
+ if (mWebBrowser->getMediaPlugin())
+ {
+ mWebBrowser->getMediaPlugin()->forceRenderRefresh();
+ }
+ mForceRefresh = false;
+ }
+}
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index f527aa53ac..a00081795e 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -48,6 +48,8 @@ public:
void *callback_data);
~LLPanelLogin();
+ void draw();
+
virtual void setFocus( bool b );
static void show(const LLRect &rect,
@@ -87,6 +89,8 @@ public:
// extract name from cred in a format apropriate for username field
static std::string getUserName(LLPointer<LLCredential> &cred);
+ void collapseGridPanel(bool collapse);
+
private:
friend class LLPanelLoginListener;
void addFavoritesToStartLocation();
@@ -122,7 +126,6 @@ private:
static LLPanelLogin* sInstance;
static bool sCapslockDidNotification;
- bool mFirstLoginThisInstall;
static bool sCredentialSet;
@@ -130,8 +133,15 @@ private:
unsigned int mPasswordLength;
unsigned int mLocationLength;
+ LLTimer mForceRefreshTimer;
+ bool mForceRefresh {false};
+
bool mAlertNotif;
LLButton* mLoginBtn;
+ LLLayoutPanel* mGridPanel;
+ LLLayoutStack* mLoginStack;
+
+ LLMediaCtrl* mWebBrowser;
};
#endif
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index f079c70c6c..c75314825c 100644
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -438,7 +438,7 @@ void LLSpeakerMgr::update(bool resort_ok)
{
if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL)
{
- // external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice)
+ // external speakers should be timed out when they leave the voice channel
speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
}
else
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index f780e4f5bd..b3ed65be82 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -2637,8 +2637,9 @@ void uninstall_nsis_if_required()
S32 found_minor = 0;
S32 found_patch = 0;
U64 found_build = 0;
+ std::string nsis_path;
- if (!get_nsis_version(found_major, found_minor, found_patch, found_build))
+ if (!get_nsis_version(found_major, found_minor, found_patch, found_build, nsis_path))
{
return;
}
@@ -2670,7 +2671,7 @@ void uninstall_nsis_if_required()
// so there is no point to check build.
LL_INFOS() << "Found NSIS install " << found_major << "." << found_minor << "." << found_patch << "." << found_build << LL_ENDL;
- clear_nsis_links();
+ clear_nsis_links(nsis_path);
LLSD args;
args["VERSION"] = llformat("%d.%d.%d", found_major, found_minor, found_patch);
diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp
index eb77343fd3..3de61dffc7 100644
--- a/indra/newview/lltoastnotifypanel.cpp
+++ b/indra/newview/lltoastnotifypanel.cpp
@@ -47,7 +47,7 @@
const S32 BOTTOM_PAD = VPAD * 3;
const S32 IGNORE_BTN_TOP_DELTA = 3*VPAD;//additional ignore_btn padding
-S32 BUTTON_WIDTH = 90;
+const S32 BUTTON_WIDTH = 90;
//static
@@ -59,7 +59,8 @@ LLToastNotifyPanel::button_click_signal_t LLToastNotifyPanel::sButtonClickSignal
LLToastNotifyPanel::LLToastNotifyPanel(const LLNotificationPtr& notification, const LLRect& rect, bool show_images)
: LLCheckBoxToastPanel(notification)
, LLInstanceTracker<LLToastNotifyPanel, LLUUID, LLInstanceTrackerReplaceOnCollision>(notification->getID())
-, mTextBox(NULL)
+, mTextBox(NULL),
+ mButtonWidth(BUTTON_WIDTH)
{
init(rect, show_images);
}
@@ -70,9 +71,9 @@ void LLToastNotifyPanel::addDefaultButton()
LLButton* ok_btn = createButton(form_element, false);
LLRect new_btn_rect(ok_btn->getRect());
- new_btn_rect.setOriginAndSize(llabs(getRect().getWidth() - BUTTON_WIDTH)/ 2, BOTTOM_PAD,
+ new_btn_rect.setOriginAndSize(llabs(getRect().getWidth() - mButtonWidth) / 2, BOTTOM_PAD,
//auto_size for ok button makes it very small, so let's make it wider
- BUTTON_WIDTH, new_btn_rect.getHeight());
+ mButtonWidth, new_btn_rect.getHeight());
ok_btn->setRect(new_btn_rect);
addChild(ok_btn, -1);
mNumButtons = 1;
@@ -115,7 +116,7 @@ LLButton* LLToastNotifyPanel::createButton(const LLSD& form_element, bool is_opt
p.font = font;
p.rect.height = BTN_HEIGHT;
p.click_callback.function(boost::bind(&LLToastNotifyPanel::onClickButton, userdata));
- p.rect.width = BUTTON_WIDTH;
+ p.rect.width = mButtonWidth;
p.auto_resize = false;
p.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
p.enabled = !form_element.has("enabled") || form_element["enabled"].asBoolean();
@@ -125,7 +126,7 @@ LLButton* LLToastNotifyPanel::createButton(const LLSD& form_element, bool is_opt
p.image_color_disabled(LLUIColorTable::instance().getColor("ButtonCautionImageColor"));
}
// for the scriptdialog buttons we use fixed button size. This is a limit!
- if (!mIsScriptDialog && font->getWidth(form_element["text"].asString()) > (BUTTON_WIDTH-2*HPAD))
+ if (!mIsScriptDialog && font->getWidth(form_element["text"].asString()) > (mButtonWidth - 2 * HPAD))
{
p.rect.width = 1;
p.auto_resize = true;
@@ -290,7 +291,7 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images )
mInfoPanel = getChild<LLPanel>("info_panel");
mControlPanel = getChild<LLPanel>("control_panel");
- BUTTON_WIDTH = gSavedSettings.getS32("ToastButtonWidth");
+
// customize panel's attributes
// is it intended for displaying a tip?
mIsTip = mNotification->getType() == "notifytip";
@@ -299,6 +300,10 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images )
// is it a script dialog?
mIsScriptDialog = (notif_name == "ScriptDialog" || notif_name == "ScriptDialogGroup");
+ static LLCachedControl<S32> btn_width(gSavedSettings, "ToastButtonWidth", 90);
+ static LLCachedControl<S32> script_button_width(gSavedSettings, "ScriptToastButtonWidth", 110);
+ mButtonWidth = mIsScriptDialog ? script_button_width : btn_width;
+
bool is_content_trusted = (notif_name != "LoadWebPage");
// is it a caution?
//
@@ -379,8 +384,21 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images )
}
else
{
- const S32 button_panel_width = mControlPanel->getRect().getWidth();// do not change width of the panel
+ S32 button_panel_width = mControlPanel->getRect().getWidth();// get initial width from XML
S32 button_panel_height = mControlPanel->getRect().getHeight();
+
+ // Script dialog has wider buttons so it requires wider layout to ensure proper spacing
+ if (mIsScriptDialog)
+ {
+ // width for 3 columns: 3 buttons + 2 gaps
+ S32 min_width_required = 3 * mButtonWidth + 2 * (2 * HPAD);
+ if (min_width_required > button_panel_width)
+ {
+ button_panel_width = min_width_required;
+ S32 width_increase = button_panel_width - mControlPanel->getRect().getWidth();
+ reshape(getRect().getWidth() + width_increase, getRect().getHeight());
+ }
+ }
//try get an average h_pad to spread out buttons
S32 h_pad = (button_panel_width - buttons_width) / (S32(buttons.size()));
if(h_pad < 2*HPAD)
@@ -390,8 +408,8 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images )
* for a scriptdialog toast h_pad can be < 2*HPAD if we have a lot of buttons.
* In last case set default h_pad to avoid heaping of buttons
*/
- S32 button_per_row = button_panel_width / BUTTON_WIDTH;
- h_pad = (button_panel_width % BUTTON_WIDTH) / (button_per_row - 1);// -1 because we do not need space after last button in a row
+ S32 button_per_row = button_panel_width / mButtonWidth;
+ h_pad = (button_panel_width % mButtonWidth) / (button_per_row - 1);// -1 because we do not need space after last button in a row
if(h_pad < 2*HPAD) // still not enough space between buttons ?
{
h_pad = 2*HPAD;
@@ -402,7 +420,7 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images )
// we are using default width for script buttons so we can determinate button_rows
// to get a number of rows we divide the required width of the buttons to button_panel_width
// buttons.size() is reduced by -2 due to presence of ignore button which is calculated independently a bit lower
- S32 button_rows = llceil(F32(buttons.size() - 2) * (BUTTON_WIDTH + h_pad) / (button_panel_width + h_pad));
+ S32 button_rows = llceil(F32(buttons.size() - 2) * (mButtonWidth + h_pad) / (button_panel_width + h_pad));
//reserve one row for the ignore_btn
button_rows++;
//calculate required panel height for scripdialog notification.
diff --git a/indra/newview/lltoastnotifypanel.h b/indra/newview/lltoastnotifypanel.h
index d694513aba..71b9eaf8f5 100644
--- a/indra/newview/lltoastnotifypanel.h
+++ b/indra/newview/lltoastnotifypanel.h
@@ -134,6 +134,8 @@ protected:
S32 mNumOptions { 0 };
S32 mNumButtons { 0 };
+ S32 mButtonWidth;
+
static const std::string sFontDefault;
static const std::string sFontScript;
};
diff --git a/indra/newview/llvelopack.cpp b/indra/newview/llvelopack.cpp
index d34d43cc48..26f3f41db6 100644
--- a/indra/newview/llvelopack.cpp
+++ b/indra/newview/llvelopack.cpp
@@ -331,14 +331,14 @@ static std::wstring get_desktop_path()
return L"";
}
-static bool create_shortcut(const std::wstring& shortcut_path,
+static HRESULT create_shortcut(const std::wstring& shortcut_path,
const std::wstring& target_path,
const std::wstring& arguments,
const std::wstring& description,
const std::wstring& icon_path)
{
HRESULT hr = CoInitialize(NULL);
- if (FAILED(hr)) return false;
+ if (FAILED(hr)) return hr;
IShellLinkW* shell_link = nullptr;
hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
@@ -366,7 +366,7 @@ static bool create_shortcut(const std::wstring& shortcut_path,
}
CoUninitialize();
- return SUCCEEDED(hr);
+ return hr;
}
static void register_protocol_handler(const std::wstring& protocol,
@@ -406,9 +406,172 @@ static void register_protocol_handler(const std::wstring& protocol,
}
}
-void clear_nsis_links()
+static bool get_shortcut_target(const std::wstring& lnk_path, std::wstring& target_path_str)
+{
+ // Resolve the shortcut to check its target
+ wchar_t target_path[MAX_PATH] = { 0 };
+ HRESULT hr = CoInitialize(NULL);
+ bool res = false;
+ if (SUCCEEDED(hr))
+ {
+ IShellLinkW* psl = nullptr;
+ hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (void**)&psl);
+ if (SUCCEEDED(hr))
+ {
+ IPersistFile* ppf = nullptr;
+ hr = psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
+ if (SUCCEEDED(hr))
+ {
+ hr = ppf->Load(lnk_path.c_str(), STGM_READ);
+ if (SUCCEEDED(hr))
+ {
+ // Resolve() in theory may retarget to a different executable,
+ // but we should be fine as long as folder stays the same,
+ // otherwise we shouldn't clear it.
+ hr = psl->Resolve(NULL, SLR_NO_UI | SLR_NOUPDATE | SLR_ANY_MATCH);
+ if (SUCCEEDED(hr))
+ {
+ hr = psl->GetPath(target_path, MAX_PATH, nullptr, 0);
+ if (SUCCEEDED(hr))
+ {
+ target_path_str = std::wstring(target_path);
+ res = true;
+ }
+ }
+ }
+ ppf->Release();
+ }
+ psl->Release();
+ }
+ CoUninitialize();
+ }
+ return res;
+}
+
+static bool paths_are_equal(const std::wstring& path1, const std::wstring& path2)
+{
+ try
+ {
+ std::error_code ec1, ec2;
+ std::filesystem::path p1(path1);
+ std::filesystem::path p2(path2);
+
+ // Get canonical (absolute, normalized) paths
+ auto canonical1 = std::filesystem::canonical(p1, ec1);
+ auto canonical2 = std::filesystem::canonical(p2, ec2);
+
+ // If either path doesn't exist, fall back to string comparison
+ if (ec1 || ec2)
+ {
+ // Normalize case for comparison
+ std::wstring lower1 = path1;
+ std::wstring lower2 = path2;
+ std::transform(lower1.begin(), lower1.end(), lower1.begin(), ::towlower);
+ std::transform(lower2.begin(), lower2.end(), lower2.begin(), ::towlower);
+ while (!lower1.empty() && (lower1.back() == L'\\' || lower1.back() == L'/'))
+ {
+ lower1.pop_back();
+ }
+ while (!lower2.empty() && (lower2.back() == L'\\' || lower2.back() == L'/'))
+ {
+ lower2.pop_back();
+ }
+ return lower1 == lower2;
+ }
+
+ // Use filesystem::equivalent which handles all path variations
+ return std::filesystem::equivalent(canonical1, canonical2, ec1);
+ }
+ catch (const std::filesystem::filesystem_error&)
+ {
+ // Fallback to case-insensitive string comparison
+ std::wstring lower1 = path1;
+ std::wstring lower2 = path2;
+ std::transform(lower1.begin(), lower1.end(), lower1.begin(), ::towlower);
+ std::transform(lower2.begin(), lower2.end(), lower2.begin(), ::towlower);
+ while (!lower1.empty() && (lower1.back() == L'\\' || lower1.back() == L'/'))
+ {
+ lower1.pop_back();
+ }
+ while (!lower2.empty() && (lower2.back() == L'\\' || lower2.back() == L'/'))
+ {
+ lower2.pop_back();
+ }
+ return lower1 == lower2;
+ }
+}
+
+static void update_taskbar_shortcut(const std::string& nsis_folder_path, const std::wstring& appdata_path, const std::wstring& app_name, const std::wstring& link_name)
+{
+ std::wstring taskbar_path = appdata_path;
+ taskbar_path += L"\\Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar\\";
+ taskbar_path += link_name;
+
+ if (!PathFileExistsW(taskbar_path.c_str()))
+ {
+ // User didn't create one
+ return;
+ }
+
+ // Verify we are removing or updating the right thing.
+ // It is not warranteed that the shortcut points to NSIS.
+ std::wstring target_path;
+ if (get_shortcut_target(taskbar_path, target_path))
+ {
+ // Strip the filename part to get just the folder path
+ std::filesystem::path trim_path(target_path);
+ if (trim_path.has_filename())
+ {
+ target_path = trim_path.parent_path().wstring();
+ }
+ std::wstring nsis_path_w = ll_convert<std::wstring>(nsis_folder_path);
+ if (!paths_are_equal(nsis_path_w, target_path))
+ {
+ // Shortcut points to something else, don't mess with it
+ LL_INFOS("Velopack") << "Found a matching shortcut, but it points to a different channel. Expected: "
+ << ll_convert_wide_to_string(nsis_path_w)
+ << ", actual: " << ll_convert_wide_to_string(target_path)
+ << LL_ENDL;
+ return;
+ }
+ }
+
+ // First try to overwrite shortcut
+ std::wstring current_exe = ll_convert<std::wstring>(gDirUtilp->getExecutablePathAndName());
+ HRESULT hr = create_shortcut(taskbar_path, current_exe, L"", app_name, current_exe);
+ if (SUCCEEDED(hr))
+ {
+ LL_INFOS("Velopack") << "Successfully updated taskbar shortcut to point to current exe" << LL_ENDL;
+ return;
+ }
+
+ // Try deleting and if possible, recreating separately. We should not leave hanging shortcuts behind.
+ if (!DeleteFileW(taskbar_path.c_str()))
+ {
+ DWORD error = GetLastError();
+ if (error != ERROR_FILE_NOT_FOUND)
+ {
+ LL_WARNS("Velopack") << "Failed to delete NSIS taskbar shortcut: "
+ << ll_convert_wide_to_string(taskbar_path)
+ << " (error: " << error << ")" << LL_ENDL;
+ }
+ }
+ else
+ {
+ // Deleted user created link, recreate it with new target if possible.
+ LL_INFOS("Velopack") << "Updating taskbar shortcut to point to current exe" << LL_ENDL;
+ HRESULT hr = create_shortcut(taskbar_path, current_exe, L"", app_name, current_exe);
+ if (FAILED(hr))
+ {
+ LL_WARNS("Velopack") << "Failed to re-create taskbar shortcut, error: " << std::hex << hr << ", NSIS shortcut was removed" << LL_ENDL;
+ }
+ }
+}
+
+void clear_nsis_links(const std::string& nsis_folder_path)
{
wchar_t path[MAX_PATH];
+ std::wstring app_name = get_app_name();
// 1. The 'start' shortcuts set by nsis would be global, like app shortcut:
// C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Second Life Viewer\Second Life Viewer.lnk
@@ -416,7 +579,7 @@ void clear_nsis_links()
if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_COMMON_PROGRAMS, NULL, 0, path)))
{
std::wstring start_menu_path = path;
- std::wstring folder_path = start_menu_path + L"\\" + get_app_name();
+ std::wstring folder_path = start_menu_path + L"\\" + app_name;
std::error_code ec;
std::filesystem::path dir(folder_path);
@@ -432,11 +595,11 @@ void clear_nsis_links()
}
// 2. Desktop link, also a global one.
- // C:\Users\Public\Desktop
+ // C:\Users\Public\Desktop\Second Life Viewer.lnk
if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, path)))
{
std::wstring desktop_path = path;
- std::wstring shortcut_path = desktop_path + L"\\" + get_app_name() + L".lnk";
+ std::wstring shortcut_path = desktop_path + L"\\" + app_name + L".lnk";
if (!DeleteFileW(shortcut_path.c_str()))
{
DWORD error = GetLastError();
@@ -448,6 +611,19 @@ void clear_nsis_links()
}
}
}
+
+ // 3. Taskbar links, which are user-specific and located at:
+ // %AppData%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\
+ // Note that it can be a link to velopack already or to a different NSIS viewer.
+ // Name might also be different based on method of creation.
+ if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, path)))
+ {
+ update_taskbar_shortcut(nsis_folder_path, path, app_name, L"Second Life.lnk"); // Window class name
+ update_taskbar_shortcut(nsis_folder_path, path, app_name, L"Second Life(1).lnk"); // Just in case user somehow did it twice and removed first
+ update_taskbar_shortcut(nsis_folder_path, path, app_name, L"SecondLifeViewer.lnk"); // Executable name
+ update_taskbar_shortcut(nsis_folder_path, path, app_name, L"secondlife-bin.lnk"); // Debug builds
+ update_taskbar_shortcut(nsis_folder_path, path, app_name, app_name + L".lnk"); // Default name
+ }
}
static void parse_version(const wchar_t* version_str, int& major, int& minor, int& patch, uint64_t& build)
@@ -463,7 +639,8 @@ bool get_nsis_version(
int& nsis_major,
int& nsis_minor,
int& nsis_patch,
- uint64_t& nsis_build)
+ uint64_t& nsis_build,
+ std::string& nsis_path)
{
// Test for presence of NSIS viewer registration, then
// attempt to read uninstall info
@@ -516,12 +693,21 @@ bool get_nsis_version(
}
std::error_code ec;
std::filesystem::path path(path_buffer);
+ // check if uninstaller exists
if (!std::filesystem::exists(path, ec))
{
return false;
}
- // Todo: check codesigning?
+ // We found a valid NSIS installation, trim the path to get the folder
+ wchar_t* pos = wcsstr(path_buffer, L"uninst.exe");
+ if (pos)
+ {
+ // Trim uninst.exe from the path by setting null terminator before it
+ *pos = L'\0';
+ }
+ // Note that it has a trailing backslash.
+ nsis_path = ll_convert_wide_to_string(path_buffer);
return true;
}
@@ -648,6 +834,32 @@ static void on_first_run(void* p_user_data, const char* app_version)
MultiByteToWideChar(CP_UTF8, 0, app_version, -1, &version[0], len);
register_uninstall_info(install_dir, app_name, version);
+ // Drop install related settings
+ // Unfortunately gDirUtilp is not initialized yet and it's shouldn't
+ // be possible to change location of the settings. For now it's simpler
+ // to hardcode the location.
+ std::optional<std::string> app_data = LLStringUtil::getoptenv("APPDATA");
+ if (app_data)
+ {
+ // Strip trailing delimiter if present
+ std::string app_data_path = *app_data;
+ if (!app_data_path.empty() && (app_data_path.back() == '\\' || app_data_path.back() == '/'))
+ {
+ app_data_path.pop_back();
+ }
+
+ std::string user_settings_path = app_data_path + "\\SecondLife\\user_settings\\settings.xml";
+ LLControlGroup settings("global");
+ if (settings.loadFromFile(user_settings_path))
+ {
+ // If user reinstalls or updates, we want to recheck for nsis leftovers.
+ if (settings.controlExists("PreviousInstallChecked"))
+ {
+ settings.setBOOL("PreviousInstallChecked", false);
+ }
+ settings.saveToFile(user_settings_path, true);
+ }
+ }
}
static void on_after_install(void* user_data, const char* app_version)
diff --git a/indra/newview/llvelopack.h b/indra/newview/llvelopack.h
index d04d0db7dc..449330f68d 100644
--- a/indra/newview/llvelopack.h
+++ b/indra/newview/llvelopack.h
@@ -46,12 +46,13 @@ void velopack_set_progress_callback(std::function<void(int)> callback);
void velopack_cleanup();
#if LL_WINDOWS
-void clear_nsis_links();
+void clear_nsis_links(const std::string& nsis_folder_path);
bool get_nsis_version(
int& nsis_major,
int& nsis_minor,
int& nsis_patch,
- uint64_t& nsis_build);
+ uint64_t& nsis_build,
+ std::string& nsis_folder_path);
#endif
#endif // LL_VELOPACK
diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp
index 2ca2c5c07d..a9aa63e68f 100644
--- a/indra/newview/llviewerchat.cpp
+++ b/indra/newview/llviewerchat.cpp
@@ -200,7 +200,7 @@ LLFontGL* LLViewerChat::getChatFont()
break;
default:
case 1:
- fontp = LLFontGL::getFontSansSerif();
+ fontp = LLFontGL::getFontSansSerifMedium();
break;
case 2:
fontp = LLFontGL::getFontSansSerifBig();
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 129d5477f1..ff111dd1bc 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -127,7 +127,6 @@
#include "llviewerstatsrecorder.h"
#include "llvlcomposition.h"
#include "llvoavatarself.h"
-#include "llvoicevivox.h"
#include "llworld.h"
#include "llworldmap.h"
#include "pipeline.h"
@@ -649,7 +648,7 @@ void init_menus()
LLRect menuBarRect = gLoginMenuBarView->getRect();
menuBarRect.setLeftTopAndSize(0, menu_bar_holder->getRect().getHeight(), menuBarRect.getWidth(), menuBarRect.getHeight());
gLoginMenuBarView->setRect(menuBarRect);
- gLoginMenuBarView->setBackgroundColor( color );
+ gLoginMenuBarView->setBackgroundColor(LLColor4::black);
menu_bar_holder->addChild(gLoginMenuBarView);
// tooltips are on top of EVERYTHING, including menus
diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp
index 6cb3aee20c..8ec2a6d661 100644
--- a/indra/newview/llviewernetwork.cpp
+++ b/indra/newview/llviewernetwork.cpp
@@ -63,7 +63,7 @@ const std::string GRID_LOGIN_IDENTIFIER_TYPES = "login_identifier_types";
const std::string GRID_SLURL_BASE = "slurl_base";
const std::string GRID_APP_SLURL_BASE = "app_slurl_base";
-const std::string DEFAULT_LOGIN_PAGE = "https://viewer-splash.secondlife.com/";
+const std::string DEFAULT_LOGIN_PAGE = "https://viewer-splash-v2.secondlife.com/";
const std::string MAIN_GRID_LOGIN_URI = "https://login.agni.lindenlab.com/cgi-bin/login.cgi";
@@ -125,7 +125,7 @@ void LLGridManager::initialize(const std::string& grid_file)
MAIN_GRID_WEB_PROFILE_URL,
"Agni");
addSystemGrid(LLTrans::getString("AditiGridLabel"),
- "util.aditi.lindenlab.com",
+ BETAGRID,
"https://login.aditi.lindenlab.com/cgi-bin/login.cgi",
"https://secondlife.aditi.lindenlab.com/helpers/",
DEFAULT_LOGIN_PAGE,
diff --git a/indra/newview/llviewernetwork.h b/indra/newview/llviewernetwork.h
index 2ed663e038..0937425a18 100644
--- a/indra/newview/llviewernetwork.h
+++ b/indra/newview/llviewernetwork.h
@@ -30,6 +30,7 @@
// @TODO this really should be private, but is used in llslurl
#define MAINGRID "util.agni.lindenlab.com"
+#define BETAGRID "util.aditi.lindenlab.com"
/// Exception thrown when a grid is not valid
class LLInvalidGridName
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index 6a029645fb..b794047135 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -702,6 +702,16 @@ bool LLViewerParcelMgr::allowAgentVoice() const
return allowAgentVoice(gAgent.getRegion(), mAgentParcel);
}
+bool LLViewerParcelMgr::isVoiceRestricted() const
+{
+ return mAgentParcel && !mAgentParcel->getParcelFlagUseEstateVoiceChannel();
+}
+
+bool LLViewerParcelMgr::allowVoiceModeration() const
+{
+ return isVoiceRestricted() && isParcelOwnedByAgent(mAgentParcel, GP_SESSION_MODERATOR);
+}
+
bool LLViewerParcelMgr::allowAgentVoice(const LLViewerRegion* region, const LLParcel* parcel) const
{
return region && region->isVoiceEnabled()
diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h
index 8439283eb0..0d79496ccc 100644
--- a/indra/newview/llviewerparcelmgr.h
+++ b/indra/newview/llviewerparcelmgr.h
@@ -174,6 +174,12 @@ public:
bool allowAgentVoice() const;
bool allowAgentVoice(const LLViewerRegion* region, const LLParcel* parcel) const;
+ // Returns true if this parcel is using private voice channel
+ bool isVoiceRestricted() const;
+
+ // Can this agent moderate Nearby voice chat on this parcel?
+ bool allowVoiceModeration() const;
+
// Can this agent start flying on this parcel?
// Used for parcel property icons in nav bar.
bool allowAgentFly(const LLViewerRegion* region, const LLParcel* parcel) const;
diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
index e023dffc03..e36ad0e722 100755
--- a/indra/newview/llviewerparceloverlay.cpp
+++ b/indra/newview/llviewerparceloverlay.cpp
@@ -63,9 +63,9 @@ LLUIColor LLViewerParcelOverlay::sForSaleColor;
LLUIColor LLViewerParcelOverlay::sAuctionColor;
LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_width_meters)
-: mRegion(region),
- mParcelGridsPerEdge(S32(region_width_meters / PARCEL_GRID_STEP_METERS)),
- mDirty(false),
+: mRegion( region ),
+ mParcelGridsPerEdge( S32( region_width_meters / PARCEL_GRID_STEP_METERS ) ),
+ mDirty( false ),
mTimeSinceLastUpdate(),
mOverlayTextureIdx(-1)
{
@@ -467,9 +467,9 @@ void LLViewerParcelOverlay::updatePropertyLines()
{
for (S32 col = 0; col < GRIDS_PER_EDGE; col++)
{
- U8 overlay = mOwnership[row * GRIDS_PER_EDGE + col];
+ U8 overlay = mOwnership[row*GRIDS_PER_EDGE+col];
S32 colorIndex = overlay & PARCEL_COLOR_MASK;
- switch (colorIndex)
+ switch(colorIndex)
{
case PARCEL_SELF:
case PARCEL_GROUP:
@@ -483,11 +483,11 @@ void LLViewerParcelOverlay::updatePropertyLines()
const LLColor4U& color = colors[colorIndex];
- F32 left = col * GRID_STEP;
- F32 right = left + GRID_STEP;
+ F32 left = col*GRID_STEP;
+ F32 right = left+GRID_STEP;
- F32 bottom = row * GRID_STEP;
- F32 top = bottom + GRID_STEP;
+ F32 bottom = row*GRID_STEP;
+ F32 top = bottom+GRID_STEP;
// West edge
if (overlay & PARCEL_WEST_LINE)
@@ -528,121 +528,99 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3
Edge& edge = mEdges.back();
edge.color = color;
- // Detailized rendering vertices:
- // A B C D E F G
- // *-*------*--------*--------*------*-* : 'outside' vertices are placed right on the border
- // *------*--------*--------*------* : 'inside' vertices are shifted on LINE_WIDTH inside
-
- // Simplified rendering vertices:
- // A G
- // *-----------------------------------*
- // *-----------------------------------*
-
F32 outside_x = start_x;
F32 outside_y = start_y;
- F32 outside_z = land.resolveHeightRegion(outside_x, outside_y);
- F32 inside_x = start_x + tick_dx;
- F32 inside_y = start_y + tick_dy;
- F32 inside_z = land.resolveHeightRegion(inside_x, inside_y);
-
- auto move = [&](F32 distance)
- {
- outside_x += dx * distance;
- outside_y += dy * distance;
- outside_z = land.resolveHeightRegion(outside_x, outside_y);
- inside_x += dx * distance;
- inside_y += dy * distance;
- inside_z = land.resolveHeightRegion(inside_x, inside_y);
- };
+ F32 outside_z = 0.f;
+ F32 inside_x = start_x + tick_dx;
+ F32 inside_y = start_y + tick_dy;
+ F32 inside_z = 0.f;
- auto split = [&](U32 lod, const LLVector4a& start, F32 x, F32 y, F32 z, F32 part)
+ auto split = [&](const LLVector3& start, F32 x, F32 y, F32 z, F32 part)
{
- F32 new_x = start[VX] + (x - start[VX]) * part;
- F32 new_y = start[VY] + (y - start[VY]) * part;
- edge.pushVertex(lod, new_x, new_y, water_z, 0);
+ F32 new_x = start.mV[VX] + (x - start.mV[VX]) * part;
+ F32 new_y = start.mV[VY] + (y - start.mV[VY]) * part;
+ F32 new_z = start.mV[VZ] + (z - start.mV[VZ]) * part;
+ edge.vertices.emplace_back(new_x, new_y, new_z);
};
- auto checkForSplit = [&](U32 lod)
+ auto checkForSplit = [&]()
{
- const std::vector<LLVector4a>& vertices = edge.verticesUnderWater[lod];
- const LLVector4a& last_outside = vertices.back();
- F32 z0 = last_outside[VZ];
+ const LLVector3& last_outside = edge.vertices.back();
+ F32 z0 = last_outside.mV[VZ];
F32 z1 = outside_z;
if ((z0 >= water_z && z1 >= water_z) || (z0 < water_z && z1 < water_z))
return;
F32 part = (water_z - z0) / (z1 - z0);
- const LLVector4a& last_inside = vertices[vertices.size() - 2];
- split(lod, last_inside, inside_x, inside_y, inside_z, part);
- split(lod, last_outside, outside_x, outside_y, outside_z, part);
+ const LLVector3& last_inside = edge.vertices[edge.vertices.size() - 2];
+ split(last_inside, inside_x, inside_y, inside_z, part);
+ split(last_outside, outside_x, outside_y, outside_z, part);
};
- auto pushTwoVertices = [&](U32 lod)
- {
- LLVector3 out(outside_x, outside_y, outside_z);
- LLVector3 in(inside_x, inside_y, inside_z);
- if (fabs(inside_z - outside_z) < LINE_WIDTH / 5)
- {
- edge.pushVertex(lod, inside_x, inside_y, inside_z, water_z);
- }
- else
- {
- // Make the line thinner if heights differ too much
- LLVector3 dist(in - out);
- F32 coef = dist.length() / LINE_WIDTH;
- LLVector3 new_in(out + dist / coef);
- edge.pushVertex(lod, new_in[VX], new_in[VY], new_in[VZ], water_z);
- }
- edge.pushVertex(lod, outside_x, outside_y, outside_z, water_z);
- };
+ // First part, only one vertex
+ outside_z = land.resolveHeightRegion( outside_x, outside_y );
- // Point A simplified (first two vertices)
- pushTwoVertices(1);
+ edge.vertices.emplace_back(outside_x, outside_y, outside_z);
- // Point A detailized (only one vertex)
- edge.pushVertex(0, outside_x, outside_y, outside_z, water_z);
+ inside_x += dx * LINE_WIDTH;
+ inside_y += dy * LINE_WIDTH;
- // Point B (two vertices)
- move(LINE_WIDTH);
- pushTwoVertices(0);
+ outside_x += dx * LINE_WIDTH;
+ outside_y += dy * LINE_WIDTH;
- // Points C, D, E
- F32 distance = 1.f - LINE_WIDTH;
+ // Then the "actual edge"
+ inside_z = land.resolveHeightRegion( inside_x, inside_y );
+ outside_z = land.resolveHeightRegion( outside_x, outside_y );
+
+ edge.vertices.emplace_back(inside_x, inside_y, inside_z);
+ edge.vertices.emplace_back(outside_x, outside_y, outside_z);
+
+ inside_x += dx * (dx - LINE_WIDTH);
+ inside_y += dy * (dy - LINE_WIDTH);
+
+ outside_x += dx * (dx - LINE_WIDTH);
+ outside_y += dy * (dy - LINE_WIDTH);
+
+ // Middle part, full width
constexpr S32 GRID_STEP = (S32)PARCEL_GRID_STEP_METERS;
- for (U32 i = 1; i < GRID_STEP; ++i)
+ for (S32 i = 1; i < GRID_STEP; i++)
{
- move(distance);
- checkForSplit(0);
- pushTwoVertices(0);
- distance = 1.f;
+ inside_z = land.resolveHeightRegion( inside_x, inside_y );
+ outside_z = land.resolveHeightRegion( outside_x, outside_y );
+
+ checkForSplit();
+
+ edge.vertices.emplace_back(inside_x, inside_y, inside_z);
+ edge.vertices.emplace_back(outside_x, outside_y, outside_z);
+
+ inside_x += dx;
+ inside_y += dy;
+
+ outside_x += dx;
+ outside_y += dy;
}
- // Point F (two vertices)
- move(1.f - LINE_WIDTH);
- checkForSplit(0);
- pushTwoVertices(0);
+ // Extra buffer for edge
+ inside_x -= dx * LINE_WIDTH;
+ inside_y -= dy * LINE_WIDTH;
- // Point G simplified (last two vertices)
- move(LINE_WIDTH);
- pushTwoVertices(1);
+ outside_x -= dx * LINE_WIDTH;
+ outside_y -= dy * LINE_WIDTH;
- // Point G detailized (only one vertex)
- edge.pushVertex(0, outside_x, outside_y, outside_z, water_z);
-}
+ inside_z = land.resolveHeightRegion( inside_x, inside_y );
+ outside_z = land.resolveHeightRegion( outside_x, outside_y );
-void LLViewerParcelOverlay::Edge::pushVertex(U32 lod, F32 x, F32 y, F32 z, F32 water_z)
-{
- verticesUnderWater[lod].emplace_back(x, y, z);
- gGL.transform(verticesUnderWater[lod].back());
+ checkForSplit();
- if (z >= water_z)
- {
- verticesAboveWater[lod].push_back(verticesUnderWater[lod].back());
- }
- else
- {
- verticesAboveWater[lod].emplace_back(x, y, water_z);
- gGL.transform(verticesAboveWater[lod].back());
- }
+ edge.vertices.emplace_back(inside_x, inside_y, inside_z);
+ edge.vertices.emplace_back(outside_x, outside_y, outside_z);
+
+ outside_x += dx * LINE_WIDTH;
+ outside_y += dy * LINE_WIDTH;
+
+ // Last edge is not drawn to the edge
+ outside_z = land.resolveHeightRegion( outside_x, outside_y );
+
+ edge.vertices.emplace_back(outside_x, outside_y, outside_z);
}
void LLViewerParcelOverlay::setDirty()
@@ -687,9 +665,6 @@ void LLViewerParcelOverlay::renderPropertyLines()
if (!show)
return;
- LL_PROFILE_ZONE_SCOPED;
- LL_PROFILE_GPU_ZONE("Property Lines");
-
LLSurface& land = mRegion->getLand();
bool render_water = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER);
@@ -727,8 +702,6 @@ void LLViewerParcelOverlay::renderPropertyLines()
// Stomp the camera into two dimensions
LLVector3 camera_region = mRegion->getPosRegionFromGlobal( gAgentCamera.getCameraPositionGlobal() );
- bool draw_underwater = camera_region.mV[VZ] < water_z ||
- !gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER);
// Set up a cull plane 2 * PARCEL_GRID_STEP_METERS behind
// the camera. The cull plane normal is the camera's at axis.
@@ -736,23 +709,15 @@ void LLViewerParcelOverlay::renderPropertyLines()
cull_plane_point *= -2.f * PARCEL_GRID_STEP_METERS;
cull_plane_point += camera_region;
- bool render_hidden = !draw_underwater &&
- LLSelectMgr::sRenderHiddenSelections &&
- LLFloaterReg::instanceVisible("build");
+ bool render_hidden = LLSelectMgr::sRenderHiddenSelections && LLFloaterReg::instanceVisible("build");
constexpr F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f;
- const F32 PROPERTY_LINE_LOD0_DIST_SQUARED = PROPERTY_LINE_CLIP_DIST_SQUARED / 25;
for (const Edge& edge : mEdges)
{
- const std::vector<LLVector4a>& vertices0 = edge.verticesAboveWater[0];
- const F32* first = vertices0.front().getF32ptr();
- const F32* last = vertices0.back().getF32ptr();
- LLVector3 center((first[VX] + last[VX]) / 2, (first[VY] + last[VY]) / 2, (first[VZ] + last[VZ]) / 2);
- gGL.untransform(center);
+ LLVector3 center = edge.vertices[edge.vertices.size() >> 1];
- F32 dist_squared = dist_vec_squared(center, camera_region);
- if (dist_squared > PROPERTY_LINE_CLIP_DIST_SQUARED)
+ if (dist_vec_squared2D(center, camera_region) > PROPERTY_LINE_CLIP_DIST_SQUARED)
{
continue;
}
@@ -766,33 +731,43 @@ void LLViewerParcelOverlay::renderPropertyLines()
continue;
}
- U32 lod = dist_squared < PROPERTY_LINE_LOD0_DIST_SQUARED ? 0 : 1;
-
gGL.begin(LLRender::TRIANGLE_STRIP);
gGL.color4ubv(edge.color.mV);
- if (draw_underwater)
+ for (const LLVector3& vertex : edge.vertices)
{
- gGL.vertexBatchPreTransformed(edge.verticesUnderWater[lod]);
+ if (render_hidden || camera_z < water_z || vertex.mV[2] >= water_z)
+ {
+ gGL.vertex3fv(vertex.mV);
+ }
+ else
+ {
+ LLVector3 visible = vertex;
+ visible.mV[VZ] = water_z;
+ gGL.vertex3fv(visible.mV);
+ }
}
- else
+
+ gGL.end();
+
+ if (render_hidden)
{
- gGL.vertexBatchPreTransformed(edge.verticesAboveWater[lod]);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER);
- if (render_hidden)
- {
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER);
+ gGL.begin(LLRender::TRIANGLE_STRIP);
- LLColor4U color = edge.color;
- color.mV[VALPHA] /= 4;
- gGL.color4ubv(color.mV);
+ LLColor4U color = edge.color;
+ color.mV[VALPHA] /= 4;
+ gGL.color4ubv(color.mV);
- gGL.vertexBatchPreTransformed(edge.verticesUnderWater[lod]);
+ for (const LLVector3& vertex : edge.vertices)
+ {
+ gGL.vertex3fv(vertex.mV);
}
- }
- gGL.end();
+ gGL.end();
+ }
}
gGL.popMatrix();
diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h
index 7271c85701..50bef02ddf 100644
--- a/indra/newview/llviewerparceloverlay.h
+++ b/indra/newview/llviewerparceloverlay.h
@@ -116,10 +116,7 @@ private:
struct Edge
{
- void pushVertex(U32 lod, F32 x, F32 y, F32 z, F32 water_z);
- // LOD: 0 - detailized, 1 - simplified
- std::vector<LLVector4a> verticesAboveWater[2];
- std::vector<LLVector4a> verticesUnderWater[2];
+ std::vector<LLVector3> vertices;
LLColor4U color;
};
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index fd56a8d0c7..dd02cca50a 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -3305,6 +3305,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("SetDisplayName");
capabilityNames.append("SimConsoleAsync");
capabilityNames.append("SimulatorFeatures");
+ capabilityNames.append("SpatialVoiceModerationRequest");
capabilityNames.append("StartGroupProposal");
capabilityNames.append("TerrainNavMeshProperties");
capabilityNames.append("TextureStats");
@@ -3805,6 +3806,16 @@ std::string LLViewerRegion::getSimHostName()
return std::string("...");
}
+
+bool LLViewerRegion::isRegionWebRTCEnabled()
+{
+ if (mSimulatorFeaturesReceived && mSimulatorFeatures.has("VoiceServerType"))
+ {
+ return mSimulatorFeatures["VoiceServerType"].asString() == "webrtc";
+ }
+ return false;
+}
+
void LLViewerRegion::applyCacheMiscExtras(LLViewerObject* obj)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 974bc375b8..f1eb335582 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -424,6 +424,8 @@ public:
std::string getSimHostName();
+ bool isRegionWebRTCEnabled();
+
static bool isNewObjectCreationThrottleDisabled() {return sNewObjectCreationThrottle < 0;}
// rebuild reflection probe list
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 5193514fe8..6490fe76a2 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -62,7 +62,6 @@
#include "llsdserialize.h"
#include "llsdutil.h"
#include "llcorehttputil.h"
-#include "llvoicevivox.h"
#include "llinventorymodel.h"
#include "lluiusage.h"
#include "lltranslate.h"
@@ -263,6 +262,20 @@ LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > HUDS_FRAME_PCT("huds_
LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > UI_FRAME_PCT("ui_frame_pct");
LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > SWAP_FRAME_PCT("swap_frame_pct");
LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > IDLE_FRAME_PCT("idle_frame_pct");
+
+
+
+LLTrace::SampleStatHandle<U32> WEBRTC_PACKETS_IN_LOST("webrtc_packets_in_lost", "Lost incoming packets"),
+ WEBRTC_PACKETS_IN_RECEIVED("webrtc_packets_in_recv", "Incoming packets received"),
+ WEBRTC_PACKETS_OUT_SENT("webrtc_packets_out_sent", "Outgoing packets sent"),
+ WEBRTC_PACKETS_OUT_LOST("webrtc_packets_out_lost", "Lost outgoing packets");
+
+LLTrace::SampleStatHandle<F32> WEBRTC_JITTER_OUT("webrtc_jitter_out", "Timing variation of outgoing audio"),
+ WEBRTC_JITTER_IN("webrtc_jitter_in", "Timing variation of incoming audio"),
+ WEBRTC_LATENCY("webrtc_latency", "Round-trip audio delay"),
+ WEBRTC_UPLOAD_BANDWIDTH("webrtc_upload_bandwidth", "Estimated upload bandwidth"),
+ WEBRTC_JITTER_BUFFER("webrtc_jitter_buffer", "Average delay added to smooth incoming audio");
+
}
LLViewerStats::LLViewerStats()
@@ -796,8 +809,6 @@ void send_viewer_stats(bool include_preferences)
body["ui"] = LLUIUsage::instance().asLLSD();
- body["stats"]["voice"] = LLVoiceVivoxStats::getInstance()->read();
-
// Misc stats, two strings and two ints
// These are not expecticed to persist across multiple releases
// Comment any changes with your name and the expected release revision
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index 1ac8b2f66b..8ec0dd0024 100644
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -232,6 +232,9 @@ extern LLTrace::EventStatHandle<LLUnit<F32, LLUnits::Percent> > OBJECT_CACHE_HIT
extern LLTrace::SampleStatHandle<F64> NOTRMALIZED_FRAMETIME_JITTER_SESSION;
extern LLTrace::SampleStatHandle<F64> NORMALIZED_FRAMTIME_JITTER_PERIOD;
+extern LLTrace::SampleStatHandle<U32> WEBRTC_PACKETS_IN_LOST, WEBRTC_PACKETS_IN_RECEIVED, WEBRTC_PACKETS_OUT_SENT, WEBRTC_PACKETS_OUT_LOST;
+extern LLTrace::SampleStatHandle<F32> WEBRTC_JITTER_OUT, WEBRTC_JITTER_IN, WEBRTC_LATENCY, WEBRTC_UPLOAD_BANDWIDTH, WEBRTC_JITTER_BUFFER;
+
}
class LLViewerStats : public LLSingleton<LLViewerStats>
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index e4fd947892..7dd32074cf 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -1014,6 +1014,38 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
}
imagep->addTextureStats(max_vsize);
+
+ // Derive stream priority channel from face lists.
+ // Map render texture channels to priority channels:
+ // 0 = normal, 1 = diffuse, 2 = specular, 3 = emissive
+ {
+ static const S32 render_to_priority[] = {
+ 1, // DIFFUSE_MAP (0)
+ 0, // NORMAL_MAP / ALTERNATE_DIFFUSE_MAP (1)
+ 2, // SPECULAR_MAP (2)
+ 1, // BASECOLOR_MAP (3)
+ 2, // METALLIC_ROUGHNESS_MAP (4)
+ 0, // GLTF_NORMAL_MAP (5)
+ 3, // EMISSIVE_MAP (6)
+ };
+
+ S32 priority_channel = 1; // default to diffuse
+ for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
+ {
+ if (imagep->getNumFaces(i) > 0)
+ {
+ priority_channel = llmin(priority_channel, render_to_priority[i]);
+ }
+ }
+
+ static LLCachedControl<LLVector4> channel_priority(gSavedSettings, "TextureChannelPriority",
+ LLVector4(10.0f, 20.0f, 40.0f, 20.0f));
+ F32 factor = llmax(channel_priority().mV[priority_channel], 0.1f);
+ if (factor != 1.0f)
+ {
+ imagep->mMaxVirtualSize /= factor;
+ }
+ }
}
#if 0
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 369a887102..dbf9fe6bf2 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2351,14 +2351,22 @@ void LLViewerWindow::initWorldUI()
physical_mem = LLMemory::getMaxMemKB();
}
- if (!gNonInteractive && physical_mem > MIN_PHYSICAL_MEMORY)
+ if (!gNonInteractive)
{
- LL_INFOS() << "Preloading cef instances" << LL_ENDL;
+ if (physical_mem > MIN_PHYSICAL_MEMORY)
+ {
+ LL_INFOS() << "Preloading cef instances" << LL_ENDL;
- LLFloaterReg::getInstance("destinations");
- LLFloaterReg::getInstance("avatar_welcome_pack");
- LLFloaterReg::getInstance("search");
- LLFloaterReg::getInstance("marketplace");
+ LLFloaterReg::getInstance("destinations");
+ LLFloaterReg::getInstance("avatar_welcome_pack");
+ LLFloaterReg::getInstance("search");
+ LLFloaterReg::getInstance("marketplace");
+ }
+ else if (gSavedSettings.getBOOL("FirstLoginThisInstall"))
+ {
+ // Preload the welcome pack for first-time login even on low end hardware
+ LLFloaterReg::getInstance("avatar_welcome_pack");
+ }
}
}
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 71a9e71a9f..53d82ff989 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -25,7 +25,6 @@
*/
#include "llvoiceclient.h"
-#include "llvoicevivox.h"
#include "llvoicewebrtc.h"
#include "llviewernetwork.h"
#include "llviewercontrol.h"
@@ -39,6 +38,7 @@
#include "llagent.h"
#include "lltrans.h"
#include "lluiusage.h"
+#include "llnearbyvoicemoderation.h"
const F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f;
@@ -116,11 +116,7 @@ std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserv
LLVoiceModuleInterface *getVoiceModule(const std::string &voice_server_type)
{
- if (voice_server_type == VIVOX_VOICE_SERVER_TYPE || voice_server_type.empty())
- {
- return (LLVoiceModuleInterface *) LLVivoxVoiceClient::getInstance();
- }
- else if (voice_server_type == WEBRTC_VOICE_SERVER_TYPE)
+ if (voice_server_type == WEBRTC_VOICE_SERVER_TYPE)
{
return (LLVoiceModuleInterface *) LLWebRTCVoiceClient::getInstance();
}
@@ -166,7 +162,6 @@ void LLVoiceClient::init(LLPumpIO *pump)
// Initialize all of the voice modules
m_servicePump = pump;
LLWebRTCVoiceClient::getInstance()->init(pump);
- LLVivoxVoiceClient::getInstance()->init(pump);
}
void LLVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &agentID)
@@ -177,7 +172,6 @@ void LLVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &age
}
mRegionChangedCallbackSlot = gAgent.addRegionChangedCallback(boost::bind(&LLVoiceClient::onRegionChanged, this));
LLWebRTCVoiceClient::getInstance()->userAuthorized(user_id, agentID);
- LLVivoxVoiceClient::getInstance()->userAuthorized(user_id, agentID);
}
void LLVoiceClient::handleSimulatorFeaturesReceived(const LLSD &simulatorFeatures)
@@ -185,7 +179,7 @@ void LLVoiceClient::handleSimulatorFeaturesReceived(const LLSD &simulatorFeature
std::string voiceServerType = simulatorFeatures["VoiceServerType"].asString();
if (voiceServerType.empty())
{
- voiceServerType = VIVOX_VOICE_SERVER_TYPE;
+ voiceServerType = WEBRTC_VOICE_SERVER_TYPE;
}
if (mSpatialVoiceModule && !mNonSpatialVoiceModule)
@@ -287,19 +281,14 @@ void LLVoiceClient::setHidden(bool hidden)
{
LL_INFOS("Voice") << "( " << (hidden ? "true" : "false") << " )" << LL_ENDL;
LLWebRTCVoiceClient::getInstance()->setHidden(hidden);
- LLVivoxVoiceClient::getInstance()->setHidden(hidden);
}
void LLVoiceClient::terminate()
{
- if (LLVivoxVoiceClient::instanceExists())
+ if (LLWebRTCVoiceClient::instanceExists())
{
LLWebRTCVoiceClient::getInstance()->terminate();
}
- if (LLVivoxVoiceClient::instanceExists())
- {
- LLVivoxVoiceClient::getInstance()->terminate();
- }
mSpatialVoiceModule = NULL;
m_servicePump = NULL;
@@ -335,7 +324,6 @@ void LLVoiceClient::updateSettings()
updateMicMuteLogic();
LLWebRTCVoiceClient::getInstance()->updateSettings();
- LLVivoxVoiceClient::getInstance()->updateSettings();
}
//--------------------------------------------------
@@ -344,13 +332,11 @@ void LLVoiceClient::updateSettings()
void LLVoiceClient::tuningStart()
{
LLWebRTCVoiceClient::getInstance()->tuningStart();
- LLVivoxVoiceClient::getInstance()->tuningStart();
}
void LLVoiceClient::tuningStop()
{
LLWebRTCVoiceClient::getInstance()->tuningStop();
- LLVivoxVoiceClient::getInstance()->tuningStop();
}
bool LLVoiceClient::inTuningMode()
@@ -393,13 +379,11 @@ void LLVoiceClient::refreshDeviceLists(bool clearCurrentList)
void LLVoiceClient::setCaptureDevice(const std::string& name)
{
- LLVivoxVoiceClient::getInstance()->setCaptureDevice(name);
LLWebRTCVoiceClient::getInstance()->setCaptureDevice(name);
}
void LLVoiceClient::setRenderDevice(const std::string& name)
{
- LLVivoxVoiceClient::getInstance()->setRenderDevice(name);
LLWebRTCVoiceClient::getInstance()->setRenderDevice(name);
}
@@ -421,13 +405,11 @@ const LLVoiceDeviceList& LLVoiceClient::getRenderDevices()
void LLVoiceClient::getParticipantList(std::set<LLUUID> &participants) const
{
LLWebRTCVoiceClient::getInstance()->getParticipantList(participants);
- LLVivoxVoiceClient::getInstance()->getParticipantList(participants);
}
bool LLVoiceClient::isParticipant(const LLUUID &speaker_id) const
{
- return LLWebRTCVoiceClient::getInstance()->isParticipant(speaker_id) ||
- LLVivoxVoiceClient::getInstance()->isParticipant(speaker_id);
+ return LLWebRTCVoiceClient::getInstance()->isParticipant(speaker_id);
}
@@ -519,14 +501,12 @@ void LLVoiceClient::activateSpatialChannel(bool activate)
bool LLVoiceClient::isCurrentChannel(const LLSD& channelInfo)
{
- return LLWebRTCVoiceClient::getInstance()->isCurrentChannel(channelInfo) ||
- LLVivoxVoiceClient::getInstance()->isCurrentChannel(channelInfo);
+ return LLWebRTCVoiceClient::getInstance()->isCurrentChannel(channelInfo);
}
bool LLVoiceClient::compareChannels(const LLSD &channelInfo1, const LLSD &channelInfo2)
{
- return LLWebRTCVoiceClient::getInstance()->compareChannels(channelInfo1, channelInfo2) ||
- LLVivoxVoiceClient::getInstance()->compareChannels(channelInfo1, channelInfo2);
+ return LLWebRTCVoiceClient::getInstance()->compareChannels(channelInfo1, channelInfo2);
}
LLVoiceP2PIncomingCallInterfacePtr LLVoiceClient::getIncomingCallInterface(const LLSD& voice_call_info)
@@ -554,8 +534,8 @@ LLVoiceP2POutgoingCallInterface *LLVoiceClient::getOutgoingCallInterface(const L
if (voiceChannelInfo.has("voice_server_type") && voiceChannelInfo["voice_server_type"] != voice_server_type)
{
// there's a mismatch between what the peer is offering and what our server
- // can handle, so downgrade to vivox
- voice_server_type = VIVOX_VOICE_SERVER_TYPE;
+ // can handle, so default to webrtc
+ voice_server_type = WEBRTC_VOICE_SERVER_TYPE;
}
LLVoiceModuleInterface *module = getVoiceModule(voice_server_type);
return dynamic_cast<LLVoiceP2POutgoingCallInterface *>(module);
@@ -568,13 +548,11 @@ LLVoiceP2POutgoingCallInterface *LLVoiceClient::getOutgoingCallInterface(const L
void LLVoiceClient::setVoiceVolume(F32 volume)
{
LLWebRTCVoiceClient::getInstance()->setVoiceVolume(volume);
- LLVivoxVoiceClient::getInstance()->setVoiceVolume(volume);
}
void LLVoiceClient::setMicGain(F32 gain)
{
LLWebRTCVoiceClient::getInstance()->setMicGain(gain);
- LLVivoxVoiceClient::getInstance()->setMicGain(gain);
}
@@ -624,10 +602,6 @@ void LLVoiceClient::setVoiceEnabled(bool enabled)
{
LLWebRTCVoiceClient::getInstance()->setVoiceEnabled(enabled);
}
- if (LLVivoxVoiceClient::instanceExists())
- {
- LLVivoxVoiceClient::getInstance()->setVoiceEnabled(enabled);
- }
}
void LLVoiceClient::updateMicMuteLogic()
@@ -647,7 +621,6 @@ void LLVoiceClient::updateMicMuteLogic()
new_mic_mute = true;
}
LLWebRTCVoiceClient::getInstance()->setMuteMic(new_mic_mute);
- LLVivoxVoiceClient::getInstance()->setMuteMic(new_mic_mute);
}
void LLVoiceClient::setMuteMic(bool muted)
@@ -668,6 +641,9 @@ void LLVoiceClient::setUserPTTState(bool ptt)
{
if (ptt)
{
+ // Nearby chat is muted by moderator, don't toggle PTT
+ if (!mUserPTTState && LLNearbyVoiceModeration::getInstance()->showNotificationIfNeeded())
+ return;
LLUIUsage::instance().logCommand("Agent.EnableMicrophone");
}
mUserPTTState = ptt;
@@ -742,17 +718,12 @@ bool LLVoiceClient::getVoiceEnabled(const LLUUID& id) const
std::string LLVoiceClient::getDisplayName(const LLUUID& id) const
{
std::string result = LLWebRTCVoiceClient::getInstance()->getDisplayName(id);
- if (result.empty())
- {
- result = LLVivoxVoiceClient::getInstance()->getDisplayName(id);
- }
return result;
}
bool LLVoiceClient::isVoiceWorking() const
{
- return LLVivoxVoiceClient::getInstance()->isVoiceWorking() ||
- LLWebRTCVoiceClient::getInstance()->isVoiceWorking();
+ return LLWebRTCVoiceClient::getInstance()->isVoiceWorking();
}
bool LLVoiceClient::isParticipantAvatar(const LLUUID& id)
@@ -767,22 +738,19 @@ bool LLVoiceClient::isOnlineSIP(const LLUUID& id)
bool LLVoiceClient::getIsSpeaking(const LLUUID& id)
{
- return LLWebRTCVoiceClient::getInstance()->getIsSpeaking(id) ||
- LLVivoxVoiceClient::getInstance()->getIsSpeaking(id);
+ return LLWebRTCVoiceClient::getInstance()->getIsSpeaking(id);
}
bool LLVoiceClient::getIsModeratorMuted(const LLUUID& id)
{
// don't bother worrying about p2p calls, as
// p2p calls don't have mute.
- return LLWebRTCVoiceClient::getInstance()->getIsModeratorMuted(id) ||
- LLVivoxVoiceClient::getInstance()->getIsModeratorMuted(id);
+ return LLWebRTCVoiceClient::getInstance()->getIsModeratorMuted(id);
}
F32 LLVoiceClient::getCurrentPower(const LLUUID& id)
{
- return std::fmax(LLVivoxVoiceClient::getInstance()->getCurrentPower(id),
- LLWebRTCVoiceClient::getInstance()->getCurrentPower(id));
+ return LLWebRTCVoiceClient::getInstance()->getCurrentPower(id);
}
bool LLVoiceClient::getOnMuteList(const LLUUID& id)
@@ -794,13 +762,12 @@ bool LLVoiceClient::getOnMuteList(const LLUUID& id)
F32 LLVoiceClient::getUserVolume(const LLUUID& id)
{
- return std::fmax(LLVivoxVoiceClient::getInstance()->getUserVolume(id), LLWebRTCVoiceClient::getInstance()->getUserVolume(id));
+ return LLWebRTCVoiceClient::getInstance()->getUserVolume(id);
}
void LLVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
{
LLWebRTCVoiceClient::getInstance()->setUserVolume(id, volume);
- LLVivoxVoiceClient::getInstance()->setUserVolume(id, volume);
}
//--------------------------------------------------
@@ -808,16 +775,11 @@ void LLVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
void LLVoiceClient::addObserver(LLVoiceClientStatusObserver* observer)
{
- LLVivoxVoiceClient::getInstance()->addObserver(observer);
LLWebRTCVoiceClient::getInstance()->addObserver(observer);
}
void LLVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer)
{
- if (LLVivoxVoiceClient::instanceExists())
- {
- LLVivoxVoiceClient::getInstance()->removeObserver(observer);
- }
if (LLWebRTCVoiceClient::instanceExists())
{
LLWebRTCVoiceClient::getInstance()->removeObserver(observer);
@@ -826,16 +788,11 @@ void LLVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer)
void LLVoiceClient::addObserver(LLFriendObserver* observer)
{
- LLVivoxVoiceClient::getInstance()->addObserver(observer);
LLWebRTCVoiceClient::getInstance()->addObserver(observer);
}
void LLVoiceClient::removeObserver(LLFriendObserver* observer)
{
- if (LLVivoxVoiceClient::instanceExists())
- {
- LLVivoxVoiceClient::getInstance()->removeObserver(observer);
- }
if (LLWebRTCVoiceClient::instanceExists())
{
LLWebRTCVoiceClient::getInstance()->removeObserver(observer);
@@ -844,38 +801,17 @@ void LLVoiceClient::removeObserver(LLFriendObserver* observer)
void LLVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)
{
- LLVivoxVoiceClient::getInstance()->addObserver(observer);
LLWebRTCVoiceClient::getInstance()->addObserver(observer);
}
void LLVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer)
{
- if (LLVivoxVoiceClient::instanceExists())
- {
- LLVivoxVoiceClient::getInstance()->removeObserver(observer);
- }
if (LLWebRTCVoiceClient::instanceExists())
{
LLWebRTCVoiceClient::getInstance()->removeObserver(observer);
}
}
-std::string LLVoiceClient::sipURIFromID(const LLUUID &id) const
-{
- if (mNonSpatialVoiceModule)
- {
- return mNonSpatialVoiceModule->sipURIFromID(id);
- }
- else if (mSpatialVoiceModule)
- {
- return mSpatialVoiceModule->sipURIFromID(id);
- }
- else
- {
- return std::string();
- }
-}
-
LLSD LLVoiceClient::getP2PChannelInfoTemplate(const LLUUID& id) const
{
if (mNonSpatialVoiceModule)
@@ -908,7 +844,7 @@ class LLViewerRequiredVoiceVersion : public LLHTTPNode
const LLSD& context,
const LLSD& input) const
{
- std::string voice_server_type = "vivox";
+ std::string voice_server_type = "webrtc";
if (input.has("body") && input["body"].has("voice_server_type"))
{
voice_server_type = input["body"]["voice_server_type"].asString();
@@ -916,11 +852,7 @@ class LLViewerRequiredVoiceVersion : public LLHTTPNode
LLVoiceModuleInterface *voiceModule = NULL;
- if (voice_server_type == "vivox" || voice_server_type.empty())
- {
- voiceModule = (LLVoiceModuleInterface *) LLVivoxVoiceClient::getInstance();
- }
- else if (voice_server_type == "webrtc")
+ if (voice_server_type == "webrtc" || voice_server_type.empty())
{
voiceModule = (LLVoiceModuleInterface *) LLWebRTCVoiceClient::getInstance();
}
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index 788ea3b3b3..70bce055f9 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -106,7 +106,7 @@ struct LLVoiceVersionInfo
/// @class LLVoiceP2POutgoingCallInterface
/// @brief Outgoing call interface
///
-/// For providers that support P2P signaling (vivox)
+/// For providers that support P2P signaling
/////////////////////////////////
class LLVoiceP2POutgoingCallInterface
@@ -121,7 +121,7 @@ class LLVoiceP2POutgoingCallInterface
/// @class LLVoiceP2PIncomingCallInterface
/// @brief Incoming call interface
///
-/// For providers that support P2P signaling (vivox)
+/// For providers that support P2P signaling
/////////////////////////////////
class LLVoiceP2PIncomingCallInterface
{
@@ -180,7 +180,6 @@ public:
virtual bool deviceSettingsAvailable()=0;
virtual bool deviceSettingsUpdated() = 0;
- // Requery the vivox daemon for the current list of input/output devices.
// If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed
// (use this if you want to know when it's done).
// If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim.
@@ -280,7 +279,6 @@ public:
virtual void removeObserver(LLVoiceClientParticipantObserver* observer)=0;
//@}
- virtual std::string sipURIFromID(const LLUUID &id) const=0;
virtual LLSD getP2PChannelInfoTemplate(const LLUUID& id) const=0;
//@}
@@ -384,7 +382,7 @@ public:
bool deviceSettingsAvailable();
bool deviceSettingsUpdated(); // returns true when the device list has been updated recently.
- // Requery the vivox daemon for the current list of input/output devices.
+ // Requery the voice driver for the current list of input/output devices.
// If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed
// (use this if you want to know when it's done).
// If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim.
@@ -488,7 +486,6 @@ public:
static void addObserver(LLVoiceClientParticipantObserver* observer);
static void removeObserver(LLVoiceClientParticipantObserver* observer);
- std::string sipURIFromID(const LLUUID &id) const;
LLSD getP2PChannelInfoTemplate(const LLUUID& id) const;
//////////////////////////
@@ -513,7 +510,7 @@ protected:
LLVoiceModuleInterface* mSpatialVoiceModule;
LLVoiceModuleInterface* mNonSpatialVoiceModule;
- LLSD mSpatialCredentials; // used to store spatial credentials for vivox
+ LLSD mSpatialCredentials; // used to store spatial credentials for the voice subsystem
// so they're available when the region voice
// server is retrieved.
LLPumpIO *m_servicePump;
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
deleted file mode 100644
index 107a08fdf8..0000000000
--- a/indra/newview/llvoicevivox.cpp
+++ /dev/null
@@ -1,7926 +0,0 @@
- /**
- * @file LLVivoxVoiceClient.cpp
- * @brief Implementation of LLVivoxVoiceClient class which is the interface to the voice client process.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include <algorithm>
-#include "llvoicevivox.h"
-
-#include "llsdutil.h"
-
-// Linden library includes
-#include "llavatarnamecache.h"
-#include "llvoavatarself.h"
-#include "llbufferstream.h"
-#include "llfile.h"
-#include "llmenugl.h"
-#ifdef LL_USESYSTEMLIBS
-# include "expat.h"
-#else
-# include "expat/expat.h"
-#endif
-#include "llcallbacklist.h"
-#include "llviewerregion.h"
-#include "llviewernetwork.h" // for gGridChoice
-#include "llbase64.h"
-#include "llviewercontrol.h"
-#include "llappviewer.h" // for gDisconnected, gDisableVoice
-#include "llprocess.h"
-
-// Viewer includes
-#include "llmutelist.h" // to check for muted avatars
-#include "llagent.h"
-#include "llcachename.h"
-#include "llimview.h" // for LLIMMgr
-#include "llparcel.h"
-#include "llviewerparcelmgr.h"
-#include "llfirstuse.h"
-#include "llspeakers.h"
-#include "lltrans.h"
-#include "llviewerwindow.h"
-#include "llviewercamera.h"
-#include "llversioninfo.h"
-
-#include "llviewernetwork.h"
-#include "llnotificationsutil.h"
-
-#include "llcorehttputil.h"
-#include "lleventfilter.h"
-
-#include "stringize.h"
-
-// for base64 decoding
-#include "apr_base64.h"
-
-#define USE_SESSION_GROUPS 0
-#define VX_NULL_POSITION -2147483648.0 /*The Silence*/
-
-extern LLMenuBarGL* gMenuBarView;
-extern void handle_voice_morphing_subscribe();
-
-const std::string VIVOX_VOICE_SERVER_TYPE = "vivox";
-
-namespace {
- const F32 VOLUME_SCALE_VIVOX = 0.01f;
-
- const F32 SPEAKING_TIMEOUT = 1.f;
-
- static const std::string VISIBLE_VOICE_SERVER_TYPE = "Vivox";
-
- // Don't retry connecting to the daemon more frequently than this:
- const F32 DAEMON_CONNECT_THROTTLE_SECONDS = 1.0f;
- const int DAEMON_CONNECT_RETRY_MAX = 3;
-
- // Don't send positional updates more frequently than this:
- const F32 UPDATE_THROTTLE_SECONDS = 0.5f;
-
- // Timeout for connection to Vivox
- const F32 CONNECT_ATTEMPT_TIMEOUT = 300.0f;
- const F32 CONNECT_DNS_TIMEOUT = 5.0f;
- const int CONNECT_RETRY_MAX = 3;
-
- const F32 LOGIN_ATTEMPT_TIMEOUT = 30.0f;
- const F32 LOGOUT_ATTEMPT_TIMEOUT = 5.0f;
- const int LOGIN_RETRY_MAX = 3;
-
- const F32 PROVISION_RETRY_TIMEOUT = 2.0;
- const int PROVISION_RETRY_MAX = 5;
-
- // Cosine of a "trivially" small angle
- const F32 FOUR_DEGREES = 4.0f * (F_PI / 180.0f);
- const F32 MINUSCULE_ANGLE_COS = (F32) cos(0.5f * FOUR_DEGREES);
-
- const F32 SESSION_JOIN_TIMEOUT = 30.0f;
-
- // Defines the maximum number of times(in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine()
- // which is treated as normal. The is the number of frames to wait for a channel join before giving up. This was changed
- // from the original count of 50 for two reason. Modern PCs have higher frame rates and sometimes the SLVoice process
- // backs up processing join requests. There is a log statement that records when channel joins take longer than 100 frames.
- const int MAX_NORMAL_JOINING_SPATIAL_NUM = 1500;
-
- // How often to check for expired voice fonts in seconds
- const F32 VOICE_FONT_EXPIRY_INTERVAL = 10.f;
- // Time of day at which Vivox expires voice font subscriptions.
- // Used to replace the time portion of received expiry timestamps.
- static const std::string VOICE_FONT_EXPIRY_TIME = "T05:00:00Z";
-
- // Maximum length of capture buffer recordings in seconds.
- const F32 CAPTURE_BUFFER_MAX_TIME = 10.f;
-
- const int ERROR_VIVOX_OBJECT_NOT_FOUND = 1001;
- const int ERROR_VIVOX_NOT_LOGGED_IN = 1007;
-}
-
-static int scale_mic_volume(float volume)
-{
- // incoming volume has the range [0.0 ... 2.0], with 1.0 as the default.
- // Map it to Vivox levels as follows: 0.0 -> 30, 1.0 -> 50, 2.0 -> 70
- return 30 + (int)(volume * 20.0f);
-}
-
-static int scale_speaker_volume(float volume)
-{
- // incoming volume has the range [0.0 ... 1.0], with 0.5 as the default.
- // Map it to Vivox levels as follows: 0.0 -> 30, 0.5 -> 50, 1.0 -> 70
- return 30 + (int)(volume * 40.0f);
-
-}
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-class LLVivoxVoiceClientMuteListObserver : public LLMuteListObserver
-{
- /* virtual */ void onChange() { LLVivoxVoiceClient::getInstance()->muteListChanged();}
-};
-
-
-void LLVoiceVivoxStats::reset()
-{
- mStartTime = -1.0f;
- mConnectCycles = 0;
- mConnectTime = -1.0f;
- mConnectAttempts = 0;
- mProvisionTime = -1.0f;
- mProvisionAttempts = 0;
- mEstablishTime = -1.0f;
- mEstablishAttempts = 0;
-}
-
-LLVoiceVivoxStats::LLVoiceVivoxStats()
-{
- reset();
-}
-
-LLVoiceVivoxStats::~LLVoiceVivoxStats()
-{
-}
-
-void LLVoiceVivoxStats::connectionAttemptStart()
-{
- if (!mConnectAttempts)
- {
- mStartTime = LLTimer::getTotalTime();
- mConnectCycles++;
- }
- mConnectAttempts++;
-}
-
-void LLVoiceVivoxStats::connectionAttemptEnd(bool success)
-{
- if ( success )
- {
- mConnectTime = (LLTimer::getTotalTime() - mStartTime) / USEC_PER_SEC;
- }
-}
-
-void LLVoiceVivoxStats::provisionAttemptStart()
-{
- if (!mProvisionAttempts)
- {
- mStartTime = LLTimer::getTotalTime();
- }
- mProvisionAttempts++;
-}
-
-void LLVoiceVivoxStats::provisionAttemptEnd(bool success)
-{
- if ( success )
- {
- mProvisionTime = (LLTimer::getTotalTime() - mStartTime) / USEC_PER_SEC;
- }
-}
-
-void LLVoiceVivoxStats::establishAttemptStart()
-{
- if (!mEstablishAttempts)
- {
- mStartTime = LLTimer::getTotalTime();
- }
- mEstablishAttempts++;
-}
-
-void LLVoiceVivoxStats::establishAttemptEnd(bool success)
-{
- if ( success )
- {
- mEstablishTime = (LLTimer::getTotalTime() - mStartTime) / USEC_PER_SEC;
- }
-}
-
-LLSD LLVoiceVivoxStats::read()
-{
- LLSD stats(LLSD::emptyMap());
-
- stats["connect_cycles"] = LLSD::Integer(mConnectCycles);
- stats["connect_attempts"] = LLSD::Integer(mConnectAttempts);
- stats["connect_time"] = LLSD::Real(mConnectTime);
-
- stats["provision_attempts"] = LLSD::Integer(mProvisionAttempts);
- stats["provision_time"] = LLSD::Real(mProvisionTime);
-
- stats["establish_attempts"] = LLSD::Integer(mEstablishAttempts);
- stats["establish_time"] = LLSD::Real(mEstablishTime);
-
- return stats;
-}
-
-static LLVivoxVoiceClientMuteListObserver mutelist_listener;
-static bool sMuteListListener_listening = false;
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-static LLProcessPtr sGatewayPtr;
-static LLEventStream sGatewayPump("VivoxDaemonPump", true);
-
-static bool isGatewayRunning()
-{
- return sGatewayPtr && sGatewayPtr->isRunning();
-}
-
-static void killGateway()
-{
- if (sGatewayPtr)
- {
- LL_DEBUGS("Voice") << "SLVoice " << sGatewayPtr->getStatusString() << LL_ENDL;
-
- sGatewayPump.stopListening("VivoxDaemonPump");
- sGatewayPtr->kill(__FUNCTION__);
- sGatewayPtr=NULL;
- }
- else
- {
- LL_DEBUGS("Voice") << "no gateway" << LL_ENDL;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-bool LLVivoxVoiceClient::sShuttingDown = false;
-bool LLVivoxVoiceClient::sConnected = false;
-LLPumpIO *LLVivoxVoiceClient::sPump = nullptr;
-
-LLVivoxVoiceClient::LLVivoxVoiceClient() :
- mWriteOffset(0),
- mHidden(true),
- mSessionTerminateRequested(false),
- mRelogRequested(false),
- mTerminateDaemon(false),
- mSpatialJoiningNum(0),
-
- mTuningMode(false),
- mTuningEnergy(0.0f),
- mTuningMicVolume(0),
- mTuningMicVolumeDirty(true),
- mTuningSpeakerVolume(50), // Set to 50 so the user can hear himself when he sets his mic volume
- mTuningSpeakerVolumeDirty(true),
- mDevicesListUpdated(false),
-
- mAudioSession(), // TBD - should be NULL
- mNextAudioSession(),
-
- mCurrentParcelLocalID(0),
- mConnectorEstablished(false),
- mAccountLoggedIn(false),
- mNumberOfAliases(0),
- mCommandCookie(0),
- mLoginRetryCount(0),
-
- mBuddyListMapPopulated(false),
- mBlockRulesListReceived(false),
- mAutoAcceptRulesListReceived(false),
-
- mCaptureDeviceDirty(false),
- mRenderDeviceDirty(false),
- mSpatialCoordsDirty(false),
- mIsInitialized(false),
-
- mMuteMic(false),
- mMuteMicDirty(false),
- mFriendsListDirty(true),
-
- mEarLocation(0),
- mSpeakerVolumeDirty(true),
- mSpeakerMuteDirty(true),
- mMicVolume(0),
- mMicVolumeDirty(true),
-
- mVoiceEnabled(false),
- mProcessChannels(false),
- mWriteInProgress(false),
-
- mVoiceFontsReceived(false),
- mVoiceFontsNew(false),
- mVoiceFontListDirty(false),
-
- mCaptureBufferMode(false),
- mCaptureBufferRecording(false),
- mCaptureBufferRecorded(false),
- mCaptureBufferPlaying(false),
- mShutdownComplete(true),
- mPlayRequestCount(0),
-
- mAvatarNameCacheConnection(),
- mIsInTuningMode(false),
- mIsInChannel(false),
- mIsJoiningSession(false),
- mIsWaitingForFonts(false),
- mIsLoggingIn(false),
- mIsLoggedIn(false),
- mIsProcessingChannels(false),
- mIsCoroutineActive(false),
- mVivoxPump("vivoxClientPump")
-{
- sShuttingDown = false;
- sConnected = false;
- sPump = nullptr;
-
- mSpeakerVolume = scale_speaker_volume(0);
-
- mVoiceVersion.serverVersion = "";
- mVoiceVersion.voiceServerType = VISIBLE_VOICE_SERVER_TYPE;
- mVoiceVersion.internalVoiceServerType = VIVOX_VOICE_SERVER_TYPE;
- mVoiceVersion.majorVersion = 1;
- mVoiceVersion.minorVersion = 0;
- mVoiceVersion.mBuildVersion = "";
- mVoiceVersion.serverVersion = "";
-
- // gMuteListp isn't set up at this point, so we defer this until later.
-// gMuteListp->addObserver(&mutelist_listener);
-
-
-#if LL_DARWIN || LL_LINUX
- // HACK: THIS DOES NOT BELONG HERE
- // When the vivox daemon dies, the next write attempt on our socket generates a SIGPIPE, which kills us.
- // This should cause us to ignore SIGPIPE and handle the error through proper channels.
- // This should really be set up elsewhere. Where should it go?
- signal(SIGPIPE, SIG_IGN);
-
- // Since we're now launching the gateway with fork/exec instead of system(), we need to deal with zombie processes.
- // Ignoring SIGCHLD should prevent zombies from being created. Alternately, we could use wait(), but I'd rather not do that.
- signal(SIGCHLD, SIG_IGN);
-#endif
-
-
- gIdleCallbacks.addFunction(idle, this);
-}
-
-//---------------------------------------------------
-
-LLVivoxVoiceClient::~LLVivoxVoiceClient()
-{
- if (mAvatarNameCacheConnection.connected())
- {
- mAvatarNameCacheConnection.disconnect();
- }
- sShuttingDown = true;
-}
-
-//---------------------------------------------------
-
-void LLVivoxVoiceClient::init(LLPumpIO *pump)
-{
- // constructor will set up LLVoiceClient::getInstance()
- sPump = pump;
-
-// LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro",
-// boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance()));
-
-}
-
-void LLVivoxVoiceClient::terminate()
-{
- if (sShuttingDown)
- {
- return;
- }
-
- // needs to be done manually here since we will not get another pass in
- // coroutines... that mechanism is long since gone.
- if (mIsLoggedIn)
- {
- logoutOfVivox(false);
- }
-
- if(sConnected)
- {
- breakVoiceConnection(false);
- sConnected = false;
- }
- else
- {
- mRelogRequested = false;
- killGateway();
- }
-
- sShuttingDown = true;
- sPump = NULL;
-}
-
-//---------------------------------------------------
-
-void LLVivoxVoiceClient::cleanUp()
-{
- LL_DEBUGS("Voice") << LL_ENDL;
-
- deleteAllSessions();
- deleteAllVoiceFonts();
- deleteVoiceFontTemplates();
- LL_DEBUGS("Voice") << "exiting" << LL_ENDL;
-}
-
-//---------------------------------------------------
-
-const LLVoiceVersionInfo& LLVivoxVoiceClient::getVersion()
-{
- return mVoiceVersion;
-}
-
-//---------------------------------------------------
-
-void LLVivoxVoiceClient::updateSettings()
-{
- setVoiceEnabled(LLVoiceClient::getInstance()->voiceEnabled());
- setEarLocation(gSavedSettings.getS32("VoiceEarLocation"));
-
- std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
- setCaptureDevice(inputDevice);
- std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
- setRenderDevice(outputDevice);
- F32 mic_level = gSavedSettings.getF32("AudioLevelMic");
- setMicGain(mic_level);
-}
-
-/////////////////////////////
-// utility functions
-
-bool LLVivoxVoiceClient::writeString(const std::string &str)
-{
- bool result = false;
- LL_DEBUGS("LowVoice") << "sending:\n" << str << LL_ENDL;
-
- if(sConnected)
- {
- apr_status_t err;
- apr_size_t size = (apr_size_t)str.size();
- apr_size_t written = size;
-
- //MARK: Turn this on to log outgoing XML
- // LL_DEBUGS("Voice") << "sending: " << str << LL_ENDL;
-
- // check return code - sockets will fail (broken, etc.)
- err = apr_socket_send(
- mSocket->getSocket(),
- (const char*)str.data(),
- &written);
-
- if(err == 0 && written == size)
- {
- // Success.
- result = true;
- }
- else if (err == 0 && written != size) {
- // Did a short write, log it for now
- LL_WARNS("Voice") << ") short write on socket sending data to vivox daemon." << "Sent " << written << "bytes instead of " << size <<LL_ENDL;
- }
- else if(APR_STATUS_IS_EAGAIN(err))
- {
- char buf[MAX_STRING];
- LL_WARNS("Voice") << "EAGAIN error " << err << " (" << apr_strerror(err, buf, MAX_STRING) << ") sending data to vivox daemon." << LL_ENDL;
- }
- else
- {
- // Assume any socket error means something bad. For now, just close the socket.
- char buf[MAX_STRING];
- LL_WARNS("Voice") << "apr error " << err << " ("<< apr_strerror(err, buf, MAX_STRING) << ") sending data to vivox daemon." << LL_ENDL;
- daemonDied();
- }
- }
-
- return result;
-}
-
-
-/////////////////////////////
-// session control messages
-void LLVivoxVoiceClient::connectorCreate()
-{
- std::ostringstream stream;
- std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
-
- // Transition to stateConnectorStarted when the connector handle comes back.
- std::string vivoxLogLevel = gSavedSettings.getString("VivoxDebugLevel");
- if ( vivoxLogLevel.empty() )
- {
- vivoxLogLevel = "0";
- }
- LL_DEBUGS("Voice") << "creating connector with log level " << vivoxLogLevel << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.Create.1\">"
- << "<ClientName>V2 SDK</ClientName>"
- << "<AccountManagementServer>" << mVoiceAccountServerURI << "</AccountManagementServer>"
- << "<Mode>Normal</Mode>"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Logging>"
- << "<Folder>" << logdir << "</Folder>"
- << "<FileNamePrefix>Connector</FileNamePrefix>"
- << "<FileNameSuffix>.log</FileNameSuffix>"
- << "<LogLevel>" << vivoxLogLevel << "</LogLevel>"
- << "</Logging>"
- << "<Application>" << LLVersionInfo::instance().getChannel() << " " << LLVersionInfo::instance().getVersion() << "</Application>"
- //<< "<Application></Application>" //Name can cause problems per vivox.
- << "<MaxCalls>12</MaxCalls>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::connectorShutdown()
-{
- if(mConnectorEstablished)
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.InitiateShutdown.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "</Request>"
- << "\n\n\n";
-
- mShutdownComplete = false;
- mConnectorEstablished = false;
-
- writeString(stream.str());
- }
- else
- {
- mShutdownComplete = true;
- }
-}
-
-void LLVivoxVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &agentID)
-{
-
- mAccountDisplayName = user_id;
-
- LL_INFOS("Voice") << "name \"" << mAccountDisplayName << "\" , ID " << agentID << LL_ENDL;
-
- mAccountName = nameFromID(agentID);
-}
-
-void LLVivoxVoiceClient::setLoginInfo(
- const std::string& account_name,
- const std::string& password,
- const std::string& voice_sip_uri_hostname,
- const std::string& voice_account_server_uri)
-{
- mVoiceSIPURIHostName = voice_sip_uri_hostname;
- mVoiceAccountServerURI = voice_account_server_uri;
-
- if(mAccountLoggedIn)
- {
- // Already logged in.
- LL_WARNS("Voice") << "Called while already logged in." << LL_ENDL;
-
- // Don't process another login.
- return;
- }
- else if ( account_name != mAccountName )
- {
- LL_WARNS("Voice") << "Mismatched account name! " << account_name
- << " instead of " << mAccountName << LL_ENDL;
- }
- else
- {
- mAccountPassword = password;
- }
-
- std::string debugSIPURIHostName = gSavedSettings.getString("VivoxDebugSIPURIHostName");
-
- if( !debugSIPURIHostName.empty() )
- {
- LL_INFOS("Voice") << "Overriding account server based on VivoxDebugSIPURIHostName: "
- << debugSIPURIHostName << LL_ENDL;
- mVoiceSIPURIHostName = debugSIPURIHostName;
- }
-
- if( mVoiceSIPURIHostName.empty() )
- {
- // we have an empty account server name
- // so we fall back to hardcoded defaults
-
- if(LLGridManager::getInstance()->isInProductionGrid())
- {
- // Use the release account server
- mVoiceSIPURIHostName = "bhr.vivox.com";
- }
- else
- {
- // Use the development account server
- mVoiceSIPURIHostName = "bhd.vivox.com";
- }
- LL_INFOS("Voice") << "Defaulting SIP URI host: "
- << mVoiceSIPURIHostName << LL_ENDL;
-
- }
-
- std::string debugAccountServerURI = gSavedSettings.getString("VivoxDebugVoiceAccountServerURI");
-
- if( !debugAccountServerURI.empty() )
- {
- LL_INFOS("Voice") << "Overriding account server based on VivoxDebugVoiceAccountServerURI: "
- << debugAccountServerURI << LL_ENDL;
- mVoiceAccountServerURI = debugAccountServerURI;
- }
-
- if( mVoiceAccountServerURI.empty() )
- {
- // If the account server URI isn't specified, construct it from the SIP URI hostname
- mVoiceAccountServerURI = "https://www." + mVoiceSIPURIHostName + "/api2/";
- LL_INFOS("Voice") << "Inferring account server based on SIP URI Host name: "
- << mVoiceAccountServerURI << LL_ENDL;
- }
-}
-
-void LLVivoxVoiceClient::idle(void* user_data)
-{
-}
-
-//=========================================================================
-// the following are methods to support the coroutine implementation of the
-// voice connection and processing. They should only be called in the context
-// of a coroutine.
-//
-//
-
-typedef enum e_voice_control_coro_state
-{
- VOICE_STATE_ERROR = -1,
- VOICE_STATE_DONE = 0,
- VOICE_STATE_TP_WAIT, // entry point
- VOICE_STATE_START_DAEMON,
- VOICE_STATE_PROVISION_ACCOUNT,
- VOICE_STATE_START_SESSION,
- VOICE_STATE_SESSION_RETRY,
- VOICE_STATE_SESSION_ESTABLISHED,
- VOICE_STATE_WAIT_FOR_CHANNEL,
- VOICE_STATE_DISCONNECT,
- VOICE_STATE_WAIT_FOR_EXIT,
-} EVoiceControlCoroState;
-
-void LLVivoxVoiceClient::voiceControlCoro()
-{
- int state = 0;
- try
- {
- // state is passed as a reference instead of being
- // a member due to unresolved issues with coroutine
- // surviving longer than LLVivoxVoiceClient
- voiceControlStateMachine(state);
- }
- catch (const LLCoros::Stop&)
- {
- LL_DEBUGS("LLVivoxVoiceClient") << "Received a shutdown exception" << LL_ENDL;
- }
- catch (const LLContinueError&)
- {
- LOG_UNHANDLED_EXCEPTION("LLVivoxVoiceClient");
- }
- catch (...)
- {
- // Ideally for Windows need to log SEH exception instead or to set SEH
- // handlers but bugsplat shows local variables for windows, which should
- // be enough
- LL_WARNS("Voice") << "voiceControlStateMachine crashed in state " << state << LL_ENDL;
- throw;
- }
-}
-
-void LLVivoxVoiceClient::voiceControlStateMachine(S32 &coro_state)
-{
- if (sShuttingDown)
- {
- return;
- }
-
- LL_DEBUGS("Voice") << "starting" << LL_ENDL;
- mIsCoroutineActive = true;
- LLCoros::set_consuming(true);
-
- U32 retry = 0;
-
- coro_state = VOICE_STATE_TP_WAIT;
-
- do
- {
- if (sShuttingDown)
- {
- // Vivox singleton performed the exit, logged out,
- // cleaned sockets, gateway and no longer cares
- // about state of coroutine, so just stop
- return;
- }
-
- switch (coro_state)
- {
- case VOICE_STATE_TP_WAIT:
- // starting point for voice
- if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE)
- {
- LL_DEBUGS("Voice") << "Suspending voiceControlCoro() momentarily for teleport. Tuning: " << mTuningMode << ". Relog: " << mRelogRequested << LL_ENDL;
- llcoro::suspendUntilTimeout(1.0);
- }
- else
- {
- coro_state = VOICE_STATE_START_DAEMON;
- }
- break;
-
- case VOICE_STATE_START_DAEMON:
- LL_DEBUGS("Voice") << "Launching daemon" << LL_ENDL;
- LLVoiceVivoxStats::getInstance()->reset();
- if (startAndLaunchDaemon())
- {
- coro_state = VOICE_STATE_PROVISION_ACCOUNT;
- }
- else
- {
- coro_state = VOICE_STATE_SESSION_RETRY;
- }
- break;
-
- case VOICE_STATE_PROVISION_ACCOUNT:
- if (provisionVoiceAccount())
- {
- coro_state = VOICE_STATE_START_SESSION;
- }
- else
- {
- coro_state = VOICE_STATE_SESSION_RETRY;
- }
- break;
-
- case VOICE_STATE_START_SESSION:
- if (establishVoiceConnection())
- {
- coro_state = VOICE_STATE_SESSION_ESTABLISHED;
- }
- else
- {
- coro_state = VOICE_STATE_SESSION_RETRY;
- }
- break;
-
- case VOICE_STATE_SESSION_RETRY:
- giveUp(); // cleans sockets and session
- if (mRelogRequested)
- {
- // We failed to connect, give it a bit time before retrying.
- retry++;
- F32 full_delay = llmin(5.f * (F32)retry, 60.f);
- F32 current_delay = 0.f;
- LL_INFOS("Voice") << "Voice failed to establish session after " << retry
- << " tries. Will attempt to reconnect in " << full_delay
- << " seconds" << LL_ENDL;
- while (current_delay < full_delay && !sShuttingDown)
- {
- // Assuming that a second has passed is not accurate,
- // but we don't need accurancy here, just to make sure
- // that some time passed and not to outlive voice itself
- current_delay++;
- llcoro::suspendUntilTimeout(1.f);
- }
- coro_state = VOICE_STATE_WAIT_FOR_EXIT;
- }
- else
- {
- coro_state = VOICE_STATE_DONE;
- }
- break;
-
- case VOICE_STATE_SESSION_ESTABLISHED:
- {
- // enable/disable the automatic VAD and explicitly set the initial values of
- // the VAD variables ourselves when it is off - see SL-15072 for more details
- // note: we set the other parameters too even if the auto VAD is on which is ok
- unsigned int vad_auto = gSavedSettings.getU32("VivoxVadAuto");
- unsigned int vad_hangover = gSavedSettings.getU32("VivoxVadHangover");
- unsigned int vad_noise_floor = gSavedSettings.getU32("VivoxVadNoiseFloor");
- unsigned int vad_sensitivity = gSavedSettings.getU32("VivoxVadSensitivity");
- setupVADParams(vad_auto, vad_hangover, vad_noise_floor, vad_sensitivity);
-
- // watch for changes to the VAD settings via Debug Settings UI and act on them accordingly
- gSavedSettings.getControl("VivoxVadAuto")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
- gSavedSettings.getControl("VivoxVadHangover")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
- gSavedSettings.getControl("VivoxVadNoiseFloor")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
- gSavedSettings.getControl("VivoxVadSensitivity")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
-
- if (mTuningMode)
- {
- performMicTuning();
- }
-
- coro_state = VOICE_STATE_WAIT_FOR_CHANNEL;
- }
- break;
-
- case VOICE_STATE_WAIT_FOR_CHANNEL:
- waitForChannel(); // todo: split into more states like login/fonts
- coro_state = VOICE_STATE_DISCONNECT;
- break;
-
- case VOICE_STATE_DISCONNECT:
- LL_DEBUGS("Voice") << "lost channel RelogRequested=" << mRelogRequested << LL_ENDL;
- endAndDisconnectSession();
- retry = 0; // Connected without issues
- coro_state = VOICE_STATE_WAIT_FOR_EXIT;
- break;
-
- case VOICE_STATE_WAIT_FOR_EXIT:
- if (isGatewayRunning())
- {
- LL_INFOS("Voice") << "waiting for SLVoice to exit" << LL_ENDL;
- llcoro::suspendUntilTimeout(1.0);
- }
- else if (mRelogRequested && mVoiceEnabled)
- {
- LL_INFOS("Voice") << "will attempt to reconnect to voice" << LL_ENDL;
- coro_state = VOICE_STATE_TP_WAIT;
- }
- else
- {
- coro_state = VOICE_STATE_DONE;
- }
- break;
-
- case VOICE_STATE_DONE:
- break;
- }
- } while (coro_state > 0);
-
- if (sShuttingDown)
- {
- // LLVivoxVoiceClient might be already dead
- return;
- }
-
- mIsCoroutineActive = false;
- LL_INFOS("Voice") << "exiting" << LL_ENDL;
-}
-
-bool LLVivoxVoiceClient::endAndDisconnectSession()
-{
- LL_DEBUGS("Voice") << LL_ENDL;
-
- breakVoiceConnection(true);
-
- killGateway();
-
- return true;
-}
-
-bool LLVivoxVoiceClient::callbackEndDaemon(const LLSD& data)
-{
- if (!sShuttingDown && mVoiceEnabled)
- {
- LL_WARNS("Voice") << "SLVoice terminated " << ll_stream_notation_sd(data) << LL_ENDL;
- terminateAudioSession(false);
- closeSocket();
- cleanUp();
- LLVoiceClient::getInstance()->setUserPTTState(false);
- gAgent.setVoiceConnected(false);
- mRelogRequested = true;
- }
- sGatewayPump.stopListening("VivoxDaemonPump");
- return false;
-}
-
-bool LLVivoxVoiceClient::startAndLaunchDaemon()
-{
- //---------------------------------------------------------------------
- if (!LLVoiceClient::getInstance()->voiceEnabled())
- {
- // Voice is locked out, we must not launch the vivox daemon.
- LL_WARNS("Voice") << "voice disabled; not starting daemon" << LL_ENDL;
- return false;
- }
-
- if (!isGatewayRunning())
- {
-#ifndef VIVOXDAEMON_REMOTEHOST
- // Launch the voice daemon
-#if LL_WINDOWS
- // On windows use exe (not work or RO) directory
- std::string exe_path = gDirUtilp->getExecutableDir();
- gDirUtilp->append(exe_path, "SLVoice.exe");
-#elif LL_DARWIN
- // On MAC use resource directory
- std::string exe_path = gDirUtilp->getAppRODataDir();
- gDirUtilp->append(exe_path, "SLVoice");
-#else
- std::string exe_path = gDirUtilp->getExecutableDir();
- gDirUtilp->append(exe_path, "SLVoice");
-#endif
- // See if the vivox executable exists
- llstat s;
- if (!LLFile::stat(exe_path, &s))
- {
- // vivox executable exists. Build the command line and launch the daemon.
- LLProcess::Params params;
- params.executable = exe_path;
-
- // VOICE-88: Cycle through [portbase..portbase+portrange) on
- // successive tries because attempting to relaunch (after manually
- // disabling and then re-enabling voice) with the same port can
- // cause SLVoice's bind() call to fail with EADDRINUSE. We expect
- // that eventually the OS will time out previous ports, which is
- // why we cycle instead of incrementing indefinitely.
-
- static LLCachedControl<U32> portbase(gSavedSettings, "VivoxVoicePort");
- static LLCachedControl<std::string> host(gSavedSettings, "VivoxVoiceHost");
- static LLCachedControl<std::string> loglevel(gSavedSettings, "VivoxDebugLevel");
- static LLCachedControl<std::string> log_folder(gSavedSettings, "VivoxLogDirectory");
- static LLCachedControl<std::string> shutdown_timeout(gSavedSettings, "VivoxShutdownTimeout");
- static const U32 portrange = 100;
- static U32 portoffset = 0;
- U32 port = 0;
-
- if (LLAppViewer::instance()->isSecondInstance())
- {
- // Ideally need to know amount of instances and
- // to increment instance_offset on EADDRINUSE.
- // But for now just use rand
- static U32 instance_offset = portrange * ll_rand(20);
- port = portbase + portoffset + instance_offset;
- }
- else
- {
- // leave main thread with exclusive port set
- port = portbase + portoffset;
- }
- portoffset = (portoffset + 1) % portrange;
- params.args.add("-i");
- params.args.add(STRINGIZE(host() << ':' << port));
-
- params.args.add("-ll");
- if (loglevel().empty())
- {
- params.args.add("0");
- }
- else
- {
- params.args.add(loglevel);
- }
-
- params.args.add("-lf");
- if (log_folder().empty())
- {
- params.args.add(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""));
- }
- else
- {
- params.args.add(log_folder);
- }
-
- // set log file basename and .log
- params.args.add("-lp");
- params.args.add("SLVoice");
- params.args.add("-ls");
- params.args.add(".log");
-
- // rotate any existing log
- std::string new_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SLVoice.log");
- std::string old_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SLVoice.old");
- if (gDirUtilp->fileExists(new_log))
- {
- LLFile::rename(new_log, old_log);
- }
-
- if (!shutdown_timeout().empty())
- {
- params.args.add("-st");
- params.args.add(shutdown_timeout);
- }
- params.cwd = gDirUtilp->getAppRODataDir();
-
-# ifdef VIVOX_HANDLE_ARGS
- params.args.add("-ah");
- params.args.add(LLVivoxSecurity::getInstance()->accountHandle());
-
- params.args.add("-ch");
- params.args.add(LLVivoxSecurity::getInstance()->connectorHandle());
-# endif // VIVOX_HANDLE_ARGS
-
- params.postend = sGatewayPump.getName();
- sGatewayPump.listen("VivoxDaemonPump", boost::bind(&LLVivoxVoiceClient::callbackEndDaemon, this, _1));
-
- LL_INFOS("Voice") << "Launching SLVoice" << LL_ENDL;
- LL_DEBUGS("Voice") << "SLVoice params " << params << LL_ENDL;
-
- sGatewayPtr = LLProcess::create(params);
-
- mDaemonHost = LLHost(host().c_str(), port);
- }
- else
- {
- LL_WARNS("Voice") << exe_path << " not found." << LL_ENDL;
- return false;
- }
-#else
- // SLIM SDK: port changed from 44124 to 44125.
- // We can connect to a client gateway running on another host. This is useful for testing.
- // To do this, launch the gateway on a nearby host like this:
- // vivox-gw.exe -p tcp -i 0.0.0.0:44125
- // and put that host's IP address here.
- mDaemonHost = LLHost(gSavedSettings.getString("VivoxVoiceHost"), gSavedSettings.getU32("VivoxVoicePort"));
-#endif
-
- // Dirty the states we'll need to sync with the daemon when it comes up.
- mMuteMicDirty = true;
- mMicVolumeDirty = true;
- mSpeakerVolumeDirty = true;
- mSpeakerMuteDirty = true;
- // These only need to be set if they're not default (i.e. empty string).
- mCaptureDeviceDirty = !mCaptureDevice.empty();
- mRenderDeviceDirty = !mRenderDevice.empty();
-
- mMainSessionGroupHandle.clear();
- }
- else
- {
- LL_DEBUGS("Voice") << " gateway running; not attempting to start" << LL_ENDL;
- }
-
- //---------------------------------------------------------------------
- llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
-
- LL_DEBUGS("Voice") << "Connecting to vivox daemon:" << mDaemonHost << LL_ENDL;
-
- int retryCount(0);
- LLVoiceVivoxStats::getInstance()->reset();
- while (!sConnected && !sShuttingDown && retryCount++ <= DAEMON_CONNECT_RETRY_MAX)
- {
- LLVoiceVivoxStats::getInstance()->connectionAttemptStart();
- LL_DEBUGS("Voice") << "Attempting to connect to vivox daemon: " << mDaemonHost << LL_ENDL;
- closeSocket();
- if (!mSocket)
- {
- mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
- }
-
- sConnected = mSocket->blockingConnect(mDaemonHost);
- LLVoiceVivoxStats::getInstance()->connectionAttemptEnd(sConnected);
- if (!sConnected)
- {
- llcoro::suspendUntilTimeout(DAEMON_CONNECT_THROTTLE_SECONDS);
- }
- }
-
- //---------------------------------------------------------------------
- if (sShuttingDown && !sConnected)
- {
- return false;
- }
-
- llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
-
- while (!sPump && !sShuttingDown)
- { // Can't use the pump until we have it available.
- llcoro::suspendUntilNextFrame();
- }
-
- if (sShuttingDown)
- {
- return false;
- }
-
- // MBW -- Note to self: pumps and pipes examples in
- // indra/test/io.cpp
- // indra/test/llpipeutil.{cpp|h}
-
- // Attach the pumps and pipes
-
- LLPumpIO::chain_t readChain;
-
- readChain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(mSocket)));
- readChain.push_back(LLIOPipe::ptr_t(new LLVivoxProtocolParser()));
-
-
- sPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS);
-
-
- //---------------------------------------------------------------------
- llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
-
- // Initial devices query
- getCaptureDevicesSendMessage();
- getRenderDevicesSendMessage();
-
- mLoginRetryCount = 0;
-
- return true;
-}
-
-bool LLVivoxVoiceClient::provisionVoiceAccount()
-{
- LL_INFOS("Voice") << "Provisioning voice account." << LL_ENDL;
-
- while ((!gAgent.getRegion() || !gAgent.getRegion()->capabilitiesReceived()) && !sShuttingDown)
- {
- LL_DEBUGS("Voice") << "no capabilities for voice provisioning; waiting " << LL_ENDL;
- // *TODO* Pump a message for wake up.
- llcoro::suspend();
- }
-
- if (sShuttingDown)
- {
- return false;
- }
-
- std::string url = gAgent.getRegionCapability("ProvisionVoiceAccountRequest");
-
- LL_DEBUGS("Voice") << "region ready for voice provisioning; url=" << url << LL_ENDL;
-
- LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
- LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
- httpAdapter = std::make_shared<LLCoreHttpUtil::HttpCoroutineAdapter>("voiceAccountProvision", httpPolicy);
- LLCore::HttpRequest::ptr_t httpRequest = std::make_shared<LLCore::HttpRequest>();
- LLCore::HttpOptions::ptr_t httpOpts = std::make_shared<LLCore::HttpOptions>();
- int retryCount(0);
-
- LLSD result;
- bool provisioned = false;
- do
- {
- LLVoiceVivoxStats::getInstance()->provisionAttemptStart();
- LLSD body;
- body["voice_server_type"] = "vivox";
- result = httpAdapter->postAndSuspend(httpRequest, url, body, httpOpts);
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
- LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
-
- if (status == LLCore::HttpStatus(404))
- {
- F32 timeout = pow(PROVISION_RETRY_TIMEOUT, static_cast<float>(retryCount));
- LL_WARNS("Voice") << "Provision CAP 404. Retrying in " << timeout << " seconds. Retries: " << (S32)retryCount << LL_ENDL;
- llcoro::suspendUntilTimeout(timeout);
-
- if (sShuttingDown)
- {
- return false;
- }
- }
- else if (!status)
- {
- LL_WARNS("Voice") << "Unable to provision voice account." << LL_ENDL;
- LLVoiceVivoxStats::getInstance()->provisionAttemptEnd(false);
- return false;
- }
- else
- {
- provisioned = true;
- }
- } while (!provisioned && ++retryCount <= PROVISION_RETRY_MAX && !sShuttingDown);
-
- if (sShuttingDown && !provisioned)
- {
- return false;
- }
-
- LLVoiceVivoxStats::getInstance()->provisionAttemptEnd(provisioned);
- if (!provisioned)
- {
- LL_WARNS("Voice") << "Could not access voice provision cap after " << retryCount << " attempts." << LL_ENDL;
- return false;
- }
- LL_DEBUGS("Voice") << "Voice Provision Result." << result << LL_ENDL;
- std::string voiceSipUriHostname;
- std::string voiceAccountServerUri;
- std::string voiceUserName = result["username"].asString();
- std::string voicePassword = result["password"].asString();
-
- if (result.has("voice_sip_uri_hostname"))
- {
- voiceSipUriHostname = result["voice_sip_uri_hostname"].asString();
- }
-
- // this key is actually misnamed -- it will be an entire URI, not just a hostname.
- if (result.has("voice_account_server_name"))
- {
- voiceAccountServerUri = result["voice_account_server_name"].asString();
- }
-
- LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response"
- << " user " << (voiceUserName.empty() ? "not set" : "set")
- << " password " << (voicePassword.empty() ? "not set" : "set")
- << " sip uri " << voiceSipUriHostname
- << " account uri " << voiceAccountServerUri
- << LL_ENDL;
-
- setLoginInfo(voiceUserName, voicePassword, voiceSipUriHostname, voiceAccountServerUri);
-
- return true;
-}
-
-bool LLVivoxVoiceClient::establishVoiceConnection()
-{
- if (!mVoiceEnabled && mIsInitialized)
- {
- LL_WARNS("Voice") << "cannot establish connection; enabled "<<mVoiceEnabled<<" initialized "<<mIsInitialized<<LL_ENDL;
- return false;
- }
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LLSD result;
- bool connected(false);
- bool giving_up(false);
- int retries = 0;
- LL_INFOS("Voice") << "Requesting connection to voice service" << LL_ENDL;
-
- LLVoiceVivoxStats::getInstance()->establishAttemptStart();
- connectorCreate();
- do
- {
- result = llcoro::suspendUntilEventOn(mVivoxPump);
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
-
- if (result.has("connector"))
- {
- connected = LLSD::Boolean(result["connector"]);
- LLVoiceVivoxStats::getInstance()->establishAttemptEnd(connected);
- if (!connected)
- {
- if (result.has("retry") && ++retries <= CONNECT_RETRY_MAX && !sShuttingDown)
- {
- F32 timeout = (F32)LLSD::Real(result["retry"]);
- timeout *= retries;
- LL_INFOS("Voice") << "Retry connection to voice service in " << timeout << " seconds" << LL_ENDL;
- llcoro::suspendUntilTimeout(timeout);
-
- if (mVoiceEnabled) // user may have switched it off
- {
- // try again
- LLVoiceVivoxStats::getInstance()->establishAttemptStart();
- connectorCreate();
- }
- else
- {
- // stop if they've turned off voice
- giving_up = true;
- }
- }
- else
- {
- giving_up=true;
- }
- }
- }
- LL_DEBUGS("Voice") << (connected ? "" : "not ") << "connected, "
- << (giving_up ? "" : "not ") << "giving up"
- << LL_ENDL;
- } while (!connected && !giving_up && !sShuttingDown);
-
- if (giving_up)
- {
- LLSD args;
- args["HOSTID"] = LLURI(mVoiceAccountServerURI).authority();
- LLNotificationsUtil::add("NoVoiceConnect", args);
- }
-
- return connected;
-}
-
-bool LLVivoxVoiceClient::breakVoiceConnection(bool corowait)
-{
- LL_DEBUGS("Voice") << "( wait=" << corowait << ")" << LL_ENDL;
- bool retval(true);
-
- mShutdownComplete = false;
- connectorShutdown();
-
- if (corowait)
- {
- LLSD timeoutResult(LLSDMap("connector", "timeout"));
-
- LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult);
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
-
- retval = result.has("connector");
- }
- else
- {
- mRelogRequested = false; //stop the control coro
- // If we are not doing a corowait then we must sleep until the connector has responded
- // otherwise we may very well close the socket too early.
-#if LL_WINDOWS
- if (!mShutdownComplete)
- {
- // The situation that brings us here is a call from ::terminate()
- // At this point message system is already down so we can't wait for
- // the message, yet we need to receive "connector shutdown response".
- // Either wait a bit and emulate it or check gMessageSystem for specific message
- _sleep(1000);
- if (sConnected)
- {
- sConnected = false;
- LLSD vivoxevent(LLSDMap("connector", LLSD::Boolean(false)));
- mVivoxPump.post(vivoxevent);
- }
- mShutdownComplete = true;
- }
-#endif
- }
-
- LL_DEBUGS("Voice") << "closing SLVoice socket" << LL_ENDL;
- closeSocket(); // Need to do this now -- bad things happen if the destructor does it later.
- cleanUp();
- sConnected = false;
-
- return retval;
-}
-
-bool LLVivoxVoiceClient::loginToVivox()
-{
- LLSD timeoutResult(LLSDMap("login", "timeout"));
-
- int loginRetryCount(0);
-
- bool response_ok(false);
- bool account_login(false);
- bool send_login(true);
-
- do
- {
- mIsLoggingIn = true;
- if (send_login)
- {
- loginSendMessage();
- send_login = false;
- }
-
- LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGIN_ATTEMPT_TIMEOUT, timeoutResult);
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
-
- if (result.has("login"))
- {
- std::string loginresp = result["login"];
-
- if (((loginresp == "retry") || (loginresp == "timeout")) && !sShuttingDown)
- {
- LL_WARNS("Voice") << "login failed with status '" << loginresp << "' "
- << " count " << loginRetryCount << "/" << LOGIN_RETRY_MAX
- << LL_ENDL;
- if (++loginRetryCount > LOGIN_RETRY_MAX)
- {
- // We've run out of retries - tell the user
- LL_WARNS("Voice") << "too many login retries (" << loginRetryCount << "); giving up." << LL_ENDL;
- LLSD args;
- args["HOSTID"] = LLURI(mVoiceAccountServerURI).authority();
- mTerminateDaemon = true;
- LLNotificationsUtil::add("NoVoiceConnect", args);
-
- mIsLoggingIn = false;
- return false;
- }
- response_ok = false;
- account_login = false;
- send_login = true;
-
- // an exponential backoff gets too long too quickly; stretch it out, but not too much
- F32 timeout = loginRetryCount * LOGIN_ATTEMPT_TIMEOUT;
-
- // tell the user there is a problem
- LL_WARNS("Voice") << "login " << loginresp << " will retry login in " << timeout << " seconds." << LL_ENDL;
-
- if (!sShuttingDown)
- {
- // Todo: this is way to long, viewer can get stuck waiting during shutdown
- // either make it listen to pump or split in smaller waits with checks for shutdown
- llcoro::suspendUntilTimeout(timeout);
- }
- }
- else if (loginresp == "failed")
- {
- mIsLoggingIn = false;
- return false;
- }
- else if (loginresp == "response_ok")
- {
- response_ok = true;
- }
- else if (loginresp == "account_login")
- {
- account_login = true;
- }
- else if (sShuttingDown)
- {
- mIsLoggingIn = false;
- return false;
- }
- }
-
- } while ((!response_ok || !account_login) && !sShuttingDown);
-
- if (sShuttingDown)
- {
- return false;
- }
-
- mRelogRequested = false;
- mIsLoggedIn = true;
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN);
-
- // Set up the mute list observer if it hasn't been set up already.
- if ((!sMuteListListener_listening))
- {
- LLMuteList::getInstance()->addObserver(&mutelist_listener);
- sMuteListListener_listening = true;
- }
-
- // Set the initial state of mic mute, local speaker volume, etc.
- sendLocalAudioUpdates();
- mIsLoggingIn = false;
-
- return true;
-}
-
-void LLVivoxVoiceClient::logoutOfVivox(bool wait)
-{
- if (mIsLoggedIn)
- {
- // Ensure that we'll re-request provisioning before logging in again
- mAccountPassword.clear();
- mVoiceAccountServerURI.clear();
-
- logoutSendMessage();
-
- if (wait)
- {
- LLSD timeoutResult(LLSDMap("logout", "timeout"));
- LLSD result;
-
- do
- {
- LL_DEBUGS("Voice")
- << "waiting for logout response on "
- << mVivoxPump.getName()
- << LL_ENDL;
-
- result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult);
-
- if (sShuttingDown)
- {
- break;
- }
-
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- // Don't get confused by prior queued events -- note that it's
- // very important that mVivoxPump is an LLEventMailDrop, which
- // does queue events.
- } while (! result["logout"]);
- }
- else
- {
- LL_DEBUGS("Voice") << "not waiting for logout" << LL_ENDL;
- }
-
- mIsLoggedIn = false;
- }
-}
-
-
-bool LLVivoxVoiceClient::retrieveVoiceFonts()
-{
- // Request the set of available voice fonts.
- refreshVoiceEffectLists(true);
-
- mIsWaitingForFonts = true;
- LLSD result;
- do
- {
- result = llcoro::suspendUntilEventOn(mVivoxPump);
-
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- if (result.has("voice_fonts"))
- break;
- } while (true);
- mIsWaitingForFonts = false;
-
- mVoiceFontExpiryTimer.start();
- mVoiceFontExpiryTimer.setTimerExpirySec(VOICE_FONT_EXPIRY_INTERVAL);
-
- return result["voice_fonts"].asBoolean();
-}
-
-bool LLVivoxVoiceClient::requestParcelVoiceInfo()
-{
- //_INFOS("Voice") << "Requesting voice info for Parcel" << LL_ENDL;
-
- LLViewerRegion * region = gAgent.getRegion();
- if (region == NULL || !region->capabilitiesReceived())
- {
- LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest capability not yet available, deferring" << LL_ENDL;
- return false;
- }
-
- // grab the cap.
- std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest");
- if (url.empty())
- {
- // Region dosn't have the cap. Stop probing.
- LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest capability not available in this region" << LL_ENDL;
- return false;
- }
-
- // update the parcel
- checkParcelChanged(true);
-
- LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL;
-
- LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
- LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
- httpAdapter = std::make_shared<LLCoreHttpUtil::HttpCoroutineAdapter>("parcelVoiceInfoRequest", httpPolicy);
- LLCore::HttpRequest::ptr_t httpRequest = std::make_shared<LLCore::HttpRequest>();
-
- LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD());
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
- LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
-
- if (mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized))
- {
- // if a terminate request has been received,
- // bail and go to the stateSessionTerminated
- // state. If the cap request is still pending,
- // the responder will check to see if we've moved
- // to a new session and won't change any state.
- LL_DEBUGS("Voice") << "terminate requested " << mSessionTerminateRequested
- << " enabled " << mVoiceEnabled
- << " initialized " << mIsInitialized
- << LL_ENDL;
- terminateAudioSession(true);
- return false;
- }
-
- if ((!status) || (mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized)))
- {
- if (mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized))
- {
- LL_WARNS("Voice") << "Session terminated." << LL_ENDL;
- }
-
- LL_WARNS("Voice") << "No voice on parcel" << LL_ENDL;
- sessionTerminate();
- return false;
- }
-
- if (!result.has("voice_credentials"))
- {
- if (LLViewerParcelMgr::getInstance()->allowAgentVoice())
- {
- LL_WARNS("Voice") << "No voice credentials" << LL_ENDL;
- }
- else
- {
- LL_DEBUGS("Voice") << "No voice credentials" << LL_ENDL;
- }
- }
-
- // set the spatial channel. If no voice credentials or uri are
- // available, then we simply drop out of voice spatially.
- return setSpatialChannel(result["voice_credentials"]);
-}
-
-bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession)
-{
- mIsJoiningSession = true;
-
- sessionStatePtr_t oldSession = mAudioSession;
-
- LL_INFOS("Voice") << "Adding or joining voice session " << nextSession->mHandle << LL_ENDL;
-
- mAudioSession = nextSession;
- if (!mAudioSession || !mAudioSession->mReconnect)
- {
- mNextAudioSession.reset();
- }
-
- // The old session may now need to be deleted.
- reapSession(oldSession);
-
- if (mAudioSession)
- {
- if (!mAudioSession->mHandle.empty())
- {
- // Connect to a session by session handle
-
- sessionMediaConnectSendMessage(mAudioSession);
- }
- else
- {
- // Connect to a session by URI
- sessionCreateSendMessage(mAudioSession, true, false);
- }
- }
-
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINING);
-
- llcoro::suspend();
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LLSD result;
-
- if (mSpatialJoiningNum == MAX_NORMAL_JOINING_SPATIAL_NUM)
- {
- // Notify observers to let them know there is problem with voice
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
- LL_WARNS() << "There seems to be problem with connection to voice server. Disabling voice chat abilities." << LL_ENDL;
- }
-
- // Increase mSpatialJoiningNum only for spatial sessions- it's normal to reach this case for
- // example for p2p many times while waiting for response, so it can't be used to detect errors
- if (mAudioSession && mAudioSession->mIsSpatial)
- {
- mSpatialJoiningNum++;
- }
-
- if (!mVoiceEnabled && mIsInitialized)
- {
- LL_DEBUGS("Voice") << "Voice no longer enabled. Exiting"
- << " enabled " << mVoiceEnabled
- << " initialized " << mIsInitialized
- << LL_ENDL;
- mIsJoiningSession = false;
- // User bailed out during connect -- jump straight to teardown.
- terminateAudioSession(true);
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
- return false;
- }
- else if (mSessionTerminateRequested)
- {
- LL_DEBUGS("Voice") << "Terminate requested" << LL_ENDL;
- if (mAudioSession && !mAudioSession->mHandle.empty())
- {
- // Only allow direct exits from this state in p2p calls (for cancelling an invite).
- // Terminating a half-connected session on other types of calls seems to break something in the vivox gateway.
- if (mAudioSession->mIsP2P)
- {
- terminateAudioSession(true);
- mIsJoiningSession = false;
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
- return false;
- }
- }
- }
-
- bool added(true);
- bool joined(false);
-
- LLSD timeoutResult(LLSDMap("session", "timeout"));
-
- // We are about to start a whole new session. Anything that MIGHT still be in our
- // maildrop is going to be stale and cause us much wailing and gnashing of teeth.
- // Just flush it all out and start new.
- mVivoxPump.discard();
-
- // It appears that I need to wait for BOTH the SessionGroup.AddSession response and the SessionStateChangeEvent with state 4
- // before continuing from this state. They can happen in either order, and if I don't wait for both, things can get stuck.
- // For now, the SessionGroup.AddSession response handler sets mSessionHandle and the SessionStateChangeEvent handler transitions to stateSessionJoined.
- // This is a cheap way to make sure both have happened before proceeding.
- do
- {
- result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, SESSION_JOIN_TIMEOUT, timeoutResult);
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LL_INFOS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- if (result.has("session"))
- {
- if (!mAudioSession)
- {
- LL_WARNS("Voice") << "Message for session handle \"" << result["handle"] << "\" while session is not initialized." << LL_ENDL;
- continue;
- }
- if (result.has("handle") && result["handle"] != mAudioSession->mHandle)
- {
- LL_WARNS("Voice") << "Message for session handle \"" << result["handle"] << "\" while waiting for \"" << mAudioSession->mHandle << "\"." << LL_ENDL;
- continue;
- }
-
- std::string message = result["session"].asString();
-
- if ((message == "added") || (message == "created"))
- {
- added = true;
- }
- else if (message == "joined")
- {
- joined = true;
- }
- else if ((message == "failed") || (message == "removed") || (message == "timeout"))
- { // we will get a removed message if a voice call is declined.
- LL_INFOS("Voice") << "Result:" << result << LL_ENDL;
- if (message == "failed")
- {
- int reason = result["reason"].asInteger();
- LL_WARNS("Voice") << "Add and join failed for reason " << reason << LL_ENDL;
-
- if ( (reason == ERROR_VIVOX_NOT_LOGGED_IN)
- || (reason == ERROR_VIVOX_OBJECT_NOT_FOUND))
- {
- LL_DEBUGS("Voice") << "Requesting reprovision and login." << LL_ENDL;
- requestRelog();
- }
- }
- else
- {
- LL_WARNS("Voice") << "session '" << message << "' "
- << LL_ENDL;
- }
-
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
- mIsJoiningSession = false;
- return false;
- }
- }
- } while (!added || !joined);
-
- mIsJoiningSession = false;
-
- if (mSpatialJoiningNum > 100)
- {
- LL_WARNS("Voice") << "There seems to be problem with connecting to a voice channel. Frames to join were " << mSpatialJoiningNum << LL_ENDL;
- }
-
- mSpatialJoiningNum = 0;
-
- // Events that need to happen when a session is joined could go here.
- // send an initial positional information immediately upon joining.
- //
- // do an initial update for position and the camera position, then send a
- // positional update.
- updatePosition();
- enforceTether();
-
- // Dirty state that may need to be sync'ed with the daemon.
- mMuteMicDirty = true;
- mSpeakerVolumeDirty = true;
- mSpatialCoordsDirty = true;
-
- sendPositionAndVolumeUpdate();
-
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINED);
-
- return true;
-}
-
-bool LLVivoxVoiceClient::terminateAudioSession(bool wait)
-{
-
- if (mAudioSession)
- {
- LL_INFOS("Voice") << "terminateAudioSession(" << wait << ") Terminating current voice session " << mAudioSession->mHandle << LL_ENDL;
-
- if (mIsLoggedIn)
- {
- if (!mAudioSession->mHandle.empty())
- {
-
-#if RECORD_EVERYTHING
- // HACK: for testing only
- // Save looped recording
- std::string savepath("/tmp/vivoxrecording");
- {
- time_t now = time(NULL);
- const size_t BUF_SIZE = 64;
- char time_str[BUF_SIZE]; /* Flawfinder: ignore */
-
- strftime(time_str, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
- savepath += time_str;
- }
- recordingLoopSave(savepath);
-#endif
-
- sessionMediaDisconnectSendMessage(mAudioSession);
-
- if (wait)
- {
- LLSD result;
- do
- {
- LLSD timeoutResult(LLSDMap("session", "timeout"));
-
- result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult);
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- if (result.has("session"))
- {
- if (result.has("handle"))
- {
- if (result["handle"] != mAudioSession->mHandle)
- {
- LL_WARNS("Voice") << "Message for session handle \"" << result["handle"] << "\" while waiting for \"" << mAudioSession->mHandle << "\"." << LL_ENDL;
- continue;
- }
- }
-
- std::string message = result["session"].asString();
- if (message == "removed" || message == "timeout")
- break;
- }
- } while (true);
-
- }
- }
- else
- {
- LL_WARNS("Voice") << "called with no session handle" << LL_ENDL;
- }
- }
- else
- {
- LL_WARNS("Voice") << "Session " << mAudioSession->mHandle << " already terminated by logout." << LL_ENDL;
- }
-
- sessionStatePtr_t oldSession = mAudioSession;
-
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL); // needs mAudioSession for uri
- mAudioSession.reset();
-
- // The old session may now need to be deleted.
- reapSession(oldSession);
- }
- else
- {
- LL_WARNS("Voice") << "terminateAudioSession(" << wait << ") with NULL mAudioSession" << LL_ENDL;
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
- }
-
-
- // Always reset the terminate request flag when we get here.
- // Some slower PCs have a race condition where they can switch to an incoming P2P call faster than the state machine leaves
- // the region chat.
- mSessionTerminateRequested = false;
-
- bool status=((mVoiceEnabled || !mIsInitialized) && !mRelogRequested && !sShuttingDown);
- LL_DEBUGS("Voice") << "exiting"
- << " VoiceEnabled " << mVoiceEnabled
- << " IsInitialized " << mIsInitialized
- << " RelogRequested " << mRelogRequested
- << " ShuttingDown " << (sShuttingDown ? "True" : "False")
- << " returning " << status
- << LL_ENDL;
- return status;
-}
-
-
-typedef enum e_voice_wait_for_channel_state
-{
- VOICE_CHANNEL_STATE_LOGIN = 0, // entry point
- VOICE_CHANNEL_STATE_CHECK_EFFECTS,
- VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING,
- VOICE_CHANNEL_STATE_PROCESS_CHANNEL,
- VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY,
- VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK,
- VOICE_CHANNEL_STATE_LOGOUT,
- VOICE_CHANNEL_STATE_RELOG,
- VOICE_CHANNEL_STATE_DONE,
-} EVoiceWaitForChannelState;
-
-bool LLVivoxVoiceClient::waitForChannel()
-{
- LL_INFOS("Voice") << "Waiting for channel" << LL_ENDL;
-
- EVoiceWaitForChannelState state = VOICE_CHANNEL_STATE_LOGIN;
-
- do
- {
- if (sShuttingDown)
- {
- // terminate() forcefully disconects voice, no need for cleanup
- return false;
- }
-
- switch (state)
- {
- case VOICE_CHANNEL_STATE_LOGIN:
- if (!loginToVivox())
- {
- return false;
- }
- state = VOICE_CHANNEL_STATE_CHECK_EFFECTS;
- break;
-
- case VOICE_CHANNEL_STATE_CHECK_EFFECTS:
- if (LLVoiceClient::instance().getVoiceEffectEnabled())
- {
- retrieveVoiceFonts();
-
- if (sShuttingDown)
- {
- return false;
- }
-
- // Request the set of available voice fonts.
- refreshVoiceEffectLists(false);
- }
-
-#if USE_SESSION_GROUPS
- // Rider: This code is completely unchanged from the original state machine
- // It does not seem to be in active use... but I'd rather not rip it out.
- // create the main session group
- setState(stateCreatingSessionGroup);
- sessionGroupCreateSendMessage();
-#endif
-
- state = VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING;
- break;
-
- case VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING:
- llcoro::suspend();
- state = VOICE_CHANNEL_STATE_PROCESS_CHANNEL;
- break;
-
- case VOICE_CHANNEL_STATE_PROCESS_CHANNEL:
- if (mTuningMode)
- {
- performMicTuning();
- }
- else if (mCaptureBufferMode)
- {
- recordingAndPlaybackMode();
- }
- else if (mProcessChannels && ((mNextAudioSession == NULL) || checkParcelChanged()))
- {
- // the parcel is changed, or we have no pending audio sessions,
- // so try to request the parcel voice info
- // if we have the cap, we move to the appropriate state
- requestParcelVoiceInfo(); //suspends for http reply
- }
- else if (sessionNeedsRelog(mNextAudioSession))
- {
- LL_INFOS("Voice") << "Session requesting reprovision and login." << LL_ENDL;
- requestRelog();
- break;
- }
- else if (mNextAudioSession)
- {
- if (!mNextAudioSession->mIsP2P && !mProcessChannels)
- {
- llcoro::suspend();
- break;
- }
-
- try
- {
- sessionStatePtr_t joinSession = mNextAudioSession;
- mNextAudioSession.reset();
- mIsProcessingChannels = true;
- if (!runSession(joinSession)) //suspends
- {
- mIsProcessingChannels = false;
- LL_DEBUGS("Voice") << "runSession returned false; leaving inner loop" << LL_ENDL;
- break;
- }
- else
- {
- mIsProcessingChannels = false;
- LL_DEBUGS("Voice")
- << "runSession returned true to inner loop"
- << " RelogRequested=" << mRelogRequested
- << " VoiceEnabled=" << mVoiceEnabled
- << LL_ENDL;
- }
- }
- catch (const LLCoros::Stop&)
- {
- LL_DEBUGS("LLVivoxVoiceClient") << "Received a shutdown exception" << LL_ENDL;
- }
- catch (const LLContinueError&)
- {
- LOG_UNHANDLED_EXCEPTION("LLVivoxVoiceClient");
- }
- catch (...)
- {
- // Ideally for Windows need to log SEH exception instead or to set SEH
- // handlers but bugsplat shows local variables for windows, which should
- // be enough
- LL_WARNS("Voice") << "voiceControlStateMachine crashed in state VOICE_CHANNEL_STATE_PROCESS_CHANNEL"
- << " mRelogRequested " << mRelogRequested
- << " mVoiceEnabled " << mVoiceEnabled
- << " mIsProcessingChannels " << mIsProcessingChannels
- << " mProcessChannels " << mProcessChannels
- << LL_ENDL;
- throw;
- }
- }
-
- state = VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY;
- break;
-
- case VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY:
- if (!mNextAudioSession)
- {
- llcoro::suspendUntilTimeout(1.0);
- }
- state = VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK;
- break;
-
- case VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK:
- if (mVoiceEnabled && !mRelogRequested)
- {
- state = VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING;
- break;
- }
- else
- {
- mIsProcessingChannels = false;
- LL_DEBUGS("Voice")
- << "leaving inner waitForChannel loop"
- << " RelogRequested=" << mRelogRequested
- << " VoiceEnabled=" << mVoiceEnabled
- << LL_ENDL;
- state = VOICE_CHANNEL_STATE_LOGOUT;
- break;
- }
-
- case VOICE_CHANNEL_STATE_LOGOUT:
- logoutOfVivox(true /*bool wait*/);
- if (mRelogRequested)
- {
- state = VOICE_CHANNEL_STATE_RELOG;
- }
- else
- {
- state = VOICE_CHANNEL_STATE_DONE;
- }
- break;
-
- case VOICE_CHANNEL_STATE_RELOG:
- LL_DEBUGS("Voice") << "Relog Requested, restarting provisioning" << LL_ENDL;
- if (!provisionVoiceAccount())
- {
- if (sShuttingDown)
- {
- return false;
- }
- LL_WARNS("Voice") << "provisioning voice failed; giving up" << LL_ENDL;
- giveUp();
- return false;
- }
- if (mVoiceEnabled && mRelogRequested && isGatewayRunning())
- {
- state = VOICE_CHANNEL_STATE_LOGIN;
- }
- else
- {
- state = VOICE_CHANNEL_STATE_DONE;
- }
- break;
- case VOICE_CHANNEL_STATE_DONE:
- LL_DEBUGS("Voice")
- << "exiting"
- << " RelogRequested=" << mRelogRequested
- << " VoiceEnabled=" << mVoiceEnabled
- << LL_ENDL;
- return !sShuttingDown;
- }
- } while (true);
-}
-
-bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session)
-{
- LL_INFOS("Voice") << "running new voice session " << session->mHandle << LL_ENDL;
-
- if (sShuttingDown || !mProcessChannels)
- {
- return false;
- }
-
- bool joined_session = addAndJoinSession(session);
-
- if (!joined_session)
- {
- notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN);
-
- if (mSessionTerminateRequested)
- {
- LL_DEBUGS("Voice") << "runSession terminate requested " << LL_ENDL;
- terminateAudioSession(true);
- }
- // if a relog has been requested then addAndJoineSession
- // failed in a spectacular way and we need to back out.
- // If this is not the case then we were simply trying to
- // make a call and the other party rejected it.
- return !mRelogRequested;
- }
-
- notifyParticipantObservers();
- notifyVoiceFontObservers();
-
- LLSD timeoutEvent(LLSDMap("timeout", LLSD::Boolean(true)));
-
- mIsInChannel = true;
- mMuteMicDirty = true;
-
- while (!sShuttingDown
- && mVoiceEnabled
- && isGatewayRunning()
- && !mSessionTerminateRequested
- && !mTuningMode
- && mProcessChannels)
- {
- sendCaptureAndRenderDevices(); // suspends
-
- if (sShuttingDown)
- {
- return false;
- }
-
- if (mSessionTerminateRequested)
- {
- break;
- }
-
- if (mAudioSession && mAudioSession->mParticipantsChanged)
- {
- mAudioSession->mParticipantsChanged = false;
- notifyParticipantObservers();
- }
-
- if (!inSpatialChannel())
- {
- // When in a non-spatial channel, never send positional updates.
- mSpatialCoordsDirty = false;
- }
- else
- {
- updatePosition();
-
- if (checkParcelChanged())
- {
- // *RIDER: I think I can just return here if the parcel has changed
- // and grab the new voice channel from the outside loop.
- //
- // if the parcel has changed, attempted to request the
- // cap for the parcel voice info. If we can't request it
- // then we don't have the cap URL so we do nothing and will
- // recheck next time around
- if (requestParcelVoiceInfo()) // suspends
- { // The parcel voice URI has changed.. break out and reconnect.
- break;
- }
-
- if (sShuttingDown)
- {
- return false;
- }
- }
- // Do the calculation that enforces the listener<->speaker tether (and also updates the real camera position)
- enforceTether();
- }
- sendPositionAndVolumeUpdate();
-
- // Do notifications for expiring Voice Fonts.
- if (mVoiceFontExpiryTimer.hasExpired())
- {
- expireVoiceFonts();
- mVoiceFontExpiryTimer.setTimerExpirySec(VOICE_FONT_EXPIRY_INTERVAL);
- }
-
- // send any requests to adjust mic and speaker settings if they have changed
- sendLocalAudioUpdates();
-
- mIsInitialized = true;
- LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, UPDATE_THROTTLE_SECONDS, timeoutEvent);
-
- if (sShuttingDown)
- {
- return false;
- }
-
- if (!result.has("timeout")) // logging the timeout event spams the log
- {
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- }
- if (result.has("session"))
- {
- if (result.has("handle"))
- {
- if (!mAudioSession)
- {
- LL_WARNS("Voice") << "Message for session handle \"" << result["handle"] << "\" while session is not initiated." << LL_ENDL;
- continue;
- }
- if (result["handle"] != mAudioSession->mHandle)
- {
- LL_WARNS("Voice") << "Message for session handle \"" << result["handle"] << "\" while waiting for \"" << mAudioSession->mHandle << "\"." << LL_ENDL;
- continue;
- }
- }
-
- std::string message = result["session"];
-
- if (message == "removed")
- {
- LL_DEBUGS("Voice") << "session removed" << LL_ENDL;
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
- break;
- }
- }
- else if (result.has("login"))
- {
- std::string message = result["login"];
- if (message == "account_logout")
- {
- LL_DEBUGS("Voice") << "logged out" << LL_ENDL;
- mIsLoggedIn = false;
- mRelogRequested = true;
- break;
- }
- }
- }
-
- if (sShuttingDown)
- {
- return false;
- }
-
- mIsInChannel = false;
- LL_DEBUGS("Voice") << "terminating at end of runSession" << LL_ENDL;
- terminateAudioSession(true);
-
- return true;
-}
-
-void LLVivoxVoiceClient::sendCaptureAndRenderDevices()
-{
- if (mCaptureDeviceDirty || mRenderDeviceDirty)
- {
- std::ostringstream stream;
-
- buildSetCaptureDevice(stream);
- buildSetRenderDevice(stream);
-
- if (!stream.str().empty())
- {
- writeString(stream.str());
- }
-
- llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
- }
-}
-
-void LLVivoxVoiceClient::recordingAndPlaybackMode()
-{
- LL_INFOS("Voice") << "In voice capture/playback mode." << LL_ENDL;
-
- while (true)
- {
- LLSD command;
- do
- {
- command = llcoro::suspendUntilEventOn(mVivoxPump);
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(command) << LL_ENDL;
- } while (!command.has("recplay"));
-
- if (command["recplay"].asString() == "quit")
- {
- mCaptureBufferMode = false;
- break;
- }
- else if (command["recplay"].asString() == "record")
- {
- voiceRecordBuffer();
- }
- else if (command["recplay"].asString() == "playback")
- {
- voicePlaybackBuffer();
- }
- }
-
- LL_INFOS("Voice") << "Leaving capture/playback mode." << LL_ENDL;
- mCaptureBufferRecording = false;
- mCaptureBufferRecorded = false;
- mCaptureBufferPlaying = false;
-
- return;
-}
-
-int LLVivoxVoiceClient::voiceRecordBuffer()
-{
- LLSD timeoutResult(LLSDMap("recplay", "stop"));
-
- LL_INFOS("Voice") << "Recording voice buffer" << LL_ENDL;
-
- LLSD result;
-
- captureBufferRecordStartSendMessage();
- notifyVoiceFontObservers();
-
- do
- {
- result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, CAPTURE_BUFFER_MAX_TIME, timeoutResult);
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- } while (!result.has("recplay"));
-
- mCaptureBufferRecorded = true;
-
- captureBufferRecordStopSendMessage();
- mCaptureBufferRecording = false;
-
- // Update UI, should really use a separate callback.
- notifyVoiceFontObservers();
-
- return true;
- /*TODO expand return to move directly into play*/
-}
-
-int LLVivoxVoiceClient::voicePlaybackBuffer()
-{
- LLSD timeoutResult(LLSDMap("recplay", "stop"));
-
- LL_INFOS("Voice") << "Playing voice buffer" << LL_ENDL;
-
- LLSD result;
-
- do
- {
- captureBufferPlayStartSendMessage(mPreviewVoiceFont);
-
- // Store the voice font being previewed, so that we know to restart if it changes.
- mPreviewVoiceFontLast = mPreviewVoiceFont;
-
- do
- {
- // Update UI, should really use a separate callback.
- notifyVoiceFontObservers();
-
- result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, CAPTURE_BUFFER_MAX_TIME, timeoutResult);
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- } while (!result.has("recplay"));
-
- if (result["recplay"] == "playback")
- continue; // restart playback... May be a font change.
-
- break;
- } while (true);
-
- // Stop playing.
- captureBufferPlayStopSendMessage();
- mCaptureBufferPlaying = false;
-
- // Update UI, should really use a separate callback.
- notifyVoiceFontObservers();
-
- return true;
-}
-
-
-bool LLVivoxVoiceClient::performMicTuning()
-{
- LL_INFOS("Voice") << "Entering voice tuning mode." << LL_ENDL;
- mIsInTuningMode = true;
-
- while (mTuningMode && !sShuttingDown)
- {
- llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
- }
-
- mIsInTuningMode = false;
-
- //---------------------------------------------------------------------
- return true;
-}
-
-//=========================================================================
-
-void LLVivoxVoiceClient::closeSocket(void)
-{
- mSocket.reset();
- sConnected = false;
- mConnectorEstablished = false;
- mAccountLoggedIn = false;
-}
-
-void LLVivoxVoiceClient::loginSendMessage()
-{
- std::ostringstream stream;
-
- bool autoPostCrashDumps = gSavedSettings.getBOOL("VivoxAutoPostCrashDumps");
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Login.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<AccountName>" << mAccountName << "</AccountName>"
- << "<AccountPassword>" << mAccountPassword << "</AccountPassword>"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "<AudioSessionAnswerMode>VerifyAnswer</AudioSessionAnswerMode>"
- << "<EnableBuddiesAndPresence>false</EnableBuddiesAndPresence>"
- << "<EnablePresencePersistence>0</EnablePresencePersistence>"
- << "<BuddyManagementMode>Application</BuddyManagementMode>"
- << "<ParticipantPropertyFrequency>5</ParticipantPropertyFrequency>"
- << (autoPostCrashDumps?"<AutopostCrashDumps>true</AutopostCrashDumps>":"")
- << "</Request>\n\n\n";
-
- LL_INFOS("Voice") << "Attempting voice login" << LL_ENDL;
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::logout()
-{
- // Ensure that we'll re-request provisioning before logging in again
- mAccountPassword.clear();
- mVoiceAccountServerURI.clear();
-
- logoutSendMessage();
-}
-
-void LLVivoxVoiceClient::logoutSendMessage()
-{
- if(mAccountLoggedIn)
- {
- LL_INFOS("Voice") << "Attempting voice logout" << LL_ENDL;
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Logout.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "</Request>"
- << "\n\n\n";
-
- mAccountLoggedIn = false;
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::sessionGroupCreateSendMessage()
-{
- if(mAccountLoggedIn)
- {
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "creating session group" << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.Create.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "<Type>Normal</Type>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::sessionCreateSendMessage(const sessionStatePtr_t &session, bool startAudio, bool startText)
-{
- S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
- LL_DEBUGS("Voice") << "Requesting create: " << session->mSIPURI
- << " with voice font: " << session->mVoiceFontID << " (" << font_index << ")"
- << LL_ENDL;
-
- session->mCreateInProgress = true;
- if(startAudio)
- {
- session->mMediaConnectInProgress = true;
- }
-
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << session->mSIPURI << "\" action=\"Session.Create.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "<URI>" << session->mSIPURI << "</URI>";
-
- static const std::string allowed_chars =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789"
- "-._~";
-
- if(!session->mHash.empty())
- {
- stream
- << "<Password>" << LLURI::escape(session->mHash, allowed_chars) << "</Password>"
- << "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>";
- }
-
- stream
- << "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>"
- << "<ConnectText>" << (startText?"true":"false") << "</ConnectText>"
- << "<Name>" << mChannelName << "</Name>"
- << "</Request>\n\n\n";
- LL_WARNS("Voice") << "Session.Create: " << stream.str() << LL_ENDL;
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::sessionGroupAddSessionSendMessage(const sessionStatePtr_t &session, bool startAudio, bool startText)
-{
- LL_DEBUGS("Voice") << "Requesting create: " << session->mSIPURI << LL_ENDL;
-
- S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
- LL_DEBUGS("Voice") << "With voice font: " << session->mVoiceFontID << " (" << font_index << ")" << LL_ENDL;
-
- session->mCreateInProgress = true;
- if(startAudio)
- {
- session->mMediaConnectInProgress = true;
- }
-
- std::string password;
- if(!session->mHash.empty())
- {
- static const std::string allowed_chars =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789"
- "-._~"
- ;
- password = LLURI::escape(session->mHash, allowed_chars);
- }
-
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << session->mSIPURI << "\" action=\"SessionGroup.AddSession.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "<URI>" << session->mSIPURI << "</URI>"
- << "<Name>" << mChannelName << "</Name>"
- << "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>"
- << "<ConnectText>" << (startText?"true":"false") << "</ConnectText>"
- << "<Password>" << password << "</Password>"
- << "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>"
- << "</Request>\n\n\n"
- ;
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::sessionMediaConnectSendMessage(const sessionStatePtr_t &session)
-{
- S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
- LL_DEBUGS("Voice") << "Connecting audio to session handle: " << session->mHandle
- << " with voice font: " << session->mVoiceFontID << " (" << font_index << ")"
- << LL_ENDL;
-
- session->mMediaConnectInProgress = true;
-
- std::ostringstream stream;
-
- stream
- << "<Request requestId=\"" << session->mHandle << "\" action=\"Session.MediaConnect.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "<Media>Audio</Media>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::sessionTextConnectSendMessage(const sessionStatePtr_t &session)
-{
- LL_DEBUGS("Voice") << "connecting text to session handle: " << session->mHandle << LL_ENDL;
-
- std::ostringstream stream;
-
- stream
- << "<Request requestId=\"" << session->mHandle << "\" action=\"Session.TextConnect.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::sessionTerminate()
-{
- mSessionTerminateRequested = true;
-}
-
-void LLVivoxVoiceClient::requestRelog()
-{
- mSessionTerminateRequested = true;
- mRelogRequested = true;
-}
-
-
-void LLVivoxVoiceClient::leaveAudioSession()
-{
- if(mAudioSession)
- {
- LL_DEBUGS("Voice") << "leaving session: " << mAudioSession->mSIPURI << LL_ENDL;
-
- if(!mAudioSession->mHandle.empty())
- {
-
-#if RECORD_EVERYTHING
- // HACK: for testing only
- // Save looped recording
- std::string savepath("/tmp/vivoxrecording");
- {
- time_t now = time(NULL);
- const size_t BUF_SIZE = 64;
- char time_str[BUF_SIZE]; /* Flawfinder: ignore */
-
- strftime(time_str, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
- savepath += time_str;
- }
- recordingLoopSave(savepath);
-#endif
-
- sessionMediaDisconnectSendMessage(mAudioSession);
- }
- else
- {
- LL_WARNS("Voice") << "called with no session handle" << LL_ENDL;
- }
- }
- else
- {
- LL_WARNS("Voice") << "called with no active session" << LL_ENDL;
- }
- sessionTerminate();
-}
-
-void LLVivoxVoiceClient::sessionTerminateSendMessage(const sessionStatePtr_t &session)
-{
- std::ostringstream stream;
-
- sessionGroupTerminateSendMessage(session);
- return;
- /*
- LL_DEBUGS("Voice") << "Sending Session.Terminate with handle " << session->mHandle << LL_ENDL;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Terminate.1\">"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
- */
-}
-
-void LLVivoxVoiceClient::sessionGroupTerminateSendMessage(const sessionStatePtr_t &session)
-{
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Sending SessionGroup.Terminate with handle " << session->mGroupHandle << LL_ENDL;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.Terminate.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::sessionMediaDisconnectSendMessage(const sessionStatePtr_t &session)
-{
- std::ostringstream stream;
- sessionGroupTerminateSendMessage(session);
- return;
- /*
- LL_DEBUGS("Voice") << "Sending Session.MediaDisconnect with handle " << session->mHandle << LL_ENDL;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.MediaDisconnect.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "<Media>Audio</Media>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
- */
-
-}
-
-
-void LLVivoxVoiceClient::getCaptureDevicesSendMessage()
-{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetCaptureDevices.1\">"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::getRenderDevicesSendMessage()
-{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetRenderDevices.1\">"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::clearCaptureDevices()
-{
- LL_DEBUGS("Voice") << "called" << LL_ENDL;
- mCaptureDevices.clear();
-}
-
-void LLVivoxVoiceClient::addCaptureDevice(const LLVoiceDevice& device)
-{
- LL_DEBUGS("Voice") << "display: '" << device.display_name << "' device: '" << device.full_name << "'" << LL_ENDL;
- mCaptureDevices.push_back(device);
-}
-
-LLVoiceDeviceList& LLVivoxVoiceClient::getCaptureDevices()
-{
- return mCaptureDevices;
-}
-
-void LLVivoxVoiceClient::setCaptureDevice(const std::string& name)
-{
- if(name == "Default")
- {
- if(!mCaptureDevice.empty())
- {
- mCaptureDevice.clear();
- mCaptureDeviceDirty = true;
- }
- }
- else
- {
- if(mCaptureDevice != name)
- {
- mCaptureDevice = name;
- mCaptureDeviceDirty = true;
- }
- }
-}
-void LLVivoxVoiceClient::setDevicesListUpdated(bool state)
-{
- mDevicesListUpdated = state;
-}
-
-void LLVivoxVoiceClient::clearRenderDevices()
-{
- LL_DEBUGS("Voice") << "called" << LL_ENDL;
- mRenderDevices.clear();
-}
-
-void LLVivoxVoiceClient::addRenderDevice(const LLVoiceDevice& device)
-{
- LL_DEBUGS("Voice") << "display: '" << device.display_name << "' device: '" << device.full_name << "'" << LL_ENDL;
- mRenderDevices.push_back(device);
-}
-
-LLVoiceDeviceList& LLVivoxVoiceClient::getRenderDevices()
-{
- return mRenderDevices;
-}
-
-void LLVivoxVoiceClient::setRenderDevice(const std::string& name)
-{
- if(name == "Default")
- {
- if(!mRenderDevice.empty())
- {
- mRenderDevice.clear();
- mRenderDeviceDirty = true;
- }
- }
- else
- {
- if(mRenderDevice != name)
- {
- mRenderDevice = name;
- mRenderDeviceDirty = true;
- }
- }
-
-}
-
-void LLVivoxVoiceClient::tuningStart()
-{
- LL_DEBUGS("Voice") << "Starting tuning" << LL_ENDL;
- mTuningMode = true;
- if (!mIsCoroutineActive)
- {
- LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro",
- boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance()));
- }
- else if (mIsInChannel)
- {
- LL_DEBUGS("Voice") << "no channel" << LL_ENDL;
- sessionTerminate();
- }
-}
-
-void LLVivoxVoiceClient::tuningStop()
-{
- mTuningMode = false;
- // force a renegotiation.
- mCurrentParcelLocalID = 0;
- mCurrentRegionName = "";
-}
-
-bool LLVivoxVoiceClient::inTuningMode()
-{
- return mIsInTuningMode;
-}
-
-void LLVivoxVoiceClient::tuningRenderStartSendMessage(const std::string& name, bool loop)
-{
- mTuningAudioFile = name;
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStart.1\">"
- << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>"
- << "<Loop>" << (loop?"1":"0") << "</Loop>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::tuningRenderStopSendMessage()
-{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStop.1\">"
- << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::tuningCaptureStartSendMessage(int loop)
-{
- LL_DEBUGS("Voice") << "sending CaptureAudioStart" << LL_ENDL;
-
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStart.1\">"
- << "<Duration>-1</Duration>"
- << "<LoopToRenderDevice>" << loop << "</LoopToRenderDevice>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::tuningCaptureStopSendMessage()
-{
- LL_DEBUGS("Voice") << "sending CaptureAudioStop" << LL_ENDL;
-
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStop.1\">"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-
- mTuningEnergy = 0.0f;
-}
-
-void LLVivoxVoiceClient::tuningSetMicVolume(float volume)
-{
- int scaled_volume = scale_mic_volume(volume);
-
- if(scaled_volume != mTuningMicVolume)
- {
- mTuningMicVolume = scaled_volume;
- mTuningMicVolumeDirty = true;
- }
-}
-
-void LLVivoxVoiceClient::tuningSetSpeakerVolume(float volume)
-{
- int scaled_volume = scale_speaker_volume(volume);
-
- if(scaled_volume != mTuningSpeakerVolume)
- {
- mTuningSpeakerVolume = scaled_volume;
- mTuningSpeakerVolumeDirty = true;
- }
-}
-
-float LLVivoxVoiceClient::tuningGetEnergy(void)
-{
- return mTuningEnergy;
-}
-
-bool LLVivoxVoiceClient::deviceSettingsAvailable()
-{
- bool result = true;
-
- if(!sConnected)
- result = false;
-
- if(mRenderDevices.empty())
- result = false;
-
- return result;
-}
-bool LLVivoxVoiceClient::deviceSettingsUpdated()
-{
- bool updated = mDevicesListUpdated;
- if (mDevicesListUpdated)
- {
- // a hot swap event or a polling of the audio devices has been parsed since the last redraw of the input and output device panel.
- mDevicesListUpdated = false; // toggle the setting
- }
- return updated;
-}
-
-void LLVivoxVoiceClient::refreshDeviceLists(bool clearCurrentList)
-{
- if(clearCurrentList)
- {
- clearCaptureDevices();
- clearRenderDevices();
- }
- getCaptureDevicesSendMessage();
- getRenderDevicesSendMessage();
-}
-
-void LLVivoxVoiceClient::daemonDied()
-{
- // The daemon died, so the connection is gone. Reset everything and start over.
- LL_WARNS("Voice") << "Connection to vivox daemon lost. Resetting state."<< LL_ENDL;
-
- //TODO: Try to relaunch the daemon
-}
-
-void LLVivoxVoiceClient::giveUp()
-{
- // All has failed. Clean up and stop trying.
- LL_WARNS("Voice") << "Terminating Voice Service" << LL_ENDL;
- closeSocket();
- cleanUp();
-}
-
-static void oldSDKTransform (LLVector3 &left, LLVector3 &up, LLVector3 &at, LLVector3d &pos, LLVector3 &vel)
-{
- F32 nat[3], nup[3], nl[3]; // the new at, up, left vectors and the new position and velocity
-// F32 nvel[3];
- F64 npos[3];
-
- // The original XML command was sent like this:
- /*
- << "<Position>"
- << "<X>" << pos[VX] << "</X>"
- << "<Y>" << pos[VZ] << "</Y>"
- << "<Z>" << pos[VY] << "</Z>"
- << "</Position>"
- << "<Velocity>"
- << "<X>" << mAvatarVelocity[VX] << "</X>"
- << "<Y>" << mAvatarVelocity[VZ] << "</Y>"
- << "<Z>" << mAvatarVelocity[VY] << "</Z>"
- << "</Velocity>"
- << "<AtOrientation>"
- << "<X>" << l.mV[VX] << "</X>"
- << "<Y>" << u.mV[VX] << "</Y>"
- << "<Z>" << a.mV[VX] << "</Z>"
- << "</AtOrientation>"
- << "<UpOrientation>"
- << "<X>" << l.mV[VZ] << "</X>"
- << "<Y>" << u.mV[VY] << "</Y>"
- << "<Z>" << a.mV[VZ] << "</Z>"
- << "</UpOrientation>"
- << "<LeftOrientation>"
- << "<X>" << l.mV [VY] << "</X>"
- << "<Y>" << u.mV [VZ] << "</Y>"
- << "<Z>" << a.mV [VY] << "</Z>"
- << "</LeftOrientation>";
- */
-
-#if 1
- // This was the original transform done when building the XML command
- nat[0] = left.mV[VX];
- nat[1] = up.mV[VX];
- nat[2] = at.mV[VX];
-
- nup[0] = left.mV[VZ];
- nup[1] = up.mV[VY];
- nup[2] = at.mV[VZ];
-
- nl[0] = left.mV[VY];
- nl[1] = up.mV[VZ];
- nl[2] = at.mV[VY];
-
- npos[0] = pos.mdV[VX];
- npos[1] = pos.mdV[VZ];
- npos[2] = pos.mdV[VY];
-
-// nvel[0] = vel.mV[VX];
-// nvel[1] = vel.mV[VZ];
-// nvel[2] = vel.mV[VY];
-
- for(int i=0;i<3;++i) {
- at.mV[i] = nat[i];
- up.mV[i] = nup[i];
- left.mV[i] = nl[i];
- pos.mdV[i] = npos[i];
- }
-
- // This was the original transform done in the SDK
- nat[0] = at.mV[2];
- nat[1] = 0; // y component of at vector is always 0, this was up[2]
- nat[2] = -1 * left.mV[2];
-
- // We override whatever the application gives us
- nup[0] = 0; // x component of up vector is always 0
- nup[1] = 1; // y component of up vector is always 1
- nup[2] = 0; // z component of up vector is always 0
-
- nl[0] = at.mV[0];
- nl[1] = 0; // y component of left vector is always zero, this was up[0]
- nl[2] = -1 * left.mV[0];
-
- npos[2] = pos.mdV[2] * -1.0;
- npos[1] = pos.mdV[1];
- npos[0] = pos.mdV[0];
-
- for(int i=0;i<3;++i) {
- at.mV[i] = nat[i];
- up.mV[i] = nup[i];
- left.mV[i] = nl[i];
- pos.mdV[i] = npos[i];
- }
-#else
- // This is the compose of the two transforms (at least, that's what I'm trying for)
- nat[0] = at.mV[VX];
- nat[1] = 0; // y component of at vector is always 0, this was up[2]
- nat[2] = -1 * up.mV[VZ];
-
- // We override whatever the application gives us
- nup[0] = 0; // x component of up vector is always 0
- nup[1] = 1; // y component of up vector is always 1
- nup[2] = 0; // z component of up vector is always 0
-
- nl[0] = left.mV[VX];
- nl[1] = 0; // y component of left vector is always zero, this was up[0]
- nl[2] = -1 * left.mV[VY];
-
- npos[0] = pos.mdV[VX];
- npos[1] = pos.mdV[VZ];
- npos[2] = pos.mdV[VY] * -1.0;
-
- nvel[0] = vel.mV[VX];
- nvel[1] = vel.mV[VZ];
- nvel[2] = vel.mV[VY];
-
- for(int i=0;i<3;++i) {
- at.mV[i] = nat[i];
- up.mV[i] = nup[i];
- left.mV[i] = nl[i];
- pos.mdV[i] = npos[i];
- }
-
-#endif
-}
-
-void LLVivoxVoiceClient::setHidden(bool hidden)
-{
- mHidden = hidden;
-
- if (mHidden && inSpatialChannel())
- {
- // get out of the channel entirely
- leaveAudioSession();
- }
- else
- {
- sendPositionAndVolumeUpdate();
- }
-}
-
-void LLVivoxVoiceClient::sendPositionAndVolumeUpdate(void)
-{
- std::ostringstream stream;
-
- if (mSpatialCoordsDirty && inSpatialChannel())
- {
- LLVector3 l, u, a, vel;
- LLVector3d pos;
-
- mSpatialCoordsDirty = false;
-
- // Always send both speaker and listener positions together.
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Set3DPosition.1\">"
- << "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>";
-
- stream << "<SpeakerPosition>";
-
- LLMatrix3 avatarRot = mAvatarRot.getMatrix3();
-
-// LL_DEBUGS("Voice") << "Sending speaker position " << mAvatarPosition << LL_ENDL;
- l = avatarRot.getLeftRow();
- u = avatarRot.getUpRow();
- a = avatarRot.getFwdRow();
-
- pos = mAvatarPosition;
- vel = mAvatarVelocity;
-
- // SLIM SDK: the old SDK was doing a transform on the passed coordinates that the new one doesn't do anymore.
- // The old transform is replicated by this function.
- oldSDKTransform(l, u, a, pos, vel);
-
- if (mHidden)
- {
- for (int i=0;i<3;++i)
- {
- pos.mdV[i] = VX_NULL_POSITION;
- }
- }
-
- stream
- << "<Position>"
- << "<X>" << pos.mdV[VX] << "</X>"
- << "<Y>" << pos.mdV[VY] << "</Y>"
- << "<Z>" << pos.mdV[VZ] << "</Z>"
- << "</Position>"
- << "<Velocity>"
- << "<X>" << vel.mV[VX] << "</X>"
- << "<Y>" << vel.mV[VY] << "</Y>"
- << "<Z>" << vel.mV[VZ] << "</Z>"
- << "</Velocity>"
- << "<AtOrientation>"
- << "<X>" << a.mV[VX] << "</X>"
- << "<Y>" << a.mV[VY] << "</Y>"
- << "<Z>" << a.mV[VZ] << "</Z>"
- << "</AtOrientation>"
- << "<UpOrientation>"
- << "<X>" << u.mV[VX] << "</X>"
- << "<Y>" << u.mV[VY] << "</Y>"
- << "<Z>" << u.mV[VZ] << "</Z>"
- << "</UpOrientation>"
- << "<LeftOrientation>"
- << "<X>" << l.mV [VX] << "</X>"
- << "<Y>" << l.mV [VY] << "</Y>"
- << "<Z>" << l.mV [VZ] << "</Z>"
- << "</LeftOrientation>"
- ;
-
- stream << "</SpeakerPosition>";
-
- stream << "<ListenerPosition>";
-
- LLVector3d earPosition;
- LLVector3 earVelocity;
- LLMatrix3 earRot;
-
- switch(mEarLocation)
- {
- case earLocCamera:
- default:
- earPosition = mCameraPosition;
- earVelocity = mCameraVelocity;
- earRot = mCameraRot;
- break;
-
- case earLocAvatar:
- earPosition = mAvatarPosition;
- earVelocity = mAvatarVelocity;
- earRot = avatarRot;
- break;
-
- case earLocMixed:
- earPosition = mAvatarPosition;
- earVelocity = mAvatarVelocity;
- earRot = mCameraRot;
- break;
- }
-
- l = earRot.getLeftRow();
- u = earRot.getUpRow();
- a = earRot.getFwdRow();
-
- pos = earPosition;
- vel = earVelocity;
-
-
- oldSDKTransform(l, u, a, pos, vel);
-
- if (mHidden)
- {
- for (int i=0;i<3;++i)
- {
- pos.mdV[i] = VX_NULL_POSITION;
- }
- }
-
- stream
- << "<Position>"
- << "<X>" << pos.mdV[VX] << "</X>"
- << "<Y>" << pos.mdV[VY] << "</Y>"
- << "<Z>" << pos.mdV[VZ] << "</Z>"
- << "</Position>"
- << "<Velocity>"
- << "<X>" << vel.mV[VX] << "</X>"
- << "<Y>" << vel.mV[VY] << "</Y>"
- << "<Z>" << vel.mV[VZ] << "</Z>"
- << "</Velocity>"
- << "<AtOrientation>"
- << "<X>" << a.mV[VX] << "</X>"
- << "<Y>" << a.mV[VY] << "</Y>"
- << "<Z>" << a.mV[VZ] << "</Z>"
- << "</AtOrientation>"
- << "<UpOrientation>"
- << "<X>" << u.mV[VX] << "</X>"
- << "<Y>" << u.mV[VY] << "</Y>"
- << "<Z>" << u.mV[VZ] << "</Z>"
- << "</UpOrientation>"
- << "<LeftOrientation>"
- << "<X>" << l.mV [VX] << "</X>"
- << "<Y>" << l.mV [VY] << "</Y>"
- << "<Z>" << l.mV [VZ] << "</Z>"
- << "</LeftOrientation>"
- ;
-
- stream << "</ListenerPosition>";
-
- stream << "<ReqDispositionType>1</ReqDispositionType>"; //do not generate responses for update requests
- stream << "</Request>\n\n\n";
- }
-
- if(mAudioSession && (mAudioSession->mVolumeDirty || mAudioSession->mMuteDirty))
- {
- participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin();
-
- mAudioSession->mVolumeDirty = false;
- mAudioSession->mMuteDirty = false;
-
- for(; iter != mAudioSession->mParticipantsByURI.end(); iter++)
- {
- participantStatePtr_t p(iter->second);
-
- if(p->mVolumeDirty)
- {
- // Can't set volume/mute for yourself
- if(!p->mIsSelf)
- {
- // scale from the range 0.0-1.0 to vivox volume in the range 0-100
- S32 volume = ll_round(p->mVolume / VOLUME_SCALE_VIVOX);
- bool mute = p->mOnMuteList;
-
- if(mute)
- {
- // SetParticipantMuteForMe doesn't work in p2p sessions.
- // If we want the user to be muted, set their volume to 0 as well.
- // This isn't perfect, but it will at least reduce their volume to a minimum.
- volume = 0;
- // Mark the current volume level as set to prevent incoming events
- // changing it to 0, so that we can return to it when unmuting.
- p->mVolumeSet = true;
- }
-
- if(volume == 0)
- {
- mute = true;
- }
-
- LL_DEBUGS("Voice") << "Setting volume/mute for avatar " << p->mAvatarID << " to " << volume << (mute?"/true":"/false") << LL_ENDL;
-
- // SLIM SDK: Send both volume and mute commands.
-
- // Send a "volume for me" command for the user.
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetParticipantVolumeForMe.1\">"
- << "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>"
- << "<ParticipantURI>" << p->mURI << "</ParticipantURI>"
- << "<Volume>" << volume << "</Volume>"
- << "</Request>\n\n\n";
-
- if(!mAudioSession->mIsP2P)
- {
- // Send a "mute for me" command for the user
- // Doesn't work in P2P sessions
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetParticipantMuteForMe.1\">"
- << "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>"
- << "<ParticipantURI>" << p->mURI << "</ParticipantURI>"
- << "<Mute>" << (mute?"1":"0") << "</Mute>"
- << "<Scope>Audio</Scope>"
- << "</Request>\n\n\n";
- }
- }
-
- p->mVolumeDirty = false;
- }
- }
- }
-
- std::string update(stream.str());
- if(!update.empty())
- {
- LL_DEBUGS("VoiceUpdate") << "sending update " << update << LL_ENDL;
- writeString(update);
- }
-
-}
-
-void LLVivoxVoiceClient::buildSetCaptureDevice(std::ostringstream &stream)
-{
- if(mCaptureDeviceDirty)
- {
- LL_DEBUGS("Voice") << "Setting input device = \"" << mCaptureDevice << "\"" << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetCaptureDevice.1\">"
- << "<CaptureDeviceSpecifier>" << mCaptureDevice << "</CaptureDeviceSpecifier>"
- << "</Request>"
- << "\n\n\n";
-
- mCaptureDeviceDirty = false;
- }
-}
-
-void LLVivoxVoiceClient::buildSetRenderDevice(std::ostringstream &stream)
-{
- if(mRenderDeviceDirty)
- {
- LL_DEBUGS("Voice") << "Setting output device = \"" << mRenderDevice << "\"" << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetRenderDevice.1\">"
- << "<RenderDeviceSpecifier>" << mRenderDevice << "</RenderDeviceSpecifier>"
- << "</Request>"
- << "\n\n\n";
- mRenderDeviceDirty = false;
- }
-}
-
-void LLVivoxVoiceClient::sendLocalAudioUpdates()
-{
- // Check all of the dirty states and then send messages to those needing to be changed.
- // Tuningmode hands its own mute settings.
- std::ostringstream stream;
-
- if (mMuteMicDirty && !mTuningMode)
- {
- mMuteMicDirty = false;
-
- // Send a local mute command.
-
- LL_INFOS("Voice") << "Sending MuteLocalMic command with parameter " << (mMuteMic ? "true" : "false") << LL_ENDL;
-
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Value>" << (mMuteMic ? "true" : "false") << "</Value>"
- << "</Request>\n\n\n";
-
- }
-
- if (mSpeakerMuteDirty && !mTuningMode)
- {
- const char *muteval = ((mSpeakerVolume <= scale_speaker_volume(0)) ? "true" : "false");
-
- mSpeakerMuteDirty = false;
-
- LL_INFOS("Voice") << "Setting speaker mute to " << muteval << LL_ENDL;
-
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalSpeaker.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Value>" << muteval << "</Value>"
- << "</Request>\n\n\n";
-
- }
-
- if (mSpeakerVolumeDirty)
- {
- mSpeakerVolumeDirty = false;
-
- LL_INFOS("Voice") << "Setting speaker volume to " << mSpeakerVolume << LL_ENDL;
-
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalSpeakerVolume.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Value>" << mSpeakerVolume << "</Value>"
- << "</Request>\n\n\n";
-
- }
-
- if (mMicVolumeDirty)
- {
- mMicVolumeDirty = false;
-
- LL_INFOS("Voice") << "Setting mic volume to " << mMicVolume << LL_ENDL;
-
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalMicVolume.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Value>" << mMicVolume << "</Value>"
- << "</Request>\n\n\n";
- }
-
-
- if (!stream.str().empty())
- {
- writeString(stream.str());
- }
-}
-
-/**
- * Because of the recurring voice cutout issues (SL-15072) we are going to try
- * to disable the automatic VAD (Voice Activity Detection) and set the associated
- * parameters directly. We will expose them via Debug Settings and that should
- * let us iterate on a collection of values that work for us. Hopefully!
- *
- * From the VIVOX Docs:
- *
- * VadAuto: A flag indicating if the automatic VAD is enabled (1) or disabled (0)
- *
- * VadHangover: The time (in milliseconds) that it takes
- * for the VAD to switch back to silence from speech mode after the last speech
- * frame has been detected.
- *
- * VadNoiseFloor: A dimensionless value between 0 and
- * 20000 (default 576) that controls the maximum level at which the noise floor
- * may be set at by the VAD's noise tracking. Too low of a value will make noise
- * tracking ineffective (A value of 0 disables noise tracking and the VAD then
- * relies purely on the sensitivity property). Too high of a value will make
- * long speech classifiable as noise.
- *
- * VadSensitivity: A dimensionless value between 0 and
- * 100, indicating the 'sensitivity of the VAD'. Increasing this value corresponds
- * to decreasing the sensitivity of the VAD (i.e. '0' is most sensitive,
- * while 100 is 'least sensitive')
- */
-void LLVivoxVoiceClient::setupVADParams(unsigned int vad_auto,
- unsigned int vad_hangover,
- unsigned int vad_noise_floor,
- unsigned int vad_sensitivity)
-{
- std::ostringstream stream;
-
- LL_INFOS("Voice") << "Setting the automatic VAD to "
- << (vad_auto ? "True" : "False")
- << " and discrete values to"
- << " VadHangover = " << vad_hangover
- << ", VadSensitivity = " << vad_sensitivity
- << ", VadNoiseFloor = " << vad_noise_floor
- << LL_ENDL;
-
- // Create a request to set the VAD parameters:
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetVadProperties.1\">"
- << "<VadAuto>" << vad_auto << "</VadAuto>"
- << "<VadHangover>" << vad_hangover << "</VadHangover>"
- << "<VadSensitivity>" << vad_sensitivity << "</VadSensitivity>"
- << "<VadNoiseFloor>" << vad_noise_floor << "</VadNoiseFloor>"
- << "</Request>\n\n\n";
-
- if (!stream.str().empty())
- {
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::onVADSettingsChange()
-{
- // pick up the VAD variables (one of which was changed)
- unsigned int vad_auto = gSavedSettings.getU32("VivoxVadAuto");
- unsigned int vad_hangover = gSavedSettings.getU32("VivoxVadHangover");
- unsigned int vad_noise_floor = gSavedSettings.getU32("VivoxVadNoiseFloor");
- unsigned int vad_sensitivity = gSavedSettings.getU32("VivoxVadSensitivity");
-
- // build a VAD params change request and send it to SLVoice
- setupVADParams(vad_auto, vad_hangover, vad_noise_floor, vad_sensitivity);
-}
-
-/////////////////////////////
-// Response/Event handlers
-
-void LLVivoxVoiceClient::connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID)
-{
- LLSD result = LLSD::emptyMap();
-
- if(statusCode == 0)
- {
- // Connector created, move forward.
- if (connectorHandle == LLVivoxSecurity::getInstance()->connectorHandle())
- {
- LL_INFOS("Voice") << "Voice connector succeeded, Vivox SDK version is " << versionID << " connector handle " << connectorHandle << LL_ENDL;
- mVoiceVersion.serverVersion = versionID;
- mConnectorEstablished = true;
- mTerminateDaemon = false;
-
- result["connector"] = LLSD::Boolean(true);
- }
- else
- {
- // This shouldn't happen - we are somehow out of sync with SLVoice
- // or possibly there are two things trying to run SLVoice at once
- // or someone is trying to hack into it.
- LL_WARNS("Voice") << "Connector returned wrong handle "
- << "(" << connectorHandle << ")"
- << " expected (" << LLVivoxSecurity::getInstance()->connectorHandle() << ")"
- << LL_ENDL;
- result["connector"] = LLSD::Boolean(false);
- // Give up.
- mTerminateDaemon = true;
- }
- }
- else if (statusCode == 10028) // web request timeout prior to login
- {
- // this is usually fatal, but a long timeout might work
- result["connector"] = LLSD::Boolean(false);
- result["retry"] = LLSD::Real(CONNECT_ATTEMPT_TIMEOUT);
-
- LL_WARNS("Voice") << "Voice connection failed" << LL_ENDL;
- }
- else if (statusCode == 10006) // name resolution failure - a shorter retry may work
- {
- // some networks have slower DNS, but a short timeout might let it catch up
- result["connector"] = LLSD::Boolean(false);
- result["retry"] = LLSD::Real(CONNECT_DNS_TIMEOUT);
-
- LL_WARNS("Voice") << "Voice connection DNS lookup failed" << LL_ENDL;
- }
- else // unknown failure - give up
- {
- LL_WARNS("Voice") << "Voice connection failure ("<< statusCode << "): " << statusString << LL_ENDL;
- mTerminateDaemon = true;
- result["connector"] = LLSD::Boolean(false);
- }
-
- mVivoxPump.post(result);
-}
-
-void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases)
-{
- LLSD result = LLSD::emptyMap();
-
- LL_DEBUGS("Voice") << "Account.Login response (" << statusCode << "): " << statusString << LL_ENDL;
-
- // Status code of 20200 means "bad password". We may want to special-case that at some point.
-
- if ( statusCode == HTTP_UNAUTHORIZED )
- {
- // Login failure which is probably caused by the delay after a user's password being updated.
- LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL;
- result["login"] = LLSD::String("retry");
- }
- else if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL;
- result["login"] = LLSD::String("failed");
- }
- else
- {
- // Login succeeded, move forward.
- mAccountLoggedIn = true;
- mNumberOfAliases = numberOfAliases;
- result["login"] = LLSD::String("response_ok");
- }
-
- mVivoxPump.post(result);
-
-}
-
-void LLVivoxVoiceClient::sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle)
-{
- sessionStatePtr_t session(findSessionBeingCreatedByURI(requestId));
-
- if(session)
- {
- session->mCreateInProgress = false;
- }
-
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Session.Create response failure (" << statusCode << "): " << statusString << LL_ENDL;
- if(session)
- {
- session->mErrorStatusCode = statusCode;
- session->mErrorStatusString = statusString;
- if(session == mAudioSession)
- {
- LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle))
- ("session", "failed")
- ("reason", LLSD::Integer(statusCode)));
-
- mVivoxPump.post(vivoxevent);
- }
- else
- {
- reapSession(session);
- }
- }
- }
- else
- {
- LL_INFOS("Voice") << "Session.Create response received (success), session handle is " << sessionHandle << LL_ENDL;
- if(session)
- {
- setSessionHandle(session, sessionHandle);
- }
- LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle))
- ("session", "created"));
-
- mVivoxPump.post(vivoxevent);
- }
-}
-
-void LLVivoxVoiceClient::sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle)
-{
- sessionStatePtr_t session(findSessionBeingCreatedByURI(requestId));
-
- if(session)
- {
- session->mCreateInProgress = false;
- }
-
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "SessionGroup.AddSession response failure (" << statusCode << "): " << statusString << LL_ENDL;
- if(session)
- {
- session->mErrorStatusCode = statusCode;
- session->mErrorStatusString = statusString;
- if(session == mAudioSession)
- {
- LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle))
- ("session", "failed"));
-
- mVivoxPump.post(vivoxevent);
- }
- else
- {
- reapSession(session);
- }
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "SessionGroup.AddSession response received (success), session handle is " << sessionHandle << LL_ENDL;
- if(session)
- {
- setSessionHandle(session, sessionHandle);
- }
-
- LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle))
- ("session", "added"));
-
- mVivoxPump.post(vivoxevent);
-
- }
-}
-
-void LLVivoxVoiceClient::sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString)
-{
- sessionStatePtr_t session(findSession(requestId));
- // 1026 is session already has media, somehow mediaconnect was called twice on the same session.
- // set the session info to reflect that the user is already connected.
- if (statusCode == 1026)
- {
- session->mVoiceActive = true;
- session->mMediaConnectInProgress = false;
- session->mMediaStreamState = streamStateConnected;
- //session->mTextStreamState = streamStateConnected;
- session->mErrorStatusCode = 0;
- }
- else if (statusCode != 0)
- {
- LL_WARNS("Voice") << "Session.Connect response failure (" << statusCode << "): " << statusString << LL_ENDL;
- if (session)
- {
- session->mMediaConnectInProgress = false;
- session->mErrorStatusCode = statusCode;
- session->mErrorStatusString = statusString;
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "Session.Connect response received (success)" << LL_ENDL;
- }
-}
-
-void LLVivoxVoiceClient::logoutResponse(int statusCode, std::string &statusString)
-{
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Account.Logout response failure: " << statusString << LL_ENDL;
- // Should this ever fail? do we care if it does?
- }
- LLSD vivoxevent(LLSDMap("logout", LLSD::Boolean(true)));
-
- mVivoxPump.post(vivoxevent);
-}
-
-void LLVivoxVoiceClient::connectorShutdownResponse(int statusCode, std::string &statusString)
-{
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Connector.InitiateShutdown response failure: " << statusString << LL_ENDL;
- // Should this ever fail? do we care if it does?
- }
-
- sConnected = false;
- mShutdownComplete = true;
-
- LLSD vivoxevent(LLSDMap("connector", LLSD::Boolean(false)));
-
- mVivoxPump.post(vivoxevent);
-}
-
-void LLVivoxVoiceClient::sessionAddedEvent(
- std::string &uriString,
- std::string &alias,
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- bool isChannel,
- bool incoming,
- std::string &nameString,
- std::string &applicationString)
-{
- sessionStatePtr_t session;
-
- LL_INFOS("Voice") << "session " << uriString << ", alias " << alias << ", name " << nameString << " handle " << sessionHandle << LL_ENDL;
-
- session = addSession(uriString, sessionHandle);
- if(session)
- {
- session->mGroupHandle = sessionGroupHandle;
- session->mIsChannel = isChannel;
- session->mIncoming = incoming;
- session->mAlias = alias;
-
- // Generate a caller UUID -- don't need to do this for channels
- if(!session->mIsChannel)
- {
- if(IDFromName(session->mSIPURI, session->mCallerID))
- {
- // Normal URI(base64-encoded UUID)
- }
- else if(!session->mAlias.empty() && IDFromName(session->mAlias, session->mCallerID))
- {
- // Wrong URI, but an alias is available. Stash the incoming URI as an alternate
- session->mAlternateSIPURI = session->mSIPURI;
-
- // and generate a proper URI from the ID.
- setSessionURI(session, sipURIFromID(session->mCallerID));
- }
- else
- {
- LL_INFOS("Voice") << "Could not generate caller id from uri, using hash of uri " << session->mSIPURI << LL_ENDL;
- session->mCallerID.generate(session->mSIPURI);
- session->mSynthesizedCallerID = true;
-
- // Can't look up the name in this case -- we have to extract it from the URI.
- std::string namePortion = nameFromsipURI(session->mSIPURI);
- if(namePortion.empty())
- {
- // Didn't seem to be a SIP URI, just use the whole provided name.
- namePortion = nameString;
- }
-
- // Some incoming names may be separated with an underscore instead of a space. Fix this.
- LLStringUtil::replaceChar(namePortion, '_', ' ');
-
- // Act like we just finished resolving the name (this stores it in all the right places)
- avatarNameResolved(session->mCallerID, namePortion);
- }
-
- LL_INFOS("Voice") << "caller ID: " << session->mCallerID << LL_ENDL;
-
- if(!session->mSynthesizedCallerID)
- {
- // If we got here, we don't have a proper name. Initiate a lookup.
- lookupName(session->mCallerID);
- }
- }
- }
-}
-
-void LLVivoxVoiceClient::sessionGroupAddedEvent(std::string &sessionGroupHandle)
-{
- LL_DEBUGS("Voice") << "handle " << sessionGroupHandle << LL_ENDL;
-
-#if USE_SESSION_GROUPS
- if(mMainSessionGroupHandle.empty())
- {
- // This is the first (i.e. "main") session group. Save its handle.
- mMainSessionGroupHandle = sessionGroupHandle;
- }
- else
- {
- LL_DEBUGS("Voice") << "Already had a session group handle " << mMainSessionGroupHandle << LL_ENDL;
- }
-#endif
-}
-
-void LLVivoxVoiceClient::joinedAudioSession(const sessionStatePtr_t &session)
-{
- LL_DEBUGS("Voice") << "Joined Audio Session" << LL_ENDL;
- if(mAudioSession != session)
- {
- sessionStatePtr_t oldSession = mAudioSession;
-
- mAudioSession = session;
-
- // The old session may now need to be deleted.
- reapSession(oldSession);
- }
-
- // This is the session we're joining.
- if(mIsJoiningSession)
- {
- LLSD vivoxevent(LLSDMap("handle", LLSD::String(session->mHandle))
- ("session", "joined"));
-
- mVivoxPump.post(vivoxevent);
-
- // Add the current user as a participant here.
- participantStatePtr_t participant(session->addParticipant(sipURIFromName(mAccountName)));
- if(participant)
- {
- participant->mIsSelf = true;
- lookupName(participant->mAvatarID);
-
- LL_INFOS("Voice") << "added self as participant \"" << participant->mAccountName
- << "\" (" << participant->mAvatarID << ")"<< LL_ENDL;
- }
-
- if(!session->mIsChannel)
- {
- // this is a p2p session. Make sure the other end is added as a participant.
- participantStatePtr_t participant(session->addParticipant(session->mSIPURI));
- if(participant)
- {
- if(participant->mAvatarIDValid)
- {
- lookupName(participant->mAvatarID);
- }
- else if(!session->mName.empty())
- {
- participant->mDisplayName = session->mName;
- avatarNameResolved(participant->mAvatarID, session->mName);
- }
-
- // TODO: Question: Do we need to set up mAvatarID/mAvatarIDValid here?
- LL_INFOS("Voice") << "added caller as participant \"" << participant->mAccountName
- << "\" (" << participant->mAvatarID << ")"<< LL_ENDL;
- }
- }
- }
-}
-
-void LLVivoxVoiceClient::sessionRemovedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle)
-{
- LL_INFOS("Voice") << "handle " << sessionHandle << LL_ENDL;
-
- sessionStatePtr_t session(findSession(sessionHandle));
- if(session)
- {
- leftAudioSession(session);
-
- // This message invalidates the session's handle. Set it to empty.
- clearSessionHandle(session);
-
- // This also means that the session's session group is now empty.
- // Terminate the session group so it doesn't leak.
- sessionGroupTerminateSendMessage(session);
-
- // Reset the media state (we now have no info)
- session->mMediaStreamState = streamStateUnknown;
- //session->mTextStreamState = streamStateUnknown;
-
- // Conditionally delete the session
- reapSession(session);
- }
- else
- {
- // Already reaped this session.
- LL_DEBUGS("Voice") << "unknown session " << sessionHandle << " removed" << LL_ENDL;
- }
-
-}
-
-void LLVivoxVoiceClient::reapSession(const sessionStatePtr_t &session)
-{
- if(session)
- {
-
- if(session->mCreateInProgress)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (create in progress)" << LL_ENDL;
- }
- else if(session->mMediaConnectInProgress)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (connect in progress)" << LL_ENDL;
- }
- else if(session == mAudioSession)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the current session)" << LL_ENDL;
- }
- else if(session == mNextAudioSession)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the next session)" << LL_ENDL;
- }
- else
- {
- // We don't have a reason to keep tracking this session, so just delete it.
- LL_DEBUGS("Voice") << "deleting session " << session->mSIPURI << LL_ENDL;
- deleteSession(session);
- }
- }
- else
- {
-// LL_DEBUGS("Voice") << "session is NULL" << LL_ENDL;
- }
-}
-
-// Returns true if the session seems to indicate we've moved to a region on a different voice server
-bool LLVivoxVoiceClient::sessionNeedsRelog(const sessionStatePtr_t &session)
-{
- bool result = false;
-
- if(session)
- {
- // Only make this check for spatial channels (so it won't happen for group or p2p calls)
- if(session->mIsSpatial)
- {
- std::string::size_type atsign;
-
- atsign = session->mSIPURI.find("@");
-
- if(atsign != std::string::npos)
- {
- std::string urihost = session->mSIPURI.substr(atsign + 1);
- if(stricmp(urihost.c_str(), mVoiceSIPURIHostName.c_str()))
- {
- // The hostname in this URI is different from what we expect. This probably means we need to relog.
-
- // We could make a ProvisionVoiceAccountRequest and compare the result with the current values of
- // mVoiceSIPURIHostName and mVoiceAccountServerURI to be really sure, but this is a pretty good indicator.
-
- result = true;
- }
- }
- }
- }
-
- return result;
-}
-
-void LLVivoxVoiceClient::leftAudioSession(const sessionStatePtr_t &session)
-{
- if (mAudioSession == session)
- {
- LLSD vivoxevent(LLSDMap("handle", LLSD::String(session->mHandle))
- ("session", "removed"));
-
- mVivoxPump.post(vivoxevent);
- }
-}
-
-void LLVivoxVoiceClient::accountLoginStateChangeEvent(
- std::string &accountHandle,
- int statusCode,
- std::string &statusString,
- int state)
-{
- LLSD levent = LLSD::emptyMap();
-
- /*
- According to Mike S., status codes for this event are:
- login_state_logged_out=0,
- login_state_logged_in = 1,
- login_state_logging_in = 2,
- login_state_logging_out = 3,
- login_state_resetting = 4,
- login_state_error=100
- */
-
- LL_DEBUGS("Voice") << "state change event: " << state << LL_ENDL;
- switch(state)
- {
- case 1:
- levent["login"] = LLSD::String("account_login");
-
- mVivoxPump.post(levent);
- break;
- case 2:
- break;
-
- case 3:
- levent["login"] = LLSD::String("account_loggingOut");
-
- mVivoxPump.post(levent);
- break;
-
- case 4:
- break;
-
- case 100:
- LL_WARNS("Voice") << "account state event error" << LL_ENDL;
- break;
-
- case 0:
- levent["login"] = LLSD::String("account_logout");
-
- mVivoxPump.post(levent);
- break;
-
- default:
- //Used to be a commented out warning
- LL_WARNS("Voice") << "unknown account state event: " << state << LL_ENDL;
- break;
- }
-}
-
-void LLVivoxVoiceClient::mediaCompletionEvent(std::string &sessionGroupHandle, std::string &mediaCompletionType)
-{
- LLSD result;
-
- if (mediaCompletionType == "AuxBufferAudioCapture")
- {
- mCaptureBufferRecording = false;
- result["recplay"] = "end";
- }
- else if (mediaCompletionType == "AuxBufferAudioRender")
- {
- // Ignore all but the last stop event
- if (--mPlayRequestCount <= 0)
- {
- mCaptureBufferPlaying = false;
- result["recplay"] = "end";
-// result["recplay"] = "done";
- }
- }
- else
- {
- LL_WARNS("Voice") << "Unknown MediaCompletionType: " << mediaCompletionType << LL_ENDL;
- }
-
- if (!result.isUndefined())
- mVivoxPump.post(result);
-}
-
-void LLVivoxVoiceClient::mediaStreamUpdatedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- int statusCode,
- std::string &statusString,
- int state,
- bool incoming)
-{
- sessionStatePtr_t session(findSession(sessionHandle));
-
- LL_DEBUGS("Voice") << "session " << sessionHandle << ", status code " << statusCode << ", string \"" << statusString << "\"" << LL_ENDL;
-
- if(session)
- {
- // We know about this session
-
- // Save the state for later use
- session->mMediaStreamState = state;
-
- switch(statusCode)
- {
- case 0:
- case HTTP_OK:
- // generic success
- // Don't change the saved error code (it may have been set elsewhere)
- break;
- default:
- // save the status code for later
- session->mErrorStatusCode = statusCode;
- break;
- }
-
- switch(state)
- {
- case streamStateDisconnecting:
- case streamStateIdle:
- // Standard "left audio session", Vivox state 'disconnected'
- session->mVoiceActive = false;
- session->mMediaConnectInProgress = false;
- leftAudioSession(session);
- break;
-
- case streamStateConnected:
- session->mVoiceActive = true;
- session->mMediaConnectInProgress = false;
- joinedAudioSession(session);
- case streamStateConnecting: // do nothing, but prevents a warning getting into the logs.
- break;
-
- case streamStateRinging:
- if(incoming)
- {
- // Send the voice chat invite to the GUI layer
- // TODO: Question: Should we correlate with the mute list here?
- session->mIMSessionID = LLIMMgr::computeSessionID(IM_SESSION_P2P_INVITE, session->mCallerID);
- session->mVoiceInvitePending = true;
- if(session->mName.empty())
- {
- lookupName(session->mCallerID);
- }
- else
- {
- // Act like we just finished resolving the name
- avatarNameResolved(session->mCallerID, session->mName);
- }
- }
- break;
-
- default:
- LL_WARNS("Voice") << "unknown state " << state << LL_ENDL;
- break;
-
- }
-
- }
- else
- {
- // session disconnectintg and disconnected events arriving after we have already left the session.
- LL_DEBUGS("Voice") << "session " << sessionHandle << " not found"<< LL_ENDL;
- }
-}
-
-void LLVivoxVoiceClient::participantAddedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- std::string &uriString,
- std::string &alias,
- std::string &nameString,
- std::string &displayNameString,
- int participantType)
-{
- sessionStatePtr_t session(findSession(sessionHandle));
- if(session)
- {
- participantStatePtr_t participant(session->addParticipant(uriString));
- if(participant)
- {
- participant->mAccountName = nameString;
-
- LL_DEBUGS("Voice") << "added participant \"" << participant->mAccountName
- << "\" (" << participant->mAvatarID << ")"<< LL_ENDL;
-
- if(participant->mAvatarIDValid)
- {
- // Initiate a lookup
- lookupName(participant->mAvatarID);
- }
- else
- {
- // If we don't have a valid avatar UUID, we need to fill in the display name to make the active speakers floater work.
- std::string namePortion = nameFromsipURI(uriString);
- if(namePortion.empty())
- {
- // Problem with the SIP URI, fall back to the display name
- namePortion = displayNameString;
- }
- if(namePortion.empty())
- {
- // Problems with both of the above, fall back to the account name
- namePortion = nameString;
- }
-
- // Set the display name (which is a hint to the active speakers window not to do its own lookup)
- participant->mDisplayName = namePortion;
- avatarNameResolved(participant->mAvatarID, namePortion);
- }
- }
- }
-}
-
-void LLVivoxVoiceClient::participantRemovedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- std::string &uriString,
- std::string &alias,
- std::string &nameString)
-{
- sessionStatePtr_t session(findSession(sessionHandle));
- if(session)
- {
- participantStatePtr_t participant(session->findParticipant(uriString));
- if(participant)
- {
- session->removeParticipant(participant);
- }
- else
- {
- LL_DEBUGS("Voice") << "unknown participant " << uriString << LL_ENDL;
- }
- }
- else
- {
- // a late arriving event on a session we have already left.
- LL_DEBUGS("Voice") << "unknown session " << sessionHandle << LL_ENDL;
- }
-}
-
-
-void LLVivoxVoiceClient::participantUpdatedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- std::string &uriString,
- std::string &alias,
- bool isModeratorMuted,
- bool isSpeaking,
- int volume,
- F32 energy)
-{
- sessionStatePtr_t session(findSession(sessionHandle));
- if(session)
- {
- participantStatePtr_t participant(session->findParticipant(uriString));
-
- if(participant)
- {
- //LL_INFOS("Voice") << "Participant Update for " << participant->mDisplayName << LL_ENDL;
-
- participant->mIsSpeaking = isSpeaking;
- participant->mIsModeratorMuted = isModeratorMuted;
-
- // SLIM SDK: convert range: ensure that energy is set to zero if is_speaking is false
- if (isSpeaking)
- {
- participant->mSpeakingTimeout.reset();
- participant->mPower = energy;
- }
- else
- {
- participant->mPower = 0.0f;
- }
-
- // Ignore incoming volume level if it has been explicitly set, or there
- // is a volume or mute change pending.
- if ( !participant->mVolumeSet && !participant->mVolumeDirty)
- {
- participant->mVolume = (F32)volume * VOLUME_SCALE_VIVOX;
- }
-
- // *HACK: mantipov: added while working on EXT-3544
- /*
- Sometimes LLVoiceClient::participantUpdatedEvent callback is called BEFORE
- LLViewerChatterBoxSessionAgentListUpdates::post() sometimes AFTER.
-
- participantUpdatedEvent updates voice participant state in particular participantState::mIsModeratorMuted
- Originally we wanted to update session Speaker Manager to fire LLSpeakerVoiceModerationEvent to fix the EXT-3544 bug.
- Calling of the LLSpeakerMgr::update() method was added into LLIMMgr::processAgentListUpdates.
-
- But in case participantUpdatedEvent() is called after LLViewerChatterBoxSessionAgentListUpdates::post()
- voice participant mIsModeratorMuted is changed after speakers are updated in Speaker Manager
- and event is not fired.
-
- So, we have to call LLSpeakerMgr::update() here.
- */
- LLVoiceChannel* voice_cnl = LLVoiceChannel::getCurrentVoiceChannel();
-
- // ignore session ID of local chat
- if (voice_cnl && voice_cnl->getSessionID().notNull())
- {
- LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(voice_cnl->getSessionID());
- if (speaker_manager)
- {
- speaker_manager->update(true);
-
- // also initialize voice moderate_mode depend on Agent's participant. See EXT-6937.
- // *TODO: remove once a way to request the current voice channel moderation mode is implemented.
- if (gAgent.getID() == participant->mAvatarID)
- {
- speaker_manager->initVoiceModerateMode();
- }
- }
- }
- }
- else
- {
- LL_WARNS("Voice") << "unknown participant: " << uriString << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "unknown session " << sessionHandle << LL_ENDL;
- }
-}
-
-void LLVivoxVoiceClient::messageEvent(
- std::string &sessionHandle,
- std::string &uriString,
- std::string &alias,
- std::string &messageHeader,
- std::string &messageBody,
- std::string &applicationString)
-{
- LL_DEBUGS("Voice") << "Message event, session " << sessionHandle << " from " << uriString << LL_ENDL;
-// LL_DEBUGS("Voice") << " header " << messageHeader << ", body: \n" << messageBody << LL_ENDL;
-
- LL_INFOS("Voice") << "Vivox raw message:" << std::endl << messageBody << LL_ENDL;
-
- if(messageHeader.find(HTTP_CONTENT_TEXT_HTML) != std::string::npos)
- {
- std::string message;
-
- {
- const std::string startMarker = "<body";
- const std::string startMarker2 = ">";
- const std::string endMarker = "</body>";
- const std::string startSpan = "<span";
- const std::string endSpan = "</span>";
- std::string::size_type start;
- std::string::size_type end;
-
- // Default to displaying the raw string, so the message gets through.
- message = messageBody;
-
- // Find the actual message text within the XML fragment
- start = messageBody.find(startMarker);
- start = messageBody.find(startMarker2, start);
- end = messageBody.find(endMarker);
-
- if(start != std::string::npos)
- {
- start += startMarker2.size();
-
- if(end != std::string::npos)
- end -= start;
-
- message.assign(messageBody, start, end);
- }
- else
- {
- // Didn't find a <body>, try looking for a <span> instead.
- start = messageBody.find(startSpan);
- start = messageBody.find(startMarker2, start);
- end = messageBody.find(endSpan);
-
- if(start != std::string::npos)
- {
- start += startMarker2.size();
-
- if(end != std::string::npos)
- end -= start;
-
- message.assign(messageBody, start, end);
- }
- }
- }
-
-// LL_DEBUGS("Voice") << " raw message = \n" << message << LL_ENDL;
-
- // strip formatting tags
- {
- std::string::size_type start;
- std::string::size_type end;
-
- while((start = message.find('<')) != std::string::npos)
- {
- if((end = message.find('>', start + 1)) != std::string::npos)
- {
- // Strip out the tag
- message.erase(start, (end + 1) - start);
- }
- else
- {
- // Avoid an infinite loop
- break;
- }
- }
- }
-
- // Decode ampersand-escaped chars
- {
- std::string::size_type mark = 0;
-
- // The text may contain text encoded with &lt;, &gt;, and &amp;
- mark = 0;
- while((mark = message.find("&lt;", mark)) != std::string::npos)
- {
- message.replace(mark, 4, "<");
- mark += 1;
- }
-
- mark = 0;
- while((mark = message.find("&gt;", mark)) != std::string::npos)
- {
- message.replace(mark, 4, ">");
- mark += 1;
- }
-
- mark = 0;
- while((mark = message.find("&amp;", mark)) != std::string::npos)
- {
- message.replace(mark, 5, "&");
- mark += 1;
- }
- }
-
- // strip leading/trailing whitespace (since we always seem to get a couple newlines)
- LLStringUtil::trim(message);
-
-// LL_DEBUGS("Voice") << " stripped message = \n" << message << LL_ENDL;
-
- sessionStatePtr_t session(findSession(sessionHandle));
- if(session)
- {
- bool is_do_not_disturb = gAgent.isDoNotDisturb();
- bool is_muted = LLMuteList::getInstance()->isMuted(session->mCallerID, session->mName, LLMute::flagTextChat);
- bool is_linden = LLMuteList::isLinden(session->mName);
- LLChat chat;
-
- chat.mMuted = is_muted && !is_linden;
-
- if(!chat.mMuted)
- {
- chat.mFromID = session->mCallerID;
- chat.mFromName = session->mName;
- chat.mSourceType = CHAT_SOURCE_AGENT;
-
- if(is_do_not_disturb && !is_linden)
- {
- // TODO: Question: Return do not disturb mode response here? Or maybe when session is started instead?
- }
-
- LL_DEBUGS("Voice") << "adding message, name " << session->mName << " session " << session->mIMSessionID << ", target " << session->mCallerID << LL_ENDL;
- LLIMMgr::getInstance()->addMessage(session->mIMSessionID,
- session->mCallerID,
- session->mName.c_str(),
- message.c_str(),
- false,
- LLStringUtil::null, // default arg
- IM_NOTHING_SPECIAL, // default arg
- 0, // default arg
- LLUUID::null, // default arg
- LLVector3::zero); // default arg
- }
- }
- }
-}
-
-void LLVivoxVoiceClient::sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string &notificationType)
-{
- sessionStatePtr_t session(findSession(sessionHandle));
-
- if(session)
- {
- participantStatePtr_t participant(session->findParticipant(uriString));
- if(participant)
- {
- if (!stricmp(notificationType.c_str(), "Typing"))
- {
- // Other end started typing
- // TODO: The proper way to add a typing notification seems to be LLIMMgr::processIMTypingStart().
- // It requires some info for the message, which we don't have here.
- }
- else if (!stricmp(notificationType.c_str(), "NotTyping"))
- {
- // Other end stopped typing
- // TODO: The proper way to remove a typing notification seems to be LLIMMgr::processIMTypingStop().
- // It requires some info for the message, which we don't have here.
- }
- else
- {
- LL_DEBUGS("Voice") << "Unknown notification type " << notificationType << "for participant " << uriString << " in session " << session->mSIPURI << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "Unknown participant " << uriString << " in session " << session->mSIPURI << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "Unknown session handle " << sessionHandle << LL_ENDL;
- }
-}
-
-void LLVivoxVoiceClient::voiceServiceConnectionStateChangedEvent(int statusCode, std::string &statusString, std::string &build_id)
-{
- // We don't generally need to process this. However, one occurence is when we first connect, and so it is the
- // earliest opportunity to learn what we're connected to.
- if (statusCode)
- {
- LL_WARNS("Voice") << "VoiceServiceConnectionStateChangedEvent statusCode: " << statusCode <<
- "statusString: " << statusString << LL_ENDL;
- return;
- }
- if (build_id.empty())
- {
- return;
- }
- mVoiceVersion.mBuildVersion = build_id;
-}
-
-void LLVivoxVoiceClient::auxAudioPropertiesEvent(F32 energy)
-{
- LL_DEBUGS("VoiceEnergy") << "got energy " << energy << LL_ENDL;
- mTuningEnergy = energy;
-}
-
-void LLVivoxVoiceClient::muteListChanged()
-{
- // The user's mute list has been updated. Go through the current participant list and sync it with the mute list.
- if(mAudioSession)
- {
- participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin();
-
- for(; iter != mAudioSession->mParticipantsByURI.end(); iter++)
- {
- participantStatePtr_t p(iter->second);
-
- // Check to see if this participant is on the mute list already
- if(p->updateMuteState())
- mAudioSession->mVolumeDirty = true;
- }
- }
-}
-
-/////////////////////////////
-// Managing list of participants
-LLVivoxVoiceClient::participantState::participantState(const std::string &uri) :
- mURI(uri),
- mPTT(false),
- mIsSpeaking(false),
- mIsModeratorMuted(false),
- mLastSpokeTimestamp(0.f),
- mPower(0.f),
- mVolume(LLVoiceClient::VOLUME_DEFAULT),
- mUserVolume(0),
- mOnMuteList(false),
- mVolumeSet(false),
- mVolumeDirty(false),
- mAvatarIDValid(false),
- mIsSelf(false)
-{
-}
-
-LLVivoxVoiceClient::participantStatePtr_t LLVivoxVoiceClient::sessionState::addParticipant(const std::string &uri)
-{
- participantStatePtr_t result;
- bool useAlternateURI = false;
-
- // Note: this is mostly the body of LLVivoxVoiceClient::sessionState::findParticipant(), but since we need to know if it
- // matched the alternate SIP URI (so we can add it properly), we need to reproduce it here.
- {
- participantMap::iterator iter = mParticipantsByURI.find(uri);
-
- if(iter == mParticipantsByURI.end())
- {
- if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI))
- {
- // This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant.
- // Use mSIPURI instead, since it will be properly encoded.
- iter = mParticipantsByURI.find(mSIPURI);
- useAlternateURI = true;
- }
- }
-
- if(iter != mParticipantsByURI.end())
- {
- result = iter->second;
- }
- }
-
- if(!result)
- {
- // participant isn't already in one list or the other.
- result = std::make_shared<participantState>(useAlternateURI?mSIPURI:uri);
- mParticipantsByURI.insert(participantMap::value_type(result->mURI, result));
- mParticipantsChanged = true;
-
- // Try to do a reverse transform on the URI to get the GUID back.
- {
- LLUUID id;
- if(LLVivoxVoiceClient::getInstance()->IDFromName(result->mURI, id))
- {
- result->mAvatarIDValid = true;
- result->mAvatarID = id;
- }
- else
- {
- // Create a UUID by hashing the URI, but do NOT set mAvatarIDValid.
- // This indicates that the ID will not be in the name cache.
- result->mAvatarID.generate(uri);
- }
- }
-
- if(result->updateMuteState())
- {
- mMuteDirty = true;
- }
-
- mParticipantsByUUID.insert(participantUUIDMap::value_type(result->mAvatarID, result));
-
- if (LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID, result->mVolume))
- {
- result->mVolumeDirty = true;
- mVolumeDirty = true;
- }
-
- LL_DEBUGS("Voice") << "participant \"" << result->mURI << "\" added." << LL_ENDL;
- }
-
- return result;
-}
-
-bool LLVivoxVoiceClient::participantState::updateMuteState()
-{
- bool result = false;
-
- bool isMuted = LLMuteList::getInstance()->isMuted(mAvatarID, LLMute::flagVoiceChat);
- if(mOnMuteList != isMuted)
- {
- mOnMuteList = isMuted;
- mVolumeDirty = true;
- result = true;
- }
- return result;
-}
-
-bool LLVivoxVoiceClient::participantState::isAvatar()
-{
- return mAvatarIDValid;
-}
-
-void LLVivoxVoiceClient::sessionState::removeParticipant(const LLVivoxVoiceClient::participantStatePtr_t &participant)
-{
- if(participant)
- {
- participantMap::iterator iter = mParticipantsByURI.find(participant->mURI);
- participantUUIDMap::iterator iter2 = mParticipantsByUUID.find(participant->mAvatarID);
-
- LL_DEBUGS("Voice") << "participant \"" << participant->mURI << "\" (" << participant->mAvatarID << ") removed." << LL_ENDL;
-
- if(iter == mParticipantsByURI.end())
- {
- LL_WARNS("Voice") << "Internal error: participant " << participant->mURI << " not in URI map" << LL_ENDL;
- }
- else if(iter2 == mParticipantsByUUID.end())
- {
- LL_WARNS("Voice") << "Internal error: participant ID " << participant->mAvatarID << " not in UUID map" << LL_ENDL;
- }
- else if(iter->second != iter2->second)
- {
- LL_WARNS("Voice") << "Internal error: participant mismatch!" << LL_ENDL;
- }
- else
- {
- mParticipantsByURI.erase(iter);
- mParticipantsByUUID.erase(iter2);
-
- mParticipantsChanged = true;
- }
- }
-}
-
-void LLVivoxVoiceClient::sessionState::removeAllParticipants()
-{
- LL_DEBUGS("Voice") << "called" << LL_ENDL;
-
- while(!mParticipantsByURI.empty())
- {
- removeParticipant(mParticipantsByURI.begin()->second);
- }
-
- if(!mParticipantsByUUID.empty())
- {
- LL_WARNS("Voice") << "Internal error: empty URI map, non-empty UUID map" << LL_ENDL;
- }
-}
-
-/*static*/
-void LLVivoxVoiceClient::sessionState::VerifySessions()
-{
- std::set<wptr_t>::iterator it = mSession.begin();
- while (it != mSession.end())
- {
- if ((*it).expired())
- {
- LL_WARNS("Voice") << "Expired session found! removing" << LL_ENDL;
- it = mSession.erase(it);
- }
- else
- ++it;
- }
-}
-
-
-void LLVivoxVoiceClient::getParticipantList(std::set<LLUUID> &participants)
-{
- if(mProcessChannels && mAudioSession)
- {
- for(participantUUIDMap::iterator iter = mAudioSession->mParticipantsByUUID.begin();
- iter != mAudioSession->mParticipantsByUUID.end();
- iter++)
- {
- participants.insert(iter->first);
- }
- }
-}
-
-bool LLVivoxVoiceClient::isParticipant(const LLUUID &speaker_id)
-{
- if(mProcessChannels && mAudioSession)
- {
- return (mAudioSession->mParticipantsByUUID.find(speaker_id) != mAudioSession->mParticipantsByUUID.end());
- }
- return false;
-}
-
-
-LLVivoxVoiceClient::participantStatePtr_t LLVivoxVoiceClient::sessionState::findParticipant(const std::string &uri)
-{
- participantStatePtr_t result;
-
- participantMap::iterator iter = mParticipantsByURI.find(uri);
-
- if(iter == mParticipantsByURI.end())
- {
- if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI))
- {
- // This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant.
- // Look up the other URI
- iter = mParticipantsByURI.find(mSIPURI);
- }
- }
-
- if(iter != mParticipantsByURI.end())
- {
- result = iter->second;
- }
-
- return result;
-}
-
-LLVivoxVoiceClient::participantStatePtr_t LLVivoxVoiceClient::sessionState::findParticipantByID(const LLUUID& id)
-{
- participantStatePtr_t result;
- participantUUIDMap::iterator iter = mParticipantsByUUID.find(id);
-
- if(iter != mParticipantsByUUID.end())
- {
- result = iter->second;
- }
-
- return result;
-}
-
-LLVivoxVoiceClient::participantStatePtr_t LLVivoxVoiceClient::findParticipantByID(const LLUUID& id)
-{
- participantStatePtr_t result;
-
- if(mAudioSession)
- {
- result = mAudioSession->findParticipantByID(id);
- }
-
- return result;
-}
-
-
-
-// Check for parcel boundary crossing
-bool LLVivoxVoiceClient::checkParcelChanged(bool update)
-{
- LLViewerRegion *region = gAgent.getRegion();
- LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-
- if(region && parcel)
- {
- S32 parcelLocalID = parcel->getLocalID();
- std::string regionName = region->getName();
-
- // LL_DEBUGS("Voice") << "Region name = \"" << regionName << "\", parcel local ID = " << parcelLocalID << ", cap URI = \"" << capURI << "\"" << LL_ENDL;
-
- // The region name starts out empty and gets filled in later.
- // Also, the cap gets filled in a short time after the region cross, but a little too late for our purposes.
- // If either is empty, wait for the next time around.
- if(!regionName.empty())
- {
- if((parcelLocalID != mCurrentParcelLocalID) || (regionName != mCurrentRegionName))
- {
- // We have changed parcels. Initiate a parcel channel lookup.
- if (update)
- {
- mCurrentParcelLocalID = parcelLocalID;
- mCurrentRegionName = regionName;
- }
- return true;
- }
- }
- }
- return false;
-}
-
-bool LLVivoxVoiceClient::switchChannel(
- std::string uri,
- bool spatial,
- bool no_reconnect,
- bool is_p2p,
- std::string hash)
-{
- bool needsSwitch = !mIsInChannel;
-
- if (mIsInChannel)
- {
- if (mSessionTerminateRequested)
- {
- // If a terminate has been requested, we need to compare against where the URI we're already headed to.
- if(mNextAudioSession)
- {
- if (mNextAudioSession->mSIPURI != uri)
- {
- needsSwitch = true;
- }
- }
- else
- {
- // mNextAudioSession is null -- this probably means we're on our way back to spatial.
- if(!uri.empty())
- {
- // We do want to process a switch in this case.
- needsSwitch = true;
- }
- }
- }
- else
- {
- // Otherwise, compare against the URI we're in now.
- if(mAudioSession)
- {
- if(mAudioSession->mSIPURI != uri)
- {
- needsSwitch = true;
- }
- }
- else
- {
- if(!uri.empty())
- {
- // mAudioSession is null -- it's not clear what case would cause this.
- // For now, log it as a warning and see if it ever crops up.
- LL_WARNS("Voice") << "No current audio session... Forcing switch" << LL_ENDL;
- needsSwitch = true;
- }
- }
- }
- }
-
- if(needsSwitch)
- {
- if(uri.empty())
- {
- // Leave any channel we may be in
- LL_DEBUGS("Voice") << "leaving channel" << LL_ENDL;
-
- sessionStatePtr_t oldSession = mNextAudioSession;
- mNextAudioSession.reset();
-
- // The old session may now need to be deleted.
- reapSession(oldSession);
-
- // If voice was on, turn it off
- if (LLVoiceClient::getInstance()->getUserPTTState())
- {
- LLVoiceClient::getInstance()->setUserPTTState(false);
- }
-
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
- }
- else
- {
- LL_DEBUGS("Voice") << "switching to channel " << uri << LL_ENDL;
-
- mNextAudioSession = addSession(uri);
- mNextAudioSession->mHash = hash;
- mNextAudioSession->mIsSpatial = spatial;
- mNextAudioSession->mReconnect = !no_reconnect;
- mNextAudioSession->mIsP2P = is_p2p;
- }
-
- if (mIsInChannel)
- {
- // If we're already in a channel, or if we're joining one, terminate
- // so we can rejoin with the new session data.
- sessionTerminate();
- }
- }
-
- return needsSwitch;
-}
-
-void LLVivoxVoiceClient::joinSession(const sessionStatePtr_t &session)
-{
- mNextAudioSession = session;
-
- if (mIsInChannel)
- {
- // If we're already in a channel, or if we're joining one, terminate
- // so we can rejoin with the new session data.
- sessionTerminate();
- }
-}
-
-void LLVivoxVoiceClient::setNonSpatialChannel(const LLSD& channelInfo, bool notify_on_first_join, bool hangup_on_last_leave)
-{
- switchChannel(channelInfo["channel_uri"].asString(), false, false, false, channelInfo["channel_credentials"].asString());
-}
-
-bool LLVivoxVoiceClient::setSpatialChannel(const LLSD& channelInfo)
-{
- mSpatialSessionURI = channelInfo["channel_uri"].asString();
- mSpatialSessionCredentials = channelInfo["channel_credentials"].asString();
- if (!mProcessChannels)
- {
- // we're not even processing channels (another provider is) so
- // save the credentials aside and exit
- return false;
- }
-
- LL_DEBUGS("Voice") << "got spatial channel uri: \"" << mSpatialSessionURI << "\"" << LL_ENDL;
-
- if((mIsInChannel && mAudioSession && !(mAudioSession->mIsSpatial)) || (mNextAudioSession && !(mNextAudioSession->mIsSpatial)))
- {
- // User is in a non-spatial chat or joining a non-spatial chat. Don't switch channels.
- LL_INFOS("Voice") << "in non-spatial chat, not switching channels" << LL_ENDL;
- return false;
- }
- else
- {
- return switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials);
- }
-}
-
-void LLVivoxVoiceClient::callUser(const LLUUID &uuid)
-{
- std::string userURI = sipURIFromID(uuid);
- mProcessChannels = true;
-
- switchChannel(userURI, false, true, true);
-}
-
-void LLVivoxVoiceClient::hangup() { leaveChannel(); }
-
-
-LLVoiceP2PIncomingCallInterfacePtr LLVivoxVoiceClient::getIncomingCallInterface(const LLSD &voice_call_info)
-{
- return std::make_shared<LLVivoxVoiceP2PIncomingCall>(voice_call_info);
-}
-
-bool LLVivoxVoiceClient::answerInvite(const std::string &sessionHandle)
-{
- // this is only ever used to answer incoming p2p call invites.
-
- sessionStatePtr_t session(findSession(sessionHandle));
- if (session)
- {
- session->mIsSpatial = false;
- session->mReconnect = false;
- session->mIsP2P = true;
- mProcessChannels = true;
- joinSession(session);
- return true;
- }
-
- return false;
-}
-
-void LLVivoxVoiceClient::declineInvite(const std::string &sessionHandle)
-{
- sessionStatePtr_t session(findSession(sessionHandle));
- if (session)
- {
- sessionMediaDisconnectSendMessage(session);
- }
-}
-
-bool LLVivoxVoiceClient::isVoiceWorking() const
-{
-
- //Added stateSessionTerminated state to avoid problems with call in parcels with disabled voice (EXT-4758)
- // Condition with joining spatial num was added to take into account possible problems with connection to voice
- // server(EXT-4313). See bug descriptions and comments for MAX_NORMAL_JOINING_SPATIAL_NUM for more info.
- return (mSpatialJoiningNum < MAX_NORMAL_JOINING_SPATIAL_NUM) && mIsLoggedIn;
-}
-
-// Returns true if the indicated participant in the current audio session is really an SL avatar.
-// Currently this will be false only for PSTN callers into group chats, and PSTN p2p calls.
-bool LLVivoxVoiceClient::isParticipantAvatar(const LLUUID &id)
-{
- bool result = true;
- sessionStatePtr_t session(findSession(id));
-
- if(session)
- {
- // this is a p2p session with the indicated caller, or the session with the specified UUID.
- if(session->mSynthesizedCallerID)
- result = false;
- }
- else
- {
- // Didn't find a matching session -- check the current audio session for a matching participant
- if(mAudioSession)
- {
- participantStatePtr_t participant(findParticipantByID(id));
- if(participant)
- {
- result = participant->isAvatar();
- }
- }
- }
-
- return result;
-}
-
-// Returns true if calling back the session URI after the session has closed is possible.
-// Currently this will be false only for PSTN P2P calls.
-bool LLVivoxVoiceClient::isSessionCallBackPossible(const LLUUID &session_id)
-{
- bool result = true;
- sessionStatePtr_t session(findSession(session_id));
-
- if(session != NULL)
- {
- result = session->isCallBackPossible();
- }
-
- return result;
-}
-
-// Returns true if the session can accept text IM's.
-// Currently this will be false only for PSTN P2P calls.
-bool LLVivoxVoiceClient::isSessionTextIMPossible(const LLUUID &session_id)
-{
- bool result = true;
- sessionStatePtr_t session(findSession(session_id));
-
- if(session != NULL)
- {
- result = session->isTextIMPossible();
- }
-
- return result;
-}
-
-void LLVivoxVoiceClient::leaveNonSpatialChannel()
-{
- LL_DEBUGS("Voice") << "Request to leave spacial channel." << LL_ENDL;
-
- // Make sure we don't rejoin the current session.
- sessionStatePtr_t oldNextSession(mNextAudioSession);
- mNextAudioSession.reset();
-
- // Most likely this will still be the current session at this point, but check it anyway.
- reapSession(oldNextSession);
-
- verifySessionState();
-
- sessionTerminate();
-}
-
-void LLVivoxVoiceClient::processChannels(bool process)
-{
- mCurrentParcelLocalID = -1;
- mCurrentRegionName.clear();
- mProcessChannels = process;
-}
-
-bool LLVivoxVoiceClient::isCurrentChannel(const LLSD &channelInfo)
-{
- if (!mProcessChannels
- || (channelInfo.has("voice_server_type") && channelInfo["voice_server_type"].asString() != VIVOX_VOICE_SERVER_TYPE)
- || mSessionTerminateRequested)
- {
- return false;
- }
- // favor the next audio session, as that's the one we're bringing up.
- sessionStatePtr_t session = mNextAudioSession;
- if (!session)
- {
- session = mAudioSession;
- }
- if (session)
- {
- if (!channelInfo["session_handle"].asString().empty())
- {
- return session->mHandle == channelInfo["session_handle"].asString();
- }
- return channelInfo["channel_uri"].asString() == session->mSIPURI;
- }
- return false;
-}
-
-bool LLVivoxVoiceClient::compareChannels(const LLSD& channelInfo1, const LLSD& channelInfo2)
-{
- return (!channelInfo1.has("voice_server_type") || (channelInfo1["voice_server_type"] == VIVOX_VOICE_SERVER_TYPE)) &&
- (!channelInfo2.has("voice_server_type") || (channelInfo2["voice_server_type"] == VIVOX_VOICE_SERVER_TYPE)) &&
- (channelInfo1["channel_uri"] == channelInfo2["channel_uri"]);
-}
-
-bool LLVivoxVoiceClient::inProximalChannel()
-{
- bool result = false;
-
- if (mIsInChannel && !mSessionTerminateRequested)
- {
- result = inSpatialChannel();
- }
-
- return result;
-}
-
-std::string LLVivoxVoiceClient::sipURIFromID(const LLUUID &id) const
-{
- std::string result;
- result = "sip:";
- result += nameFromID(id);
- result += "@";
- result += mVoiceSIPURIHostName;
-
- return result;
-}
-
-LLSD LLVivoxVoiceClient::getP2PChannelInfoTemplate(const LLUUID& id) const
-{
- LLSD result;
- result["channel_uri"] = sipURIFromID(id);
- result["voice_server_type"] = VIVOX_VOICE_SERVER_TYPE;
- return result;
-}
-
-std::string LLVivoxVoiceClient::sipURIFromAvatar(LLVOAvatar *avatar)
-{
- std::string result;
- if(avatar)
- {
- result = "sip:";
- result += nameFromID(avatar->getID());
- result += "@";
- result += mVoiceSIPURIHostName;
- }
-
- return result;
-}
-
-std::string LLVivoxVoiceClient::nameFromID(const LLUUID &uuid) const
-{
- std::string result;
-
- if (uuid.isNull()) {
- //VIVOX, the uuid emtpy look for the mURIString and return that instead.
- //result.assign(uuid.mURIStringName);
- LLStringUtil::replaceChar(result, '_', ' ');
- return result;
- }
- // Prepending this apparently prevents conflicts with reserved names inside the vivox code.
- result = "x";
-
- // Base64 encode and replace the pieces of base64 that are less compatible
- // with e-mail local-parts.
- // See RFC-4648 "Base 64 Encoding with URL and Filename Safe Alphabet"
- result += LLBase64::encode(uuid.mData, UUID_BYTES);
- LLStringUtil::replaceChar(result, '+', '-');
- LLStringUtil::replaceChar(result, '/', '_');
-
- // If you need to transform a GUID to this form on the macOS command line, this will do so:
- // echo -n x && (echo e669132a-6c43-4ee1-a78d-6c82fff59f32 |xxd -r -p |openssl base64|tr '/+' '_-')
-
- // The reverse transform can be done with:
- // echo 'x5mkTKmxDTuGnjWyC__WfMg==' |cut -b 2- -|tr '_-' '/+' |openssl base64 -d|xxd -p
-
- return result;
-}
-
-bool LLVivoxVoiceClient::IDFromName(const std::string inName, LLUUID &uuid)
-{
- bool result = false;
-
- // SLIM SDK: The "name" may actually be a SIP URI such as: "sip:xFnPP04IpREWNkuw1cOXlhw==@bhr.vivox.com"
- // If it is, convert to a bare name before doing the transform.
- std::string name = nameFromsipURI(inName);
-
- // Doesn't look like a SIP URI, assume it's an actual name.
- if(name.empty())
- name = inName;
-
- // This will only work if the name is of the proper form.
- // As an example, the account name for Monroe Linden (UUID 1673cfd3-8229-4445-8d92-ec3570e5e587) is:
- // "xFnPP04IpREWNkuw1cOXlhw=="
-
- if((name.size() == 25) && (name[0] == 'x') && (name[23] == '=') && (name[24] == '='))
- {
- // The name appears to have the right form.
-
- // Reverse the transforms done by nameFromID
- std::string temp = name;
- LLStringUtil::replaceChar(temp, '-', '+');
- LLStringUtil::replaceChar(temp, '_', '/');
-
- U8 rawuuid[UUID_BYTES + 1];
- int len = apr_base64_decode_binary(rawuuid, temp.c_str() + 1);
- if(len == UUID_BYTES)
- {
- // The decode succeeded. Stuff the bits into the result's UUID
- memcpy(uuid.mData, rawuuid, UUID_BYTES);
- result = true;
- }
- }
-
- if(!result)
- {
- // VIVOX: not a standard account name, just copy the URI name mURIString field
- // and hope for the best. bpj
- uuid.setNull(); // VIVOX, set the uuid field to nulls
- }
-
- return result;
-}
-
-std::string LLVivoxVoiceClient::sipURIFromName(std::string &name)
-{
- std::string result;
- result = "sip:";
- result += name;
- result += "@";
- result += mVoiceSIPURIHostName;
-
-// LLStringUtil::toLower(result);
-
- return result;
-}
-
-std::string LLVivoxVoiceClient::nameFromsipURI(const std::string &uri)
-{
- std::string result;
-
- std::string::size_type sipOffset, atOffset;
- sipOffset = uri.find("sip:");
- atOffset = uri.find("@");
- if((sipOffset != std::string::npos) && (atOffset != std::string::npos))
- {
- result = uri.substr(sipOffset + 4, atOffset - (sipOffset + 4));
- }
-
- return result;
-}
-
-bool LLVivoxVoiceClient::inSpatialChannel(void)
-{
- bool result = false;
-
- if(mAudioSession)
- {
- result = mAudioSession->mIsSpatial;
- }
-
- return result;
-}
-
-
-LLSD LLVivoxVoiceClient::getAudioSessionChannelInfo()
-{
- LLSD result;
-
- if (mAudioSession)
- {
- result = mAudioSession->getVoiceChannelInfo();
- }
-
- return result;
-}
-
-std::string LLVivoxVoiceClient::getAudioSessionHandle()
-{
- std::string result;
-
- if(mAudioSession)
- result = mAudioSession->mHandle;
-
- return result;
-}
-
-
-/////////////////////////////
-// Sending updates of current state
-
-void LLVivoxVoiceClient::enforceTether(void)
-{
- LLVector3d tethered = mCameraRequestedPosition;
-
- // constrain 'tethered' to within 50m of mAvatarPosition.
- {
- F32 max_dist = 50.0f;
- LLVector3d camera_offset = mCameraRequestedPosition - mAvatarPosition;
- F32 camera_distance = (F32)camera_offset.magVec();
- if(camera_distance > max_dist)
- {
- tethered = mAvatarPosition +
- (max_dist / camera_distance) * camera_offset;
- }
- }
-
- if(dist_vec_squared(mCameraPosition, tethered) > 0.01)
- {
- mCameraPosition = tethered;
- mSpatialCoordsDirty = true;
- }
-}
-
-void LLVivoxVoiceClient::updatePosition(void)
-{
-
- LLViewerRegion *region = gAgent.getRegion();
- if(region && isAgentAvatarValid())
- {
- LLMatrix3 rot;
- LLVector3d pos;
- LLQuaternion qrot;
-
- // TODO: If camera and avatar velocity are actually used by the voice system, we could compute them here...
- // They're currently always set to zero.
-
- // Send the current camera position to the voice code
- rot.setRows(LLViewerCamera::getInstance()->getAtAxis(), LLViewerCamera::getInstance()->getLeftAxis (), LLViewerCamera::getInstance()->getUpAxis());
- pos = gAgent.getRegion()->getPosGlobalFromRegion(LLViewerCamera::getInstance()->getOrigin());
-
- LLVivoxVoiceClient::getInstance()->setCameraPosition(
- pos, // position
- LLVector3::zero, // velocity
- rot); // rotation matrix
-
- // Send the current avatar position to the voice code
- qrot = gAgentAvatarp->getRootJoint()->getWorldRotation();
- pos = gAgentAvatarp->getPositionGlobal();
-
- // TODO: Can we get the head offset from outside the LLVOAvatar?
- // pos += LLVector3d(mHeadOffset);
- pos += LLVector3d(0.f, 0.f, 1.f);
-
- LLVivoxVoiceClient::getInstance()->setAvatarPosition(
- pos, // position
- LLVector3::zero, // velocity
- qrot); // rotation matrix
- }
-}
-
-void LLVivoxVoiceClient::setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot)
-{
- mCameraRequestedPosition = position;
-
- if(mCameraVelocity != velocity)
- {
- mCameraVelocity = velocity;
- mSpatialCoordsDirty = true;
- }
-
- if(mCameraRot != rot)
- {
- mCameraRot = rot;
- mSpatialCoordsDirty = true;
- }
-}
-
-void LLVivoxVoiceClient::setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLQuaternion &rot)
-{
- if(dist_vec_squared(mAvatarPosition, position) > 0.01)
- {
- mAvatarPosition = position;
- mSpatialCoordsDirty = true;
- }
-
- if(mAvatarVelocity != velocity)
- {
- mAvatarVelocity = velocity;
- mSpatialCoordsDirty = true;
- }
-
- // If the two rotations are not exactly equal test their dot product
- // to get the cos of the angle between them.
- // If it is too small, don't update.
- F32 rot_cos_diff = llabs(dot(mAvatarRot, rot));
- if ((mAvatarRot != rot) && (rot_cos_diff < MINUSCULE_ANGLE_COS))
- {
- mAvatarRot = rot;
- mSpatialCoordsDirty = true;
- }
-}
-
-bool LLVivoxVoiceClient::channelFromRegion(LLViewerRegion *region, std::string &name)
-{
- bool result = false;
-
- if(region)
- {
- name = region->getName();
- }
-
- if(!name.empty())
- result = true;
-
- return result;
-}
-
-void LLVivoxVoiceClient::leaveChannel(void)
-{
- if (mIsInChannel)
- {
- LL_DEBUGS("Voice") << "leaving channel for teleport/logout" << LL_ENDL;
- mChannelName.clear();
- }
- sessionTerminate();
-}
-
-void LLVivoxVoiceClient::setMuteMic(bool muted)
-{
- if(mMuteMic != muted)
- {
- mMuteMic = muted;
- mMuteMicDirty = true;
- }
-}
-
-void LLVivoxVoiceClient::setVoiceEnabled(bool enabled)
-{
- LL_DEBUGS("Voice")
- << "( " << (enabled ? "enabled" : "disabled") << " )"
- << " was "<< (mVoiceEnabled ? "enabled" : "disabled")
- << " coro "<< (mIsCoroutineActive ? "active" : "inactive")
- << LL_ENDL;
-
- if (enabled != mVoiceEnabled)
- {
- // TODO: Refactor this so we don't call into LLVoiceChannel, but simply
- // use the status observer
- mVoiceEnabled = enabled;
- LLVoiceClientStatusObserver::EStatusType status;
-
- if (enabled)
- {
- LL_DEBUGS("Voice") << "enabling" << LL_ENDL;
- LLVoiceChannel::getCurrentVoiceChannel()->activate();
- status = LLVoiceClientStatusObserver::STATUS_VOICE_ENABLED;
-
- if (!mIsCoroutineActive)
- {
- LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro",
- boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance()));
- }
- else
- {
- LL_DEBUGS("Voice") << "coro should be active.. not launching" << LL_ENDL;
- }
- }
- else
- {
- // Turning voice off looses your current channel -- this makes sure the UI isn't out of sync when you re-enable it.
- LLVoiceChannel::getCurrentVoiceChannel()->deactivate();
- gAgent.setVoiceConnected(false);
- status = LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED;
- mCurrentParcelLocalID = -1;
- mCurrentRegionName.clear();
- }
-
- notifyStatusObservers(status);
- }
- else
- {
- LL_DEBUGS("Voice") << " no-op" << LL_ENDL;
- }
-}
-
-
-void LLVivoxVoiceClient::setEarLocation(S32 loc)
-{
- if(mEarLocation != loc)
- {
- LL_DEBUGS("Voice") << "Setting mEarLocation to " << loc << LL_ENDL;
-
- mEarLocation = loc;
- mSpatialCoordsDirty = true;
- }
-}
-
-void LLVivoxVoiceClient::setVoiceVolume(F32 volume)
-{
- int scaled_volume = scale_speaker_volume(volume);
-
- if(scaled_volume != mSpeakerVolume)
- {
- int min_volume = scale_speaker_volume(0);
- if((scaled_volume == min_volume) || (mSpeakerVolume == min_volume))
- {
- mSpeakerMuteDirty = true;
- }
-
- mSpeakerVolume = scaled_volume;
- mSpeakerVolumeDirty = true;
- }
-}
-
-void LLVivoxVoiceClient::setMicGain(F32 volume)
-{
- int scaled_volume = scale_mic_volume(volume);
-
- if(scaled_volume != mMicVolume)
- {
- mMicVolume = scaled_volume;
- mMicVolumeDirty = true;
- }
-}
-
-/////////////////////////////
-// Accessors for data related to nearby speakers
-
-std::string LLVivoxVoiceClient::getDisplayName(const LLUUID& id)
-{
- std::string result;
- if (mProcessChannels)
- {
- participantStatePtr_t participant(findParticipantByID(id));
- if (participant)
- {
- result = participant->mDisplayName;
- }
- }
-
- return result;
-}
-
-
-
-bool LLVivoxVoiceClient::getIsSpeaking(const LLUUID& id)
-{
- bool result = false;
- if (mProcessChannels)
- {
- participantStatePtr_t participant(findParticipantByID(id));
- if (participant)
- {
- if (participant->mSpeakingTimeout.getElapsedTimeF32() > SPEAKING_TIMEOUT)
- {
- participant->mIsSpeaking = false;
- }
- result = participant->mIsSpeaking;
- }
- }
-
- return result;
-}
-
-bool LLVivoxVoiceClient::getIsModeratorMuted(const LLUUID& id)
-{
- bool result = false;
- if (!mProcessChannels)
- {
- return false;
- }
- participantStatePtr_t participant(findParticipantByID(id));
- if(participant)
- {
- result = participant->mIsModeratorMuted;
- }
-
- return result;
-}
-
-F32 LLVivoxVoiceClient::getCurrentPower(const LLUUID& id)
-{
- F32 result = 0;
- participantStatePtr_t participant(findParticipantByID(id));
- if(participant)
- {
- result = participant->mPower;
- }
-
- return result;
-}
-
-
-
-bool LLVivoxVoiceClient::getUsingPTT(const LLUUID& id)
-{
- bool result = false;
-
- participantStatePtr_t participant(findParticipantByID(id));
- if(participant)
- {
- // I'm not sure what the semantics of this should be.
- // Does "using PTT" mean they're configured with a push-to-talk button?
- // For now, we know there's no PTT mechanism in place, so nobody is using it.
- }
-
- return result;
-}
-
-// External accessors.
-F32 LLVivoxVoiceClient::getUserVolume(const LLUUID& id)
-{
- // Minimum volume will be returned for users with voice disabled
- F32 result = LLVoiceClient::VOLUME_MIN;
-
- participantStatePtr_t participant(findParticipantByID(id));
- if(participant)
- {
- result = participant->mVolume;
-
- // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
- // LL_DEBUGS("Voice") << "mVolume = " << result << " for " << id << LL_ENDL;
- }
-
- return result;
-}
-
-void LLVivoxVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
-{
- if(mAudioSession)
- {
- participantStatePtr_t participant(findParticipantByID(id));
- if (participant && !participant->mIsSelf)
- {
- if (!is_approx_equal(volume, LLVoiceClient::VOLUME_DEFAULT))
- {
- // Store this volume setting for future sessions if it has been
- // changed from the default
- LLSpeakerVolumeStorage::getInstance()->storeSpeakerVolume(id, volume);
- }
- else
- {
- // Remove stored volume setting if it is returned to the default
- LLSpeakerVolumeStorage::getInstance()->removeSpeakerVolume(id);
- }
-
- participant->mVolume = llclamp(volume, LLVoiceClient::VOLUME_MIN, LLVoiceClient::VOLUME_MAX);
- participant->mVolumeDirty = true;
- mAudioSession->mVolumeDirty = true;
- }
- }
-}
-
-std::string LLVivoxVoiceClient::getGroupID(const LLUUID& id)
-{
- std::string result;
-
- participantStatePtr_t participant(findParticipantByID(id));
- if(participant)
- {
- result = participant->mGroupID;
- }
-
- return result;
-}
-
-void LLVivoxVoiceClient::recordingLoopStart(int seconds, int deltaFramesPerControlFrame)
-{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Start)" << LL_ENDL;
-
- if(!mMainSessionGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Start</RecordingControlType>"
- << "<DeltaFramesPerControlFrame>" << deltaFramesPerControlFrame << "</DeltaFramesPerControlFrame>"
- << "<Filename>" << "" << "</Filename>"
- << "<EnableAudioRecordingEvents>false</EnableAudioRecordingEvents>"
- << "<LoopModeDurationSeconds>" << seconds << "</LoopModeDurationSeconds>"
- << "</Request>\n\n\n";
-
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::recordingLoopSave(const std::string& filename)
-{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Flush)" << LL_ENDL;
-
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Flush</RecordingControlType>"
- << "<Filename>" << filename << "</Filename>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::recordingStop()
-{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Stop)" << LL_ENDL;
-
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Stop</RecordingControlType>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::filePlaybackStart(const std::string& filename)
-{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Start)" << LL_ENDL;
-
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlPlayback.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Start</RecordingControlType>"
- << "<Filename>" << filename << "</Filename>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::filePlaybackStop()
-{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Stop)" << LL_ENDL;
-
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlPlayback.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Stop</RecordingControlType>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::filePlaybackSetPaused(bool paused)
-{
- // TODO: Implement once Vivox gives me a sample
-}
-
-void LLVivoxVoiceClient::filePlaybackSetMode(bool vox, float speed)
-{
- // TODO: Implement once Vivox gives me a sample
-}
-
-//------------------------------------------------------------------------
-std::set<LLVivoxVoiceClient::sessionState::wptr_t, std::owner_less<LLVivoxVoiceClient::sessionState::wptr_t>> LLVivoxVoiceClient::sessionState::mSession;
-
-
-LLVivoxVoiceClient::sessionState::sessionState() :
- mErrorStatusCode(0),
- mMediaStreamState(streamStateUnknown),
- mCreateInProgress(false),
- mMediaConnectInProgress(false),
- mVoiceInvitePending(false),
- mTextInvitePending(false),
- mSynthesizedCallerID(false),
- mIsChannel(false),
- mIsSpatial(false),
- mIsP2P(false),
- mIncoming(false),
- mVoiceActive(false),
- mReconnect(false),
- mVolumeDirty(false),
- mMuteDirty(false),
- mParticipantsChanged(false)
-{
-}
-
-LLSD LLVivoxVoiceClient::sessionState::getVoiceChannelInfo()
-{
- LLSD result;
-
- result["voice_server_type"] = VIVOX_VOICE_SERVER_TYPE;
- result["channel_credentials"] = mHash;
- result["channel_uri"] = mSIPURI;
- result["session_handle"] = mHandle;
-
- return result;
-}
-
-/*static*/
-LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::createSession()
-{
- sessionState::ptr_t ptr(new sessionState());
-
- std::pair<std::set<wptr_t>::iterator, bool> result = mSession.insert(ptr);
-
- if (result.second)
- ptr->mMyIterator = result.first;
-
- return ptr;
-}
-
-LLVivoxVoiceClient::sessionState::~sessionState()
-{
- LL_INFOS("Voice") << "Destroying session handle=" << mHandle << " SIP=" << mSIPURI << LL_ENDL;
- if (mMyIterator != mSession.end())
- mSession.erase(mMyIterator);
-
- removeAllParticipants();
-}
-
-bool LLVivoxVoiceClient::sessionState::isCallBackPossible()
-{
- // This may change to be explicitly specified by vivox in the future...
- // Currently, only PSTN P2P calls cannot be returned.
- // Conveniently, this is also the only case where we synthesize a caller UUID.
- return !mSynthesizedCallerID;
-}
-
-bool LLVivoxVoiceClient::sessionState::isTextIMPossible()
-{
- // This may change to be explicitly specified by vivox in the future...
- return !mSynthesizedCallerID;
-}
-
-
-/*static*/
-LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::matchSessionByHandle(const std::string &handle)
-{
- sessionStatePtr_t result;
-
- // *TODO: My kingdom for a lambda!
- std::set<wptr_t>::iterator it = std::find_if(mSession.begin(), mSession.end(), boost::bind(testByHandle, _1, handle));
-
- if (it != mSession.end())
- result = (*it).lock();
-
- return result;
-}
-
-/*static*/
-LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::matchCreatingSessionByURI(const std::string &uri)
-{
- sessionStatePtr_t result;
-
- // *TODO: My kingdom for a lambda!
- std::set<wptr_t>::iterator it = std::find_if(mSession.begin(), mSession.end(), boost::bind(testByCreatingURI, _1, uri));
-
- if (it != mSession.end())
- result = (*it).lock();
-
- return result;
-}
-
-/*static*/
-LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::matchSessionByURI(const std::string &uri)
-{
- sessionStatePtr_t result;
-
- // *TODO: My kingdom for a lambda!
- std::set<wptr_t>::iterator it = std::find_if(mSession.begin(), mSession.end(), boost::bind(testBySIPOrAlterateURI, _1, uri));
-
- if (it != mSession.end())
- result = (*it).lock();
-
- return result;
-}
-
-/*static*/
-LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::matchSessionByParticipant(const LLUUID &participant_id)
-{
- sessionStatePtr_t result;
-
- // *TODO: My kingdom for a lambda!
- std::set<wptr_t>::iterator it = std::find_if(mSession.begin(), mSession.end(), boost::bind(testByCallerId, _1, participant_id));
-
- if (it != mSession.end())
- result = (*it).lock();
-
- return result;
-}
-
-void LLVivoxVoiceClient::sessionState::for_each(sessionFunc_t func)
-{
- std::for_each(mSession.begin(), mSession.end(), boost::bind(for_eachPredicate, _1, func));
-}
-
-// simple test predicates.
-// *TODO: These should be made into lambdas when we can pull the trigger on newer C++ features.
-bool LLVivoxVoiceClient::sessionState::testByHandle(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string handle)
-{
- ptr_t aLock(a.lock());
-
- return aLock ? aLock->mHandle == handle : false;
-}
-
-bool LLVivoxVoiceClient::sessionState::testByCreatingURI(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string uri)
-{
- ptr_t aLock(a.lock());
-
- return aLock ? (aLock->mCreateInProgress && (aLock->mSIPURI == uri)) : false;
-}
-
-bool LLVivoxVoiceClient::sessionState::testBySIPOrAlterateURI(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string uri)
-{
- ptr_t aLock(a.lock());
-
- return aLock ? ((aLock->mSIPURI == uri) || (aLock->mAlternateSIPURI == uri)) : false;
-}
-
-
-bool LLVivoxVoiceClient::sessionState::testByCallerId(const LLVivoxVoiceClient::sessionState::wptr_t &a, LLUUID participantId)
-{
- ptr_t aLock(a.lock());
-
- return aLock ? ((aLock->mCallerID == participantId) || (aLock->mIMSessionID == participantId)) : false;
-}
-
-/*static*/
-void LLVivoxVoiceClient::sessionState::for_eachPredicate(const LLVivoxVoiceClient::sessionState::wptr_t &a, sessionFunc_t func)
-{
- ptr_t aLock(a.lock());
-
- if (aLock)
- func(aLock);
- else
- {
- LL_WARNS("Voice") << "Stale handle in session map!" << LL_ENDL;
- }
-}
-
-
-
-LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::findSession(const std::string &handle)
-{
- sessionStatePtr_t result;
- sessionMap::iterator iter = mSessionsByHandle.find(handle);
- if(iter != mSessionsByHandle.end())
- {
- result = iter->second;
- }
-
- return result;
-}
-
-LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::findSessionBeingCreatedByURI(const std::string &uri)
-{
- sessionStatePtr_t result = sessionState::matchCreatingSessionByURI(uri);
-
- return result;
-}
-
-LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::findSession(const LLUUID &participant_id)
-{
- sessionStatePtr_t result = sessionState::matchSessionByParticipant(participant_id);
-
- return result;
-}
-
-LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::addSession(const std::string &uri, const std::string &handle)
-{
- sessionStatePtr_t result;
-
- if(handle.empty())
- {
- // No handle supplied.
- // Check whether there's already a session with this URI
- result = sessionState::matchSessionByURI(uri);
- }
- else // (!handle.empty())
- {
- // Check for an existing session with this handle
- sessionMap::iterator iter = mSessionsByHandle.find(handle);
-
- if(iter != mSessionsByHandle.end())
- {
- result = iter->second;
- }
- }
-
- if(!result)
- {
- // No existing session found.
-
- LL_DEBUGS("Voice") << "adding new session: handle \"" << handle << "\" URI " << uri << LL_ENDL;
- result = sessionState::createSession();
- result->mSIPURI = uri;
- result->mHandle = handle;
-
- if (LLVoiceClient::instance().getVoiceEffectEnabled())
- {
- result->mVoiceFontID = LLVoiceClient::instance().getVoiceEffectDefault();
- }
-
- if(!result->mHandle.empty())
- {
- // *TODO: Rider: This concerns me. There is a path (via switchChannel) where
- // we do not track the session. In theory this means that we could end up with
- // a mAuidoSession that does not match the session tracked in mSessionsByHandle
- mSessionsByHandle.insert(sessionMap::value_type(result->mHandle, result));
- }
- }
- else
- {
- // Found an existing session
-
- if(uri != result->mSIPURI)
- {
- // TODO: Should this be an internal error?
- LL_DEBUGS("Voice") << "changing uri from " << result->mSIPURI << " to " << uri << LL_ENDL;
- setSessionURI(result, uri);
- }
-
- if(handle != result->mHandle)
- {
- if(handle.empty())
- {
- // There's at least one race condition where where addSession was clearing an existing session handle, which caused things to break.
- LL_DEBUGS("Voice") << "NOT clearing handle " << result->mHandle << LL_ENDL;
- }
- else
- {
- // TODO: Should this be an internal error?
- LL_DEBUGS("Voice") << "changing handle from " << result->mHandle << " to " << handle << LL_ENDL;
- setSessionHandle(result, handle);
- }
- }
-
- LL_DEBUGS("Voice") << "returning existing session: handle " << handle << " URI " << uri << LL_ENDL;
- }
-
- verifySessionState();
-
- return result;
-}
-
-void LLVivoxVoiceClient::clearSessionHandle(const sessionStatePtr_t &session)
-{
- if (session)
- {
- if (!session->mHandle.empty())
- {
- sessionMap::iterator iter = mSessionsByHandle.find(session->mHandle);
- if (iter != mSessionsByHandle.end())
- {
- mSessionsByHandle.erase(iter);
- }
- }
- else
- {
- LL_WARNS("Voice") << "Session has empty handle!" << LL_ENDL;
- }
- }
- else
- {
- LL_WARNS("Voice") << "Attempt to clear NULL session!" << LL_ENDL;
- }
-
-}
-
-void LLVivoxVoiceClient::setSessionHandle(const sessionStatePtr_t &session, const std::string &handle)
-{
- // Have to remove the session from the handle-indexed map before changing the handle, or things will break badly.
-
- if(!session->mHandle.empty())
- {
- // Remove session from the map if it should have been there.
- sessionMap::iterator iter = mSessionsByHandle.find(session->mHandle);
- if(iter != mSessionsByHandle.end())
- {
- if(iter->second != session)
- {
- LL_WARNS("Voice") << "Internal error: session mismatch! Session may have been duplicated. Removing version in map." << LL_ENDL;
- }
-
- mSessionsByHandle.erase(iter);
- }
- else
- {
- LL_WARNS("Voice") << "Attempt to remove session with handle " << session->mHandle << " not found in map!" << LL_ENDL;
- }
- }
-
- session->mHandle = handle;
-
- if(!handle.empty())
- {
- mSessionsByHandle.insert(sessionMap::value_type(session->mHandle, session));
- }
-
- verifySessionState();
-}
-
-void LLVivoxVoiceClient::setSessionURI(const sessionStatePtr_t &session, const std::string &uri)
-{
- // There used to be a map of session URIs to sessions, which made this complex....
- session->mSIPURI = uri;
-
- verifySessionState();
-}
-
-void LLVivoxVoiceClient::deleteSession(const sessionStatePtr_t &session)
-{
- // Remove the session from the handle map
- if(!session->mHandle.empty())
- {
- sessionMap::iterator iter = mSessionsByHandle.find(session->mHandle);
- if(iter != mSessionsByHandle.end())
- {
- if(iter->second != session)
- {
- LL_WARNS("Voice") << "Internal error: session mismatch, removing session in map." << LL_ENDL;
- }
- mSessionsByHandle.erase(iter);
- }
- }
-
- // At this point, the session should be unhooked from all lists and all state should be consistent.
- verifySessionState();
-
- // If this is the current audio session, clean up the pointer which will soon be dangling.
- if(mAudioSession == session)
- {
- mAudioSession.reset();
- }
-
- // ditto for the next audio session
- if(mNextAudioSession == session)
- {
- mNextAudioSession.reset();
- }
-
-}
-
-void LLVivoxVoiceClient::deleteAllSessions()
-{
- LL_DEBUGS("Voice") << LL_ENDL;
-
- while (!mSessionsByHandle.empty())
- {
- const sessionStatePtr_t session = mSessionsByHandle.begin()->second;
- deleteSession(session);
- }
-
-}
-
-void LLVivoxVoiceClient::verifySessionState(void)
-{
- LL_DEBUGS("Voice") << "Sessions in handle map=" << mSessionsByHandle.size() << LL_ENDL;
- sessionState::VerifySessions();
-}
-
-void LLVivoxVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)
-{
- mParticipantObservers.insert(observer);
-}
-
-void LLVivoxVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer)
-{
- mParticipantObservers.erase(observer);
-}
-
-void LLVivoxVoiceClient::notifyParticipantObservers()
-{
- for (observer_set_t::iterator it = mParticipantObservers.begin();
- it != mParticipantObservers.end();
- )
- {
- LLVoiceClientParticipantObserver* observer = *it;
- observer->onParticipantsChanged();
- // In case onParticipantsChanged() deleted an entry.
- it = mParticipantObservers.upper_bound(observer);
- }
-}
-
-void LLVivoxVoiceClient::addObserver(LLVoiceClientStatusObserver* observer)
-{
- mStatusObservers.insert(observer);
-}
-
-void LLVivoxVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer)
-{
- mStatusObservers.erase(observer);
-}
-
-void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status)
-{
- LL_DEBUGS("Voice") << "( " << LLVoiceClientStatusObserver::status2string(status) << " )"
- << " mAudioSession=" << mAudioSession
- << LL_ENDL;
-
- if(mAudioSession)
- {
- if(status == LLVoiceClientStatusObserver::ERROR_UNKNOWN)
- {
- switch(mAudioSession->mErrorStatusCode)
- {
- case 20713: status = LLVoiceClientStatusObserver::ERROR_CHANNEL_FULL; break;
- case 20714: status = LLVoiceClientStatusObserver::ERROR_CHANNEL_LOCKED; break;
- case 20715:
- //invalid channel, we may be using a set of poorly cached
- //info
- status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
- break;
- case 1009:
- //invalid username and password
- status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
- break;
- }
-
- // Reset the error code to make sure it won't be reused later by accident.
- mAudioSession->mErrorStatusCode = 0;
- }
- else if(status == LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL)
- {
- switch(mAudioSession->mErrorStatusCode)
- {
- case HTTP_NOT_FOUND: // NOT_FOUND
- // *TODO: Should this be 503?
- case 480: // TEMPORARILY_UNAVAILABLE
- case HTTP_REQUEST_TIME_OUT: // REQUEST_TIMEOUT
- // call failed because other user was not available
- // treat this as an error case
- status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
-
- // Reset the error code to make sure it won't be reused later by accident.
- mAudioSession->mErrorStatusCode = 0;
- break;
- }
- }
- }
-
- LLSD channel_info = getAudioSessionChannelInfo();
- LL_DEBUGS("Voice")
- << " " << LLVoiceClientStatusObserver::status2string(status)
- << ", session channelInfo " << channel_info
- << ", proximal is " << inSpatialChannel()
- << LL_ENDL;
-
- if (!mProcessChannels)
- {
- // we're not processing...another voice module is.
- // so nobody wants to hear from us.
- return;
- }
- for (status_observer_set_t::iterator it = mStatusObservers.begin();
- it != mStatusObservers.end();
- )
- {
- LLVoiceClientStatusObserver* observer = *it;
- observer->onChange(status, channel_info, inSpatialChannel());
- // In case onError() deleted an entry.
- it = mStatusObservers.upper_bound(observer);
- }
-
- // skipped to avoid speak button blinking
- if ( status != LLVoiceClientStatusObserver::STATUS_JOINING
- && status != LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL
- && status != LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED)
- {
- bool voice_status = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
-
- LL_WARNS("Voice") << "Setting voice connected " << (voice_status ? "True" : "False") << LL_ENDL;
- gAgent.setVoiceConnected(voice_status);
-
- if (voice_status)
- {
- LLAppViewer::instance()->postToMainCoro([=]() { LLFirstUse::speak(true); });
- }
- }
-}
-
-void LLVivoxVoiceClient::addObserver(LLFriendObserver* observer)
-{
- mFriendObservers.insert(observer);
-}
-
-void LLVivoxVoiceClient::removeObserver(LLFriendObserver* observer)
-{
- mFriendObservers.erase(observer);
-}
-
-void LLVivoxVoiceClient::notifyFriendObservers()
-{
- for (friend_observer_set_t::iterator it = mFriendObservers.begin();
- it != mFriendObservers.end();
- )
- {
- LLFriendObserver* observer = *it;
- it++;
- // The only friend-related thing we notify on is online/offline transitions.
- observer->changed(LLFriendObserver::ONLINE);
- }
-}
-
-void LLVivoxVoiceClient::lookupName(const LLUUID &id)
-{
- if (mAvatarNameCacheConnection.connected())
- {
- mAvatarNameCacheConnection.disconnect();
- }
- mAvatarNameCacheConnection = LLAvatarNameCache::get(id, boost::bind(&LLVivoxVoiceClient::onAvatarNameCache, this, _1, _2));
-}
-
-void LLVivoxVoiceClient::onAvatarNameCache(const LLUUID& agent_id,
- const LLAvatarName& av_name)
-{
- mAvatarNameCacheConnection.disconnect();
- std::string display_name = av_name.getDisplayName();
- avatarNameResolved(agent_id, display_name);
-}
-
-void LLVivoxVoiceClient::predAvatarNameResolution(const LLVivoxVoiceClient::sessionStatePtr_t &session, LLUUID id, std::string name)
-{
- participantStatePtr_t participant(session->findParticipantByID(id));
- if (participant)
- {
- // Found -- fill in the name
- participant->mAccountName = name;
- // and post a "participants updated" message to listeners later.
- session->mParticipantsChanged = true;
- }
-
- // Check whether this is a p2p session whose caller name just resolved
- if (session->mCallerID == id)
- {
- // this session's "caller ID" just resolved. Fill in the name.
- session->mName = name;
- if (session->mTextInvitePending)
- {
- session->mTextInvitePending = false;
-
- // We don't need to call LLIMMgr::getInstance()->addP2PSession() here. The first incoming message will create the panel.
- }
- if (session->mVoiceInvitePending)
- {
- session->mVoiceInvitePending = false;
- LLIMMgr::getInstance()->inviteToSession(
- session->mIMSessionID,
- session->mName,
- session->mCallerID,
- session->mName,
- IM_SESSION_P2P_INVITE,
- LLIMMgr::INVITATION_TYPE_VOICE,
- session->getVoiceChannelInfo());
- }
- }
-}
-
-void LLVivoxVoiceClient::avatarNameResolved(const LLUUID &id, const std::string &name)
-{
- sessionState::for_each(boost::bind(predAvatarNameResolution, _1, id, name));
-}
-
-bool LLVivoxVoiceClient::setVoiceEffect(const LLUUID& id)
-{
- if (!mAudioSession)
- {
- return false;
- }
-
- if (!id.isNull())
- {
- if (mVoiceFontMap.empty())
- {
- LL_DEBUGS("Voice") << "Voice fonts not available." << LL_ENDL;
- return false;
- }
- else if (mVoiceFontMap.find(id) == mVoiceFontMap.end())
- {
- LL_DEBUGS("Voice") << "Invalid voice font " << id << LL_ENDL;
- return false;
- }
- }
-
- // *TODO: Check for expired fonts?
- mAudioSession->mVoiceFontID = id;
-
- // *TODO: Separate voice font defaults for spatial chat and IM?
- gSavedPerAccountSettings.setString("VoiceEffectDefault", id.asString());
-
- sessionSetVoiceFontSendMessage(mAudioSession);
- notifyVoiceFontObservers();
-
- return true;
-}
-
-const LLUUID LLVivoxVoiceClient::getVoiceEffect()
-{
- return mAudioSession ? mAudioSession->mVoiceFontID : LLUUID::null;
-}
-
-LLSD LLVivoxVoiceClient::getVoiceEffectProperties(const LLUUID& id)
-{
- LLSD sd;
-
- voice_font_map_t::iterator iter = mVoiceFontMap.find(id);
- if (iter != mVoiceFontMap.end())
- {
- sd["template_only"] = false;
- }
- else
- {
- // Voice effect is not in the voice font map, see if there is a template
- iter = mVoiceFontTemplateMap.find(id);
- if (iter == mVoiceFontTemplateMap.end())
- {
- LL_WARNS("Voice") << "Voice effect " << id << "not found." << LL_ENDL;
- return sd;
- }
- sd["template_only"] = true;
- }
-
- voiceFontEntry *font = iter->second;
- sd["name"] = font->mName;
- sd["expiry_date"] = font->mExpirationDate;
- sd["is_new"] = font->mIsNew;
-
- return sd;
-}
-
-LLVivoxVoiceClient::voiceFontEntry::voiceFontEntry(LLUUID& id) :
- mID(id),
- mFontIndex(0),
- mFontType(VOICE_FONT_TYPE_NONE),
- mFontStatus(VOICE_FONT_STATUS_NONE),
- mIsNew(false)
-{
- mExpiryTimer.stop();
-}
-
-LLVivoxVoiceClient::voiceFontEntry::~voiceFontEntry()
-{
-}
-
-void LLVivoxVoiceClient::refreshVoiceEffectLists(bool clear_lists)
-{
- if (clear_lists)
- {
- mVoiceFontsReceived = false;
- deleteAllVoiceFonts();
- deleteVoiceFontTemplates();
- }
-
- accountGetSessionFontsSendMessage();
- accountGetTemplateFontsSendMessage();
-}
-
-const voice_effect_list_t& LLVivoxVoiceClient::getVoiceEffectList() const
-{
- return mVoiceFontList;
-}
-
-const voice_effect_list_t& LLVivoxVoiceClient::getVoiceEffectTemplateList() const
-{
- return mVoiceFontTemplateList;
-}
-
-void LLVivoxVoiceClient::addVoiceFont(const S32 font_index,
- const std::string &name,
- const std::string &description,
- const LLDate &expiration_date,
- bool has_expired,
- const S32 font_type,
- const S32 font_status,
- const bool template_font)
-{
- // Vivox SessionFontIDs are not guaranteed to remain the same between
- // sessions or grids so use a UUID for the name.
-
- // If received name is not a UUID, fudge one by hashing the name and type.
- LLUUID font_id;
- if (LLUUID::validate(name))
- {
- font_id = LLUUID(name);
- }
- else
- {
- font_id.generate(STRINGIZE(font_type << ":" << name));
- }
-
- voiceFontEntry *font = NULL;
-
- voice_font_map_t& font_map = template_font ? mVoiceFontTemplateMap : mVoiceFontMap;
- voice_effect_list_t& font_list = template_font ? mVoiceFontTemplateList : mVoiceFontList;
-
- // Check whether we've seen this font before.
- voice_font_map_t::iterator iter = font_map.find(font_id);
- bool new_font = (iter == font_map.end());
-
- // Override the has_expired flag if we have passed the expiration_date as a double check.
- if (expiration_date.secondsSinceEpoch() < (LLDate::now().secondsSinceEpoch() + VOICE_FONT_EXPIRY_INTERVAL))
- {
- has_expired = true;
- }
-
- if (has_expired)
- {
- LL_DEBUGS("VoiceFont") << "Expired " << (template_font ? "Template " : "")
- << expiration_date.asString() << " " << font_id
- << " (" << font_index << ") " << name << LL_ENDL;
-
- // Remove existing session fonts that have expired since we last saw them.
- if (!new_font && !template_font)
- {
- deleteVoiceFont(font_id);
- }
- return;
- }
-
- if (new_font)
- {
- // If it is a new font create a new entry.
- font = new voiceFontEntry(font_id);
- }
- else
- {
- // Not a new font, update the existing entry
- font = iter->second;
- }
-
- if (font)
- {
- font->mFontIndex = font_index;
- // Use the description for the human readable name if available, as the
- // "name" may be a UUID.
- font->mName = description.empty() ? name : description;
- font->mFontType = font_type;
- font->mFontStatus = font_status;
-
- // If the font is new or the expiration date has changed the expiry timers need updating.
- if (!template_font && (new_font || font->mExpirationDate != expiration_date))
- {
- font->mExpirationDate = expiration_date;
-
- // Set the expiry timer to trigger a notification when the voice font can no longer be used.
- font->mExpiryTimer.start();
- font->mExpiryTimer.setExpiryAt(expiration_date.secondsSinceEpoch() - VOICE_FONT_EXPIRY_INTERVAL);
-
- // Only flag new session fonts after the first time we have fetched the list.
- if (mVoiceFontsReceived)
- {
- font->mIsNew = true;
- mVoiceFontsNew = true;
- }
- }
-
- LL_DEBUGS("VoiceFont") << (template_font ? "Template " : "")
- << font->mExpirationDate.asString() << " " << font->mID
- << " (" << font->mFontIndex << ") " << name << LL_ENDL;
-
- if (new_font)
- {
- font_map.insert(voice_font_map_t::value_type(font->mID, font));
- font_list.insert(voice_effect_list_t::value_type(font->mName, font->mID));
- }
-
- mVoiceFontListDirty = true;
-
- // Debugging stuff
-
- if (font_type < VOICE_FONT_TYPE_NONE || font_type >= VOICE_FONT_TYPE_UNKNOWN)
- {
- LL_WARNS("VoiceFont") << "Unknown voice font type: " << font_type << LL_ENDL;
- }
- if (font_status < VOICE_FONT_STATUS_NONE || font_status >= VOICE_FONT_STATUS_UNKNOWN)
- {
- LL_WARNS("VoiceFont") << "Unknown voice font status: " << font_status << LL_ENDL;
- }
- }
-}
-
-void LLVivoxVoiceClient::expireVoiceFonts()
-{
- // *TODO: If we are selling voice fonts in packs, there are probably
- // going to be a number of fonts with the same expiration time, so would
- // be more efficient to just keep a list of expiration times rather
- // than checking each font individually.
-
- bool have_expired = false;
- bool expired_in_use = false;
-
- LLUUID current_effect = LLVoiceClient::instance().getVoiceEffectDefault();
-
- voice_font_map_t::iterator iter;
- for (iter = mVoiceFontMap.begin(); iter != mVoiceFontMap.end(); ++iter)
- {
- voiceFontEntry* voice_font = iter->second;
- LLFrameTimer& expiry_timer = voice_font->mExpiryTimer;
-
- // Check for expired voice fonts
- if (expiry_timer.getStarted() && expiry_timer.hasExpired())
- {
- // Check whether it is the active voice font
- if (voice_font->mID == current_effect)
- {
- // Reset to no voice effect.
- setVoiceEffect(LLUUID::null);
- expired_in_use = true;
- }
-
- LL_DEBUGS("Voice") << "Voice Font " << voice_font->mName << " has expired." << LL_ENDL;
- deleteVoiceFont(voice_font->mID);
- have_expired = true;
- }
- }
-
- LLSD args;
- args["URL"] = LLTrans::getString("voice_morphing_url");
- args["PREMIUM_URL"] = LLTrans::getString("premium_voice_morphing_url");
-
- // Give a notification if any voice fonts have expired.
- if (have_expired)
- {
- if (expired_in_use)
- {
- LLNotificationsUtil::add("VoiceEffectsExpiredInUse", args);
- }
- else
- {
- LLNotificationsUtil::add("VoiceEffectsExpired", args);
- }
-
- // Refresh voice font lists in the UI.
- notifyVoiceFontObservers();
- }
-}
-
-void LLVivoxVoiceClient::deleteVoiceFont(const LLUUID& id)
-{
- // Remove the entry from the voice font list.
- voice_effect_list_t::iterator list_iter = mVoiceFontList.begin();
- while (list_iter != mVoiceFontList.end())
- {
- if (list_iter->second == id)
- {
- LL_DEBUGS("VoiceFont") << "Removing " << id << " from the voice font list." << LL_ENDL;
- list_iter = mVoiceFontList.erase(list_iter);
- mVoiceFontListDirty = true;
- }
- else
- {
- ++list_iter;
- }
- }
-
- // Find the entry in the voice font map and erase its data.
- voice_font_map_t::iterator map_iter = mVoiceFontMap.find(id);
- if (map_iter != mVoiceFontMap.end())
- {
- delete map_iter->second;
- }
-
- // Remove the entry from the voice font map.
- mVoiceFontMap.erase(map_iter);
-}
-
-void LLVivoxVoiceClient::deleteAllVoiceFonts()
-{
- mVoiceFontList.clear();
-
- voice_font_map_t::iterator iter;
- for (iter = mVoiceFontMap.begin(); iter != mVoiceFontMap.end(); ++iter)
- {
- delete iter->second;
- }
- mVoiceFontMap.clear();
-}
-
-void LLVivoxVoiceClient::deleteVoiceFontTemplates()
-{
- mVoiceFontTemplateList.clear();
-
- voice_font_map_t::iterator iter;
- for (iter = mVoiceFontTemplateMap.begin(); iter != mVoiceFontTemplateMap.end(); ++iter)
- {
- delete iter->second;
- }
- mVoiceFontTemplateMap.clear();
-}
-
-S32 LLVivoxVoiceClient::getVoiceFontIndex(const LLUUID& id) const
-{
- S32 result = 0;
- if (!id.isNull())
- {
- voice_font_map_t::const_iterator it = mVoiceFontMap.find(id);
- if (it != mVoiceFontMap.end())
- {
- result = it->second->mFontIndex;
- }
- else
- {
- LL_WARNS("VoiceFont") << "Selected voice font " << id << " is not available." << LL_ENDL;
- }
- }
- return result;
-}
-
-S32 LLVivoxVoiceClient::getVoiceFontTemplateIndex(const LLUUID& id) const
-{
- S32 result = 0;
- if (!id.isNull())
- {
- voice_font_map_t::const_iterator it = mVoiceFontTemplateMap.find(id);
- if (it != mVoiceFontTemplateMap.end())
- {
- result = it->second->mFontIndex;
- }
- else
- {
- LL_WARNS("VoiceFont") << "Selected voice font template " << id << " is not available." << LL_ENDL;
- }
- }
- return result;
-}
-
-void LLVivoxVoiceClient::accountGetSessionFontsSendMessage()
-{
- if(mAccountLoggedIn)
- {
- std::ostringstream stream;
-
- LL_DEBUGS("VoiceFont") << "Requesting voice font list." << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.GetSessionFonts.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::accountGetTemplateFontsSendMessage()
-{
- if(mAccountLoggedIn)
- {
- std::ostringstream stream;
-
- LL_DEBUGS("VoiceFont") << "Requesting voice font template list." << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.GetTemplateFonts.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::sessionSetVoiceFontSendMessage(const sessionStatePtr_t &session)
-{
- S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
- LL_DEBUGS("VoiceFont") << "Requesting voice font: " << session->mVoiceFontID << " (" << font_index << "), session handle: " << session->mHandle << LL_ENDL;
-
- std::ostringstream stream;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetVoiceFont.1\">"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "<SessionFontID>" << font_index << "</SessionFontID>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::accountGetSessionFontsResponse(int statusCode, const std::string &statusString)
-{
- if (mIsWaitingForFonts)
- {
- // *TODO: We seem to get multiple events of this type. Should figure a way to advance only after
- // receiving the last one.
- LLSD result(LLSDMap("voice_fonts", LLSD::Boolean(true)));
-
- mVivoxPump.post(result);
- }
- notifyVoiceFontObservers();
- mVoiceFontsReceived = true;
-}
-
-void LLVivoxVoiceClient::accountGetTemplateFontsResponse(int statusCode, const std::string &statusString)
-{
- // Voice font list entries were updated via addVoiceFont() during parsing.
- notifyVoiceFontObservers();
-}
-void LLVivoxVoiceClient::addObserver(LLVoiceEffectObserver* observer)
-{
- mVoiceFontObservers.insert(observer);
-}
-
-void LLVivoxVoiceClient::removeObserver(LLVoiceEffectObserver* observer)
-{
- mVoiceFontObservers.erase(observer);
-}
-
-// method checks the item in VoiceMorphing menu for appropriate current voice font
-bool LLVivoxVoiceClient::onCheckVoiceEffect(const std::string& voice_effect_name)
-{
- LLVoiceEffectInterface * effect_interfacep = LLVoiceClient::instance().getVoiceEffectInterface();
- if (NULL != effect_interfacep)
- {
- const LLUUID& currect_voice_effect_id = effect_interfacep->getVoiceEffect();
-
- if (currect_voice_effect_id.isNull())
- {
- if (voice_effect_name == "NoVoiceMorphing")
- {
- return true;
- }
- }
- else
- {
- const LLSD& voice_effect_props = effect_interfacep->getVoiceEffectProperties(currect_voice_effect_id);
- if (voice_effect_props["name"].asString() == voice_effect_name)
- {
- return true;
- }
- }
- }
-
- return false;
-}
-
-// method changes voice font for selected VoiceMorphing menu item
-void LLVivoxVoiceClient::onClickVoiceEffect(const std::string& voice_effect_name)
-{
- LLVoiceEffectInterface * effect_interfacep = LLVoiceClient::instance().getVoiceEffectInterface();
- if (NULL != effect_interfacep)
- {
- if (voice_effect_name == "NoVoiceMorphing")
- {
- effect_interfacep->setVoiceEffect(LLUUID());
- return;
- }
- const voice_effect_list_t& effect_list = effect_interfacep->getVoiceEffectList();
- if (!effect_list.empty())
- {
- for (voice_effect_list_t::const_iterator it = effect_list.begin(); it != effect_list.end(); ++it)
- {
- if (voice_effect_name == it->first)
- {
- effect_interfacep->setVoiceEffect(it->second);
- return;
- }
- }
- }
- }
-}
-
-// it updates VoiceMorphing menu items in accordance with purchased properties
-void LLVivoxVoiceClient::updateVoiceMorphingMenu()
-{
- if (mVoiceFontListDirty)
- {
- LLVoiceEffectInterface * effect_interfacep = LLVoiceClient::instance().getVoiceEffectInterface();
- if (effect_interfacep)
- {
- const voice_effect_list_t& effect_list = effect_interfacep->getVoiceEffectList();
- if (!effect_list.empty())
- {
- LLMenuGL * voice_morphing_menup = gMenuBarView->findChildMenuByName("VoiceMorphing", true);
-
- if (NULL != voice_morphing_menup)
- {
- S32 items = voice_morphing_menup->getItemCount();
- if (items > 0)
- {
- voice_morphing_menup->erase(1, items - 3, false);
-
- S32 pos = 1;
- for (voice_effect_list_t::const_iterator it = effect_list.begin(); it != effect_list.end(); ++it)
- {
- LLMenuItemCheckGL::Params p;
- p.name = it->first;
- p.label = it->first;
- p.on_check.function(boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, this, it->first));
- p.on_click.function(boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, this, it->first));
- LLMenuItemCheckGL * voice_effect_itemp = LLUICtrlFactory::create<LLMenuItemCheckGL>(p);
- voice_morphing_menup->insert(pos++, voice_effect_itemp, false);
- }
-
- voice_morphing_menup->needsArrange();
- }
- }
- }
- }
- }
-}
-void LLVivoxVoiceClient::notifyVoiceFontObservers()
-{
- LL_DEBUGS("VoiceFont") << "Notifying voice effect observers. Lists changed: " << mVoiceFontListDirty << LL_ENDL;
-
- updateVoiceMorphingMenu();
-
- for (voice_font_observer_set_t::iterator it = mVoiceFontObservers.begin();
- it != mVoiceFontObservers.end();)
- {
- LLVoiceEffectObserver* observer = *it;
- observer->onVoiceEffectChanged(mVoiceFontListDirty);
- // In case onVoiceEffectChanged() deleted an entry.
- it = mVoiceFontObservers.upper_bound(observer);
- }
- mVoiceFontListDirty = false;
-
- // If new Voice Fonts have been added notify the user.
- if (mVoiceFontsNew)
- {
- if (mVoiceFontsReceived)
- {
- LLNotificationsUtil::add("VoiceEffectsNew");
- }
- mVoiceFontsNew = false;
- }
-}
-
-void LLVivoxVoiceClient::enablePreviewBuffer(bool enable)
-{
- LLSD result;
- mCaptureBufferMode = enable;
-
- if (enable)
- result["recplay"] = "start";
- else
- result["recplay"] = "quit";
-
- mVivoxPump.post(result);
-
- if(mCaptureBufferMode && mIsInChannel)
- {
- LL_DEBUGS("Voice") << "no channel" << LL_ENDL;
- sessionTerminate();
- }
-}
-
-void LLVivoxVoiceClient::recordPreviewBuffer()
-{
- if (!mCaptureBufferMode)
- {
- LL_DEBUGS("Voice") << "Not in voice effect preview mode, cannot start recording." << LL_ENDL;
- mCaptureBufferRecording = false;
- return;
- }
-
- mCaptureBufferRecording = true;
-
- LLSD result(LLSDMap("recplay", "record"));
- mVivoxPump.post(result);
-}
-
-void LLVivoxVoiceClient::playPreviewBuffer(const LLUUID& effect_id)
-{
- if (!mCaptureBufferMode)
- {
- LL_DEBUGS("Voice") << "Not in voice effect preview mode, no buffer to play." << LL_ENDL;
- mCaptureBufferRecording = false;
- return;
- }
-
- if (!mCaptureBufferRecorded)
- {
- // Can't play until we have something recorded!
- mCaptureBufferPlaying = false;
- return;
- }
-
- mPreviewVoiceFont = effect_id;
- mCaptureBufferPlaying = true;
-
- LLSD result(LLSDMap("recplay", "playback"));
- mVivoxPump.post(result);
-}
-
-void LLVivoxVoiceClient::stopPreviewBuffer()
-{
- mCaptureBufferRecording = false;
- mCaptureBufferPlaying = false;
-
- LLSD result(LLSDMap("recplay", "quit"));
- mVivoxPump.post(result);
-}
-
-bool LLVivoxVoiceClient::isPreviewRecording()
-{
- return (mCaptureBufferMode && mCaptureBufferRecording);
-}
-
-bool LLVivoxVoiceClient::isPreviewPlaying()
-{
- return (mCaptureBufferMode && mCaptureBufferPlaying);
-}
-
-void LLVivoxVoiceClient::captureBufferRecordStartSendMessage()
-{ if(mAccountLoggedIn)
- {
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Starting audio capture to buffer." << LL_ENDL;
-
- // Start capture
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.StartBufferCapture.1\">"
- << "</Request>"
- << "\n\n\n";
-
- // Unmute the mic
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Value>false</Value>"
- << "</Request>\n\n\n";
-
- // Dirty the mute mic state so that it will get reset when we finishing previewing
- mMuteMicDirty = true;
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::captureBufferRecordStopSendMessage()
-{
- if(mAccountLoggedIn)
- {
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Stopping audio capture to buffer." << LL_ENDL;
-
- // Mute the mic. Mic mute state was dirtied at recording start, so will be reset when finished previewing.
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Value>true</Value>"
- << "</Request>\n\n\n";
-
- // Stop capture
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStop.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::captureBufferPlayStartSendMessage(const LLUUID& voice_font_id)
-{
- if(mAccountLoggedIn)
- {
- // Track how may play requests are sent, so we know how many stop events to
- // expect before play actually stops.
- ++mPlayRequestCount;
-
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Starting audio buffer playback." << LL_ENDL;
-
- S32 font_index = getVoiceFontTemplateIndex(voice_font_id);
- LL_DEBUGS("Voice") << "With voice font: " << voice_font_id << " (" << font_index << ")" << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.PlayAudioBuffer.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "<TemplateFontID>" << font_index << "</TemplateFontID>"
- << "<FontDelta />"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::captureBufferPlayStopSendMessage()
-{
- if(mAccountLoggedIn)
- {
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Stopping audio buffer playback." << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStop.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-LLVivoxProtocolParser::LLVivoxProtocolParser()
-{
- parser = XML_ParserCreate(NULL);
-
- reset();
-}
-
-void LLVivoxProtocolParser::reset()
-{
- responseDepth = 0;
- ignoringTags = false;
- accumulateText = false;
- energy = 0.f;
- hasText = false;
- hasAudio = false;
- hasVideo = false;
- terminated = false;
- ignoreDepth = 0;
- isChannel = false;
- incoming = false;
- enabled = false;
- isEvent = false;
- isLocallyMuted = false;
- isModeratorMuted = false;
- isSpeaking = false;
- participantType = 0;
- returnCode = -1;
- state = 0;
- statusCode = 0;
- volume = 0;
- textBuffer.clear();
- alias.clear();
- numberOfAliases = 0;
- applicationString.clear();
-}
-
-//virtual
-LLVivoxProtocolParser::~LLVivoxProtocolParser()
-{
- if (parser)
- XML_ParserFree(parser);
-}
-
-static LLTrace::BlockTimerStatHandle FTM_VIVOX_PROCESS("Vivox Process");
-
-// virtual
-LLIOPipe::EStatus LLVivoxProtocolParser::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_VIVOX_PROCESS);
- LLBufferStream istr(channels, buffer.get());
- std::ostringstream ostr;
- while (istr.good())
- {
- char buf[1024];
- istr.read(buf, sizeof(buf));
- mInput.append(buf, istr.gcount());
- }
-
- // Look for input delimiter(s) in the input buffer. If one is found, send the message to the xml parser.
- size_t start = 0;
- size_t delim;
- while((delim = mInput.find("\n\n\n", start)) != std::string::npos)
- {
-
- // Reset internal state of the LLVivoxProtocolParser (no effect on the expat parser)
- reset();
-
- XML_ParserReset(parser, NULL);
- XML_SetElementHandler(parser, ExpatStartTag, ExpatEndTag);
- XML_SetCharacterDataHandler(parser, ExpatCharHandler);
- XML_SetUserData(parser, this);
- XML_Parse(parser, mInput.data() + start, static_cast<int>(delim - start), false);
-
-
- LL_DEBUGS("VivoxProtocolParser") << "parsing: " << mInput.substr(start, delim - start) << LL_ENDL;
- start = delim + 3;
- }
-
- if(start != 0)
- mInput = mInput.substr(start);
-
- LL_DEBUGS("VivoxProtocolParser") << "at end, mInput is: " << mInput << LL_ENDL;
-
- if(!LLVivoxVoiceClient::sConnected)
- {
- // If voice has been disabled, we just want to close the socket. This does so.
- LL_INFOS("Voice") << "returning STATUS_STOP" << LL_ENDL;
- return STATUS_STOP;
- }
-
- return STATUS_OK;
-}
-
-void XMLCALL LLVivoxProtocolParser::ExpatStartTag(void *data, const char *el, const char **attr)
-{
- if (data)
- {
- LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
- object->StartTag(el, attr);
- }
-}
-
-// --------------------------------------------------------------------------------
-
-void XMLCALL LLVivoxProtocolParser::ExpatEndTag(void *data, const char *el)
-{
- if (data)
- {
- LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
- object->EndTag(el);
- }
-}
-
-// --------------------------------------------------------------------------------
-
-void XMLCALL LLVivoxProtocolParser::ExpatCharHandler(void *data, const XML_Char *s, int len)
-{
- if (data)
- {
- LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
- object->CharData(s, len);
- }
-}
-
-// --------------------------------------------------------------------------------
-
-
-void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr)
-{
- // Reset the text accumulator. We shouldn't have strings that are inturrupted by new tags
- textBuffer.clear();
- // only accumulate text if we're not ignoring tags.
- accumulateText = !ignoringTags;
-
- if (responseDepth == 0)
- {
- isEvent = !stricmp("Event", tag);
-
- if (!stricmp("Response", tag) || isEvent)
- {
- // Grab the attributes
- while (*attr)
- {
- const char *key = *attr++;
- const char *value = *attr++;
-
- if (!stricmp("requestId", key))
- {
- requestId = value;
- }
- else if (!stricmp("action", key))
- {
- actionString = value;
- }
- else if (!stricmp("type", key))
- {
- eventTypeString = value;
- }
- }
- }
- LL_DEBUGS("VivoxProtocolParser") << tag << " (" << responseDepth << ")" << LL_ENDL;
- }
- else
- {
- if (ignoringTags)
- {
- LL_DEBUGS("VivoxProtocolParser") << "ignoring tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL;
- }
- else
- {
- LL_DEBUGS("VivoxProtocolParser") << tag << " (" << responseDepth << ")" << LL_ENDL;
-
- // Ignore the InputXml stuff so we don't get confused
- if (!stricmp("InputXml", tag))
- {
- ignoringTags = true;
- ignoreDepth = responseDepth;
- accumulateText = false;
-
- LL_DEBUGS("VivoxProtocolParser") << "starting ignore, ignoreDepth is " << ignoreDepth << LL_ENDL;
- }
- else if (!stricmp("CaptureDevices", tag))
- {
- LLVivoxVoiceClient::getInstance()->clearCaptureDevices();
- }
- else if (!stricmp("RenderDevices", tag))
- {
- LLVivoxVoiceClient::getInstance()->clearRenderDevices();
- }
- else if (!stricmp("CaptureDevice", tag))
- {
- deviceString.clear();
- }
- else if (!stricmp("RenderDevice", tag))
- {
- deviceString.clear();
- }
- else if (!stricmp("SessionFont", tag))
- {
- id = 0;
- nameString.clear();
- descriptionString.clear();
- expirationDate = LLDate();
- hasExpired = false;
- fontType = 0;
- fontStatus = 0;
- }
- else if (!stricmp("TemplateFont", tag))
- {
- id = 0;
- nameString.clear();
- descriptionString.clear();
- expirationDate = LLDate();
- hasExpired = false;
- fontType = 0;
- fontStatus = 0;
- }
- else if (!stricmp("MediaCompletionType", tag))
- {
- mediaCompletionType.clear();
- }
- }
- }
- responseDepth++;
-}
-
-// --------------------------------------------------------------------------------
-
-void LLVivoxProtocolParser::EndTag(const char *tag)
-{
- const std::string& string = textBuffer;
-
- responseDepth--;
-
- if (ignoringTags)
- {
- if (ignoreDepth == responseDepth)
- {
- LL_DEBUGS("VivoxProtocolParser") << "end of ignore" << LL_ENDL;
- ignoringTags = false;
- }
- else
- {
- LL_DEBUGS("VivoxProtocolParser") << "ignoring tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL;
- }
- }
-
- if (!ignoringTags)
- {
- LL_DEBUGS("VivoxProtocolParser") << "processing tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL;
-
- // Closing a tag. Finalize the text we've accumulated and reset
- if (!stricmp("ReturnCode", tag))
- returnCode = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("SessionHandle", tag))
- sessionHandle = string;
- else if (!stricmp("SessionGroupHandle", tag))
- sessionGroupHandle = string;
- else if (!stricmp("StatusCode", tag))
- statusCode = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("StatusString", tag))
- statusString = string;
- else if (!stricmp("ParticipantURI", tag))
- uriString = string;
- else if (!stricmp("Volume", tag))
- volume = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("Energy", tag))
- energy = (F32)strtod(string.c_str(), NULL);
- else if (!stricmp("IsModeratorMuted", tag))
- isModeratorMuted = !stricmp(string.c_str(), "true");
- else if (!stricmp("IsSpeaking", tag))
- isSpeaking = !stricmp(string.c_str(), "true");
- else if (!stricmp("Alias", tag))
- alias = string;
- else if (!stricmp("NumberOfAliases", tag))
- numberOfAliases = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("Application", tag))
- applicationString = string;
- else if (!stricmp("ConnectorHandle", tag))
- connectorHandle = string;
- else if (!stricmp("VersionID", tag))
- versionID = string;
- else if (!stricmp("Version", tag))
- mBuildID = string;
- else if (!stricmp("AccountHandle", tag))
- accountHandle = string;
- else if (!stricmp("State", tag))
- state = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("URI", tag))
- uriString = string;
- else if (!stricmp("IsChannel", tag))
- isChannel = !stricmp(string.c_str(), "true");
- else if (!stricmp("Incoming", tag))
- incoming = !stricmp(string.c_str(), "true");
- else if (!stricmp("Enabled", tag))
- enabled = !stricmp(string.c_str(), "true");
- else if (!stricmp("Name", tag))
- nameString = string;
- else if (!stricmp("AudioMedia", tag))
- audioMediaString = string;
- else if (!stricmp("ChannelName", tag))
- nameString = string;
- else if (!stricmp("DisplayName", tag))
- displayNameString = string;
- else if (!stricmp("Device", tag))
- deviceString = string;
- else if (!stricmp("AccountName", tag))
- nameString = string;
- else if (!stricmp("ParticipantType", tag))
- participantType = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("IsLocallyMuted", tag))
- isLocallyMuted = !stricmp(string.c_str(), "true");
- else if (!stricmp("MicEnergy", tag))
- energy = (F32)strtod(string.c_str(), NULL);
- else if (!stricmp("ChannelName", tag))
- nameString = string;
- else if (!stricmp("ChannelURI", tag))
- uriString = string;
- else if (!stricmp("BuddyURI", tag))
- uriString = string;
- else if (!stricmp("Presence", tag))
- statusString = string;
- else if (!stricmp("CaptureDevices", tag))
- {
- LLVivoxVoiceClient::getInstance()->setDevicesListUpdated(true);
- }
- else if (!stricmp("RenderDevices", tag))
- {
- LLVivoxVoiceClient::getInstance()->setDevicesListUpdated(true);
- }
- else if (!stricmp("CaptureDevice", tag))
- {
- LLVivoxVoiceClient::getInstance()->addCaptureDevice(LLVoiceDevice(displayNameString, deviceString));
- }
- else if (!stricmp("RenderDevice", tag))
- {
- LLVivoxVoiceClient::getInstance()->addRenderDevice(LLVoiceDevice(displayNameString, deviceString));
- }
- else if (!stricmp("BlockMask", tag))
- blockMask = string;
- else if (!stricmp("PresenceOnly", tag))
- presenceOnly = string;
- else if (!stricmp("AutoAcceptMask", tag))
- autoAcceptMask = string;
- else if (!stricmp("AutoAddAsBuddy", tag))
- autoAddAsBuddy = string;
- else if (!stricmp("MessageHeader", tag))
- messageHeader = string;
- else if (!stricmp("MessageBody", tag))
- messageBody = string;
- else if (!stricmp("NotificationType", tag))
- notificationType = string;
- else if (!stricmp("HasText", tag))
- hasText = !stricmp(string.c_str(), "true");
- else if (!stricmp("HasAudio", tag))
- hasAudio = !stricmp(string.c_str(), "true");
- else if (!stricmp("HasVideo", tag))
- hasVideo = !stricmp(string.c_str(), "true");
- else if (!stricmp("Terminated", tag))
- terminated = !stricmp(string.c_str(), "true");
- else if (!stricmp("SubscriptionHandle", tag))
- subscriptionHandle = string;
- else if (!stricmp("SubscriptionType", tag))
- subscriptionType = string;
- else if (!stricmp("SessionFont", tag))
- {
- LLVivoxVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDate, hasExpired, fontType, fontStatus, false);
- }
- else if (!stricmp("TemplateFont", tag))
- {
- LLVivoxVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDate, hasExpired, fontType, fontStatus, true);
- }
- else if (!stricmp("ID", tag))
- {
- id = strtol(string.c_str(), NULL, 10);
- }
- else if (!stricmp("Description", tag))
- {
- descriptionString = string;
- }
- else if (!stricmp("ExpirationDate", tag))
- {
- expirationDate = expiryTimeStampToLLDate(string);
- }
- else if (!stricmp("Expired", tag))
- {
- hasExpired = !stricmp(string.c_str(), "1");
- }
- else if (!stricmp("Type", tag))
- {
- fontType = strtol(string.c_str(), NULL, 10);
- }
- else if (!stricmp("Status", tag))
- {
- fontStatus = strtol(string.c_str(), NULL, 10);
- }
- else if (!stricmp("MediaCompletionType", tag))
- {
- mediaCompletionType = string;;
- }
-
- textBuffer.clear();
- accumulateText= false;
-
- if (responseDepth == 0)
- {
- // We finished all of the XML, process the data
- processResponse(tag);
- }
- }
-}
-
-// --------------------------------------------------------------------------------
-
-void LLVivoxProtocolParser::CharData(const char *buffer, int length)
-{
- /*
- This method is called for anything that isn't a tag, which can be text you
- want that lies between tags, and a lot of stuff you don't want like file formatting
- (tabs, spaces, CR/LF, etc).
-
- Only copy text if we are in accumulate mode...
- */
- if (accumulateText)
- textBuffer.append(buffer, length);
-}
-
-// --------------------------------------------------------------------------------
-
-LLDate LLVivoxProtocolParser::expiryTimeStampToLLDate(const std::string& vivox_ts)
-{
- // *HACK: Vivox reports the time incorrectly. LLDate also only parses a
- // subset of valid ISO 8601 dates (only handles Z, not offsets).
- // So just use the date portion and fix the time here.
- std::string time_stamp = vivox_ts.substr(0, 10);
- time_stamp += VOICE_FONT_EXPIRY_TIME;
-
- LL_DEBUGS("VivoxProtocolParser") << "Vivox timestamp " << vivox_ts << " modified to: " << time_stamp << LL_ENDL;
-
- return LLDate(time_stamp);
-}
-
-// --------------------------------------------------------------------------------
-
-void LLVivoxProtocolParser::processResponse(std::string tag)
-{
- LL_DEBUGS("VivoxProtocolParser") << tag << LL_ENDL;
-
- // SLIM SDK: the SDK now returns a statusCode of "200" (OK) for success. This is a change vs. previous SDKs.
- // According to Mike S., "The actual API convention is that responses with return codes of 0 are successful, regardless of the status code returned",
- // so I believe this will give correct behavior.
-
- if(returnCode == 0)
- statusCode = 0;
-
- if (isEvent)
- {
- const char *eventTypeCstr = eventTypeString.c_str();
- LL_DEBUGS("LowVoice") << eventTypeCstr << LL_ENDL;
-
- if (!stricmp(eventTypeCstr, "ParticipantUpdatedEvent"))
- {
- // These happen so often that logging them is pretty useless.
- LL_DEBUGS("LowVoice") << "Updated Params: " << sessionHandle << ", " << sessionGroupHandle << ", " << uriString << ", " << alias << ", " << isModeratorMuted << ", " << isSpeaking << ", " << volume << ", " << energy << LL_ENDL;
- LLVivoxVoiceClient::getInstance()->participantUpdatedEvent(sessionHandle, sessionGroupHandle, uriString, alias, isModeratorMuted, isSpeaking, volume, energy);
- }
- else if (!stricmp(eventTypeCstr, "AccountLoginStateChangeEvent"))
- {
- LLVivoxVoiceClient::getInstance()->accountLoginStateChangeEvent(accountHandle, statusCode, statusString, state);
- }
- else if (!stricmp(eventTypeCstr, "SessionAddedEvent"))
- {
- /*
- <Event type="SessionAddedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
- <Uri>sip:confctl-1408789@bhr.vivox.com</Uri>
- <IsChannel>true</IsChannel>
- <Incoming>false</Incoming>
- <ChannelName />
- </Event>
- */
- LLVivoxVoiceClient::getInstance()->sessionAddedEvent(uriString, alias, sessionHandle, sessionGroupHandle, isChannel, incoming, nameString, applicationString);
- }
- else if (!stricmp(eventTypeCstr, "SessionRemovedEvent"))
- {
- LLVivoxVoiceClient::getInstance()->sessionRemovedEvent(sessionHandle, sessionGroupHandle);
- }
- else if (!stricmp(eventTypeCstr, "SessionGroupUpdatedEvent"))
- {
- //nothng useful to process for this event, but we should not WARN that we have received it.
- }
- else if (!stricmp(eventTypeCstr, "SessionGroupAddedEvent"))
- {
- LLVivoxVoiceClient::getInstance()->sessionGroupAddedEvent(sessionGroupHandle);
- }
- else if (!stricmp(eventTypeCstr, "MediaStreamUpdatedEvent"))
- {
- /*
- <Event type="MediaStreamUpdatedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
- <StatusCode>200</StatusCode>
- <StatusString>OK</StatusString>
- <State>2</State>
- <Incoming>false</Incoming>
- </Event>
- */
- LLVivoxVoiceClient::getInstance()->mediaStreamUpdatedEvent(sessionHandle, sessionGroupHandle, statusCode, statusString, state, incoming);
- }
- else if (!stricmp(eventTypeCstr, "MediaCompletionEvent"))
- {
- /*
- <Event type="MediaCompletionEvent">
- <SessionGroupHandle />
- <MediaCompletionType>AuxBufferAudioCapture</MediaCompletionType>
- </Event>
- */
- LLVivoxVoiceClient::getInstance()->mediaCompletionEvent(sessionGroupHandle, mediaCompletionType);
- }
- else if (!stricmp(eventTypeCstr, "ParticipantAddedEvent"))
- {
- /*
- <Event type="ParticipantAddedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg4</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==4</SessionHandle>
- <ParticipantUri>sip:xI5auBZ60SJWIk606-1JGRQ==@bhr.vivox.com</ParticipantUri>
- <AccountName>xI5auBZ60SJWIk606-1JGRQ==</AccountName>
- <DisplayName />
- <ParticipantType>0</ParticipantType>
- </Event>
- */
- LL_DEBUGS("LowVoice") << "Added Params: " << sessionHandle << ", " << sessionGroupHandle << ", " << uriString << ", " << alias << ", " << nameString << ", " << displayNameString << ", " << participantType << LL_ENDL;
- LLVivoxVoiceClient::getInstance()->participantAddedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString, displayNameString, participantType);
- }
- else if (!stricmp(eventTypeCstr, "ParticipantRemovedEvent"))
- {
- /*
- <Event type="ParticipantRemovedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg4</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==4</SessionHandle>
- <ParticipantUri>sip:xtx7YNV-3SGiG7rA1fo5Ndw==@bhr.vivox.com</ParticipantUri>
- <AccountName>xtx7YNV-3SGiG7rA1fo5Ndw==</AccountName>
- </Event>
- */
- LL_DEBUGS("LowVoice") << "Removed params:" << sessionHandle << ", " << sessionGroupHandle << ", " << uriString << ", " << alias << ", " << nameString << LL_ENDL;
-
- LLVivoxVoiceClient::getInstance()->participantRemovedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString);
- }
- else if (!stricmp(eventTypeCstr, "AuxAudioPropertiesEvent"))
- {
- // These are really spammy in tuning mode
- LLVivoxVoiceClient::getInstance()->auxAudioPropertiesEvent(energy);
- }
- else if (!stricmp(eventTypeCstr, "MessageEvent"))
- {
- //TODO: This probably is not received any more, it was used to support SLim clients
- LLVivoxVoiceClient::getInstance()->messageEvent(sessionHandle, uriString, alias, messageHeader, messageBody, applicationString);
- }
- else if (!stricmp(eventTypeCstr, "SessionNotificationEvent"))
- {
- //TODO: This probably is not received any more, it was used to support SLim clients
- LLVivoxVoiceClient::getInstance()->sessionNotificationEvent(sessionHandle, uriString, notificationType);
- }
- else if (!stricmp(eventTypeCstr, "SessionUpdatedEvent"))
- {
- /*
- <Event type="SessionUpdatedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
- <Uri>sip:confctl-9@bhd.vivox.com</Uri>
- <IsMuted>0</IsMuted>
- <Volume>50</Volume>
- <TransmitEnabled>1</TransmitEnabled>
- <IsFocused>0</IsFocused>
- <SpeakerPosition><Position><X>0</X><Y>0</Y><Z>0</Z></Position></SpeakerPosition>
- <SessionFontID>0</SessionFontID>
- </Event>
- */
- // We don't need to process this, but we also shouldn't warn on it, since that confuses people.
- }
- else if (!stricmp(eventTypeCstr, "SessionGroupRemovedEvent"))
- {
- // We don't need to process this, but we also shouldn't warn on it, since that confuses people.
- }
- else if (!stricmp(eventTypeCstr, "VoiceServiceConnectionStateChangedEvent"))
- {
- LLVivoxVoiceClient::getInstance()->voiceServiceConnectionStateChangedEvent(statusCode, statusString, mBuildID);
- }
- else if (!stricmp(eventTypeCstr, "AudioDeviceHotSwapEvent"))
- {
- /*
- <Event type = "AudioDeviceHotSwapEvent">
- <EventType>RenderDeviceChanged< / EventType>
- <RelevantDevice>
- <Device>Speakers(Turtle Beach P11 Headset)< / Device>
- <DisplayName>Speakers(Turtle Beach P11 Headset)< / DisplayName>
- <Type>SpecificDevice< / Type>
- < / RelevantDevice>
- < / Event>
- */
- // an audio device was removed or added, fetch and update the local list of audio devices.
- LLVivoxVoiceClient::getInstance()->getCaptureDevicesSendMessage();
- LLVivoxVoiceClient::getInstance()->getRenderDevicesSendMessage();
- }
- else
- {
- LL_WARNS("VivoxProtocolParser") << "Unknown event type " << eventTypeString << LL_ENDL;
- }
- }
- else
- {
- const char *actionCstr = actionString.c_str();
- LL_DEBUGS("LowVoice") << actionCstr << LL_ENDL;
-
- if (!stricmp(actionCstr, "Session.Set3DPosition.1"))
- {
- // We don't need to process these
- }
- else if (!stricmp(actionCstr, "Connector.Create.1"))
- {
- LLVivoxVoiceClient::getInstance()->connectorCreateResponse(statusCode, statusString, connectorHandle, versionID);
- }
- else if (!stricmp(actionCstr, "Account.Login.1"))
- {
- LLVivoxVoiceClient::getInstance()->loginResponse(statusCode, statusString, accountHandle, numberOfAliases);
- }
- else if (!stricmp(actionCstr, "Session.Create.1"))
- {
- LLVivoxVoiceClient::getInstance()->sessionCreateResponse(requestId, statusCode, statusString, sessionHandle);
- }
- else if (!stricmp(actionCstr, "SessionGroup.AddSession.1"))
- {
- LLVivoxVoiceClient::getInstance()->sessionGroupAddSessionResponse(requestId, statusCode, statusString, sessionHandle);
- }
- else if (!stricmp(actionCstr, "Session.Connect.1"))
- {
- LLVivoxVoiceClient::getInstance()->sessionConnectResponse(requestId, statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Account.Logout.1"))
- {
- LLVivoxVoiceClient::getInstance()->logoutResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Connector.InitiateShutdown.1"))
- {
- LLVivoxVoiceClient::getInstance()->connectorShutdownResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Account.GetSessionFonts.1"))
- {
- LLVivoxVoiceClient::getInstance()->accountGetSessionFontsResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Account.GetTemplateFonts.1"))
- {
- LLVivoxVoiceClient::getInstance()->accountGetTemplateFontsResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Aux.SetVadProperties.1"))
- {
- // both values of statusCode (old and more recent) indicate valid requests
- if (statusCode != 0 && statusCode != 200)
- {
- LL_WARNS("Voice") << "Aux.SetVadProperties.1 request failed: "
- << "statusCode: " << statusCode
- << " and "
- << "statusString: " << statusString
- << LL_ENDL;
- }
- }
- /*
- else if (!stricmp(actionCstr, "Account.ChannelGetList.1"))
- {
- LLVoiceClient::getInstance()->channelGetListResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Connector.AccountCreate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Connector.MuteLocalMic.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Connector.MuteLocalSpeaker.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Connector.SetLocalMicVolume.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Connector.SetLocalSpeakerVolume.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Session.ListenerSetPosition.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Session.SpeakerSetPosition.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Session.AudioSourceSetPosition.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Session.GetChannelParticipants.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelCreate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelUpdate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelDelete.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelCreateAndInvite.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelFolderCreate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelFolderUpdate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelFolderDelete.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelAddModerator.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelDeleteModerator.1"))
- {
-
- }
- */
- }
-}
-
-LLVivoxSecurity::LLVivoxSecurity()
-{
- // This size is an arbitrary choice; Vivox does not care
- // Use a multiple of three so that there is no '=' padding in the base64 (purely an esthetic choice)
- #define VIVOX_TOKEN_BYTES 9
- U8 random_value[VIVOX_TOKEN_BYTES];
-
- for (int b = 0; b < VIVOX_TOKEN_BYTES; b++)
- {
- random_value[b] = ll_rand() & 0xff;
- }
- mConnectorHandle = LLBase64::encode(random_value, VIVOX_TOKEN_BYTES);
-
- for (int b = 0; b < VIVOX_TOKEN_BYTES; b++)
- {
- random_value[b] = ll_rand() & 0xff;
- }
- mAccountHandle = LLBase64::encode(random_value, VIVOX_TOKEN_BYTES);
-}
-
-LLVivoxSecurity::~LLVivoxSecurity()
-{
-}
-
-bool LLVivoxVoiceP2PIncomingCall::answerInvite() { return LLVivoxVoiceClient::getInstance()->answerInvite(mCallInfo["session_handle"]); }
-
-void LLVivoxVoiceP2PIncomingCall::declineInvite() { LLVivoxVoiceClient::getInstance()->declineInvite(mCallInfo["session_handle"]); }
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
deleted file mode 100644
index 3167705528..0000000000
--- a/indra/newview/llvoicevivox.h
+++ /dev/null
@@ -1,1093 +0,0 @@
-/**
- * @file llvoicevivox.h
- * @brief Declaration of LLDiamondwareVoiceClient class which is the interface to the voice client process.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-#ifndef LL_VOICE_VIVOX_H
-#define LL_VOICE_VIVOX_H
-
-class LLVOAvatar;
-class LLVivoxProtocolParser;
-
-#include "lliopipe.h"
-#include "llpumpio.h"
-#include "llchainio.h"
-#include "lliosocket.h"
-#include "v3math.h"
-#include "llframetimer.h"
-#include "llviewerregion.h"
-#include "llcallingcard.h" // for LLFriendObserver
-#include "lleventcoro.h"
-#include "llcoros.h"
-#include <queue>
-
-#ifdef LL_USESYSTEMLIBS
-# include "expat.h"
-#else
-# include "expat/expat.h"
-#endif
-#include "llvoiceclient.h"
-
-class LLAvatarName;
-class LLVivoxVoiceClientMuteListObserver;
-
-extern const std::string VIVOX_VOICE_SERVER_TYPE;
-
-class LLVivoxVoiceP2PIncomingCall : public LLVoiceP2PIncomingCallInterface
-{
- public:
- LLVivoxVoiceP2PIncomingCall(const LLSD& call_info) : mCallInfo(call_info) {}
- ~LLVivoxVoiceP2PIncomingCall() override {}
-
- bool answerInvite() override;
- void declineInvite() override;
-
- protected:
- LLSD mCallInfo;
-};
-
-class LLVivoxVoiceClient : public LLSingleton<LLVivoxVoiceClient>,
- virtual public LLVoiceModuleInterface,
- virtual public LLVoiceEffectInterface,
- virtual public LLVoiceP2POutgoingCallInterface
-{
- LLSINGLETON(LLVivoxVoiceClient);
- LOG_CLASS(LLVivoxVoiceClient);
- virtual ~LLVivoxVoiceClient();
-
-public:
- /// @name LLVoiceModuleInterface virtual implementations
- /// @see LLVoiceModuleInterface
- //@{
- void init(LLPumpIO *pump) override; // Call this once at application startup (creates connector)
- void terminate() override; // Call this to clean up during shutdown
-
- const LLVoiceVersionInfo& getVersion() override;
-
- void updateSettings() override; // call after loading settings and whenever they change
-
- // Returns true if vivox has successfully logged in and is not in error state
- bool isVoiceWorking() const override;
-
- void setHidden(bool hidden) override; // virtual
-
- /////////////////////
- /// @name Tuning
- //@{
- void tuningStart() override;
- void tuningStop() override;
- bool inTuningMode() override;
-
- void tuningSetMicVolume(float volume) override;
- void tuningSetSpeakerVolume(float volume) override;
- float tuningGetEnergy(void) override;
-
- //@}
-
- /////////////////////
- /// @name Devices
- //@{
- // This returns true when it's safe to bring up the "device settings" dialog in the prefs.
- // i.e. when the daemon is running and connected, and the device lists are populated.
- bool deviceSettingsAvailable() override;
- bool deviceSettingsUpdated() override; //return if the list has been updated and never fetched, only to be called from the voicepanel.
-
- // Requery the vivox daemon for the current list of input/output devices.
- // If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed
- // (use this if you want to know when it's done).
- // If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim.
- void refreshDeviceLists(bool clearCurrentList = true) override;
-
- void setCaptureDevice(const std::string& name) override;
- void setRenderDevice(const std::string& name) override;
-
- LLVoiceDeviceList& getCaptureDevices() override;
- LLVoiceDeviceList& getRenderDevices() override;
- //@}
-
- void getParticipantList(std::set<LLUUID> &participants) override;
- bool isParticipant(const LLUUID& speaker_id) override;
-
- // Send a text message to the specified user, initiating the session if necessary.
- // virtual bool sendTextMessage(const LLUUID& participant_id, const std::string& message) const {return false;};
-
- // Returns true if calling back the session URI after the session has closed is possible.
- // Currently this will be false only for PSTN P2P calls.
- // NOTE: this will return true if the session can't be found.
- bool isSessionCallBackPossible(const LLUUID &session_id) override;
-
- // Returns true if the session can accepte text IM's.
- // Currently this will be false only for PSTN P2P calls.
- // NOTE: this will return true if the session can't be found.
- bool isSessionTextIMPossible(const LLUUID &session_id) override;
-
- ////////////////////////////
- /// @name Channel stuff
- //@{
- // returns true iff the user is currently in a proximal (local spatial) channel.
- // Note that gestures should only fire if this returns true.
- bool inProximalChannel() override;
-
- void setNonSpatialChannel(const LLSD& channelInfo,
- bool notify_on_first_join,
- bool hangup_on_last_leave) override;
-
- bool setSpatialChannel(const LLSD& channelInfo) override;
-
- void leaveNonSpatialChannel() override;
-
- void processChannels(bool process) override;
-
- void leaveChannel(void);
-
- bool isCurrentChannel(const LLSD &channelInfo) override;
- bool compareChannels(const LLSD &channelInfo1, const LLSD &channelInfo2) override;
-
- //@}
-
-
- //////////////////////////
- /// @name LLVoiceP2POutgoingCallInterface
- //@{
- // start a voice channel with the specified user
- void callUser(const LLUUID &uuid) override;
- void hangup() override;
-
- //@}
-
- LLVoiceP2POutgoingCallInterface *getOutgoingCallInterface() override { return this; }
-
- LLVoiceP2PIncomingCallInterfacePtr getIncomingCallInterface(const LLSD &voice_call_info) override;
-
- bool answerInvite(const std::string &sessionHandle);
- void declineInvite(const std::string &sessionHandle);
-
- /////////////////////////
- /// @name Volume/gain
- //@{
- void setVoiceVolume(F32 volume) override;
- void setMicGain(F32 volume) override;
- //@}
-
- /////////////////////////
- /// @name enable disable voice and features
- //@{
- void setVoiceEnabled(bool enabled) override;
- void setMuteMic(bool muted) override; // Set the mute state of the local mic.
- //@}
-
- //////////////////////////
- /// @name nearby speaker accessors
- //@{
- std::string getDisplayName(const LLUUID& id) override;
- bool isParticipantAvatar(const LLUUID &id) override;
- bool getIsSpeaking(const LLUUID& id) override;
- bool getIsModeratorMuted(const LLUUID& id) override;
- F32 getCurrentPower(const LLUUID& id) override; // "power" is related to "amplitude" in a defined way. I'm just not sure what the formula is...
- F32 getUserVolume(const LLUUID& id) override;
- void setUserVolume(const LLUUID& id, F32 volume) override; // set's volume for specified agent, from 0-1 (where .5 is nominal)
- //@}
-
- // authorize the user
- void userAuthorized(const std::string& user_id,
- const LLUUID &agentID) override;
-
- //////////////////////////////
- /// @name Status notification
- //@{
- void addObserver(LLVoiceClientStatusObserver* observer) override;
- void removeObserver(LLVoiceClientStatusObserver* observer) override;
- void addObserver(LLFriendObserver* observer) override;
- void removeObserver(LLFriendObserver* observer) override;
- void addObserver(LLVoiceClientParticipantObserver* observer) override;
- void removeObserver(LLVoiceClientParticipantObserver* observer) override;
- //@}
-
- std::string sipURIFromID(const LLUUID &id) const override;
- LLSD getP2PChannelInfoTemplate(const LLUUID& id) const override;
- //@}
-
- /// @name LLVoiceEffectInterface virtual implementations
- /// @see LLVoiceEffectInterface
- //@{
-
- //////////////////////////
- /// @name Accessors
- //@{
- bool setVoiceEffect(const LLUUID& id) override;
- const LLUUID getVoiceEffect() override;
- LLSD getVoiceEffectProperties(const LLUUID& id) override;
-
- void refreshVoiceEffectLists(bool clear_lists) override;
- const voice_effect_list_t& getVoiceEffectList() const override;
- const voice_effect_list_t& getVoiceEffectTemplateList() const override;
- //@}
-
- //////////////////////////////
- /// @name Status notification
- //@{
- void addObserver(LLVoiceEffectObserver* observer) override;
- void removeObserver(LLVoiceEffectObserver* observer) override;
- //@}
-
- //////////////////////////////
- /// @name Effect preview buffer
- //@{
- void enablePreviewBuffer(bool enable) override;
- void recordPreviewBuffer() override;
- void playPreviewBuffer(const LLUUID& effect_id = LLUUID::null) override;
- void stopPreviewBuffer() override;
-
- bool isPreviewRecording() override;
- bool isPreviewPlaying() override;
- //@}
-
- //@}
-
- bool onCheckVoiceEffect(const std::string& voice_effect_name);
- void onClickVoiceEffect(const std::string& voice_effect_name);
-
-protected:
- //////////////////////
- // Vivox Specific definitions
-
- friend class LLVivoxVoiceClientMuteListObserver;
- friend class LLVivoxVoiceClientFriendsObserver;
-
-
- enum streamState
- {
- streamStateUnknown = 0,
- streamStateIdle = 1,
- streamStateConnected = 2,
- streamStateRinging = 3,
- streamStateConnecting = 6, // same as Vivox session_media_connecting enum
- streamStateDisconnecting = 7, //Same as Vivox session_media_disconnecting enum
- };
-
- struct participantState
- {
- public:
- participantState(const std::string &uri);
-
- bool updateMuteState(); // true if mute state has changed
- bool isAvatar();
-
- std::string mURI;
- LLUUID mAvatarID;
- std::string mAccountName;
- std::string mDisplayName;
- LLFrameTimer mSpeakingTimeout;
- F32 mLastSpokeTimestamp;
- F32 mPower;
- F32 mVolume;
- std::string mGroupID;
- int mUserVolume;
- bool mPTT;
- bool mIsSpeaking;
- bool mIsModeratorMuted;
- bool mOnMuteList; // true if this avatar is on the user's mute list (and should be muted)
- bool mVolumeSet; // true if incoming volume messages should not change the volume
- bool mVolumeDirty; // true if this participant needs a volume command sent (either mOnMuteList or mUserVolume has changed)
- bool mAvatarIDValid;
- bool mIsSelf;
- };
- typedef std::shared_ptr<participantState> participantStatePtr_t;
- typedef std::weak_ptr<participantState> participantStateWptr_t;
-
- typedef std::map<const std::string, participantStatePtr_t> participantMap;
- typedef std::map<const LLUUID, participantStatePtr_t> participantUUIDMap;
-
- struct sessionState
- {
- public:
- typedef std::shared_ptr<sessionState> ptr_t;
- typedef std::weak_ptr<sessionState> wptr_t;
-
- typedef std::function<void(const ptr_t &)> sessionFunc_t;
-
- static ptr_t createSession();
- ~sessionState();
-
- LLSD getVoiceChannelInfo();
-
- participantStatePtr_t addParticipant(const std::string &uri);
- void removeParticipant(const participantStatePtr_t &participant);
- void removeAllParticipants();
-
- participantStatePtr_t findParticipant(const std::string &uri);
- participantStatePtr_t findParticipantByID(const LLUUID& id);
-
- static ptr_t matchSessionByHandle(const std::string &handle);
- static ptr_t matchCreatingSessionByURI(const std::string &uri);
- static ptr_t matchSessionByURI(const std::string &uri);
- static ptr_t matchSessionByParticipant(const LLUUID &participant_id);
-
- bool isCallBackPossible();
- bool isTextIMPossible();
- bool isSpatial() { return mIsSpatial; }
-
- static void for_each(sessionFunc_t func);
-
- std::string mHandle;
- std::string mGroupHandle;
- std::string mSIPURI;
- std::string mAlias;
- std::string mName;
- std::string mAlternateSIPURI;
- std::string mHash; // Channel password
- std::string mErrorStatusString;
- std::queue<std::string> mTextMsgQueue;
-
- LLUUID mIMSessionID;
- LLUUID mCallerID;
- int mErrorStatusCode;
- int mMediaStreamState;
- bool mCreateInProgress; // True if a Session.Create has been sent for this session and no response has been received yet.
- bool mMediaConnectInProgress; // True if a Session.MediaConnect has been sent for this session and no response has been received yet.
- bool mVoiceInvitePending; // True if a voice invite is pending for this session (usually waiting on a name lookup)
- bool mTextInvitePending; // True if a text invite is pending for this session (usually waiting on a name lookup)
- bool mSynthesizedCallerID; // True if the caller ID is a hash of the SIP URI -- this means we shouldn't do a name lookup.
- bool mIsChannel; // True for both group and spatial channels (false for p2p, PSTN)
- bool mIsSpatial; // True for spatial channels
- bool mIsP2P;
- bool mIncoming;
- bool mVoiceActive;
- bool mReconnect; // Whether we should try to reconnect to this session if it's dropped
-
- // Set to true when the volume/mute state of someone in the participant list changes.
- // The code will have to walk the list to find the changed participant(s).
- bool mVolumeDirty;
- bool mMuteDirty;
-
- bool mParticipantsChanged;
- participantMap mParticipantsByURI;
- participantUUIDMap mParticipantsByUUID;
-
- LLUUID mVoiceFontID;
-
- static void VerifySessions();
-
- private:
- sessionState();
-
- static std::set<wptr_t, std::owner_less<wptr_t>> mSession; // canonical list of outstanding sessions.
- std::set<wptr_t>::iterator mMyIterator; // used for delete
-
- static void for_eachPredicate(const wptr_t &a, sessionFunc_t func);
-
- static bool testByHandle(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string handle);
- static bool testByCreatingURI(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string uri);
- static bool testBySIPOrAlterateURI(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string uri);
- static bool testByCallerId(const LLVivoxVoiceClient::sessionState::wptr_t &a, LLUUID participantId);
-
- };
- typedef std::shared_ptr<sessionState> sessionStatePtr_t;
-
- typedef std::map<std::string, sessionStatePtr_t> sessionMap;
-
- ///////////////////////////////////////////////////////
- // Private Member Functions
- //////////////////////////////////////////////////////
-
-
-
- //////////////////////////////
- /// @name TVC/Server management and communication
- //@{
- // Call this if the connection to the daemon terminates unexpectedly. It will attempt to reset everything and relaunch.
- void daemonDied();
-
- // Call this if we're just giving up on voice (can't provision an account, etc.). It will clean up and go away.
- void giveUp();
-
- // write to the tvc
- bool writeString(const std::string &str);
-
- void connectorCreate();
- void connectorShutdown();
- void closeSocket(void);
-
-// void requestVoiceAccountProvision(S32 retries = 3);
- void setLoginInfo(
- const std::string& account_name,
- const std::string& password,
- const std::string& voice_sip_uri_hostname,
- const std::string& voice_account_server_uri);
- void loginSendMessage();
- void logout();
- void logoutSendMessage();
-
-
- //@}
-
- //------------------------------------
- // tuning
-
- void tuningRenderStartSendMessage(const std::string& name, bool loop);
- void tuningRenderStopSendMessage();
-
- void tuningCaptureStartSendMessage(int duration);
- void tuningCaptureStopSendMessage();
-
- //----------------------------------
- // devices
- void clearCaptureDevices();
- void addCaptureDevice(const LLVoiceDevice& device);
- void clearRenderDevices();
- void setDevicesListUpdated(bool state);
- void addRenderDevice(const LLVoiceDevice& device);
- void buildSetAudioDevices(std::ostringstream &stream);
-
- void getCaptureDevicesSendMessage();
- void getRenderDevicesSendMessage();
-
- // local audio updates, mic mute, speaker mute, mic volume and speaker volumes
- void sendLocalAudioUpdates();
-
- /////////////////////////////
- // Response/Event handlers
- void connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID);
- void loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases);
- void sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle);
- void sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle);
- void sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString);
- void logoutResponse(int statusCode, std::string &statusString);
- void connectorShutdownResponse(int statusCode, std::string &statusString);
-
- void accountLoginStateChangeEvent(std::string &accountHandle, int statusCode, std::string &statusString, int state);
- void mediaCompletionEvent(std::string &sessionGroupHandle, std::string &mediaCompletionType);
- void mediaStreamUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, int statusCode, std::string &statusString, int state, bool incoming);
- void sessionAddedEvent(std::string &uriString, std::string &alias, std::string &sessionHandle, std::string &sessionGroupHandle, bool isChannel, bool incoming, std::string &nameString, std::string &applicationString);
- void sessionGroupAddedEvent(std::string &sessionGroupHandle);
- void sessionRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle);
- void participantAddedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString, std::string &displayNameString, int participantType);
- void participantRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString);
- void participantUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, bool isModeratorMuted, bool isSpeaking, int volume, F32 energy);
- void voiceServiceConnectionStateChangedEvent(int statusCode, std::string &statusString, std::string &build_id);
- void auxAudioPropertiesEvent(F32 energy);
- void messageEvent(std::string &sessionHandle, std::string &uriString, std::string &alias, std::string &messageHeader, std::string &messageBody, std::string &applicationString);
- void sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string &notificationType);
-
- void muteListChanged();
-
- /////////////////////////////
- // VAD changes
- // disable auto-VAD and configure VAD parameters explicitly
- void setupVADParams(unsigned int vad_auto, unsigned int vad_hangover, unsigned int vad_noise_floor, unsigned int vad_sensitivity);
- void onVADSettingsChange();
-
- /////////////////////////////
- // Sending updates of current state
- void updatePosition(void);
- void setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot);
- void setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLQuaternion &rot);
- bool channelFromRegion(LLViewerRegion *region, std::string &name);
-
- void setEarLocation(S32 loc);
-
-
- /////////////////////////////
- // Accessors for data related to nearby speakers
-
- // MBW -- XXX -- Not sure how to get this data out of the TVC
- bool getUsingPTT(const LLUUID& id);
- std::string getGroupID(const LLUUID& id); // group ID if the user is in group chat (empty string if not applicable)
-
- /////////////////////////////
- // Recording controls
- void recordingLoopStart(int seconds = 3600, int deltaFramesPerControlFrame = 200);
- void recordingLoopSave(const std::string& filename);
- void recordingStop();
-
- // Playback controls
- void filePlaybackStart(const std::string& filename);
- void filePlaybackStop();
- void filePlaybackSetPaused(bool paused);
- void filePlaybackSetMode(bool vox = false, float speed = 1.0f);
-
- participantStatePtr_t findParticipantByID(const LLUUID& id);
-
-
-#if 0
- ////////////////////////////////////////
- // voice sessions.
- typedef std::set<sessionStatePtr_t> sessionSet;
-
- typedef sessionSet::iterator sessionIterator;
- sessionIterator sessionsBegin(void);
- sessionIterator sessionsEnd(void);
-#endif
-
- sessionStatePtr_t findSession(const std::string &handle);
- sessionStatePtr_t findSessionBeingCreatedByURI(const std::string &uri);
- sessionStatePtr_t findSession(const LLUUID &participant_id);
-
- sessionStatePtr_t addSession(const std::string &uri, const std::string &handle = std::string());
- void clearSessionHandle(const sessionStatePtr_t &session);
- void setSessionHandle(const sessionStatePtr_t &session, const std::string &handle);
- void setSessionURI(const sessionStatePtr_t &session, const std::string &uri);
- void deleteSession(const sessionStatePtr_t &session);
- void deleteAllSessions(void);
-
- void verifySessionState(void);
-
- void joinedAudioSession(const sessionStatePtr_t &session);
- void leftAudioSession(const sessionStatePtr_t &session);
-
- // This is called in several places where the session _may_ need to be deleted.
- // It contains logic for whether to delete the session or keep it around.
- void reapSession(const sessionStatePtr_t &session);
-
- // Returns true if the session seems to indicate we've moved to a region on a different voice server
- bool sessionNeedsRelog(const sessionStatePtr_t &session);
-
-
- //////////////////////////////////////
- // buddy list stuff, needed for SLIM later
- struct buddyListEntry
- {
- buddyListEntry(const std::string &uri);
- std::string mURI;
- std::string mDisplayName;
- LLUUID mUUID;
- bool mOnlineSL;
- bool mOnlineSLim;
- bool mCanSeeMeOnline;
- bool mHasBlockListEntry;
- bool mHasAutoAcceptListEntry;
- bool mNameResolved;
- bool mInSLFriends;
- bool mInVivoxBuddies;
- };
-
- typedef std::map<std::string, buddyListEntry*> buddyListMap;
-
- /////////////////////////////
- // session control messages
-
- void accountListBlockRulesSendMessage();
- void accountListAutoAcceptRulesSendMessage();
-
- void sessionGroupCreateSendMessage();
- void sessionCreateSendMessage(const sessionStatePtr_t &session, bool startAudio = true, bool startText = false);
- void sessionGroupAddSessionSendMessage(const sessionStatePtr_t &session, bool startAudio = true, bool startText = false);
- void sessionMediaConnectSendMessage(const sessionStatePtr_t &session); // just joins the audio session
- void sessionTextConnectSendMessage(const sessionStatePtr_t &session); // just joins the text session
- void sessionTerminateSendMessage(const sessionStatePtr_t &session);
- void sessionGroupTerminateSendMessage(const sessionStatePtr_t &session);
- void sessionMediaDisconnectSendMessage(const sessionStatePtr_t &session);
- // void sessionTextDisconnectSendMessage(sessionState *session);
-
-
-
- // Pokes the state machine to leave the audio session next time around.
- void sessionTerminate();
-
- // Pokes the state machine to shut down the connector and restart it.
- void requestRelog();
-
- // Does the actual work to get out of the audio session
- void leaveAudioSession();
-
- friend class LLVivoxVoiceClientCapResponder;
-
-
- void lookupName(const LLUUID &id);
- void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
- void avatarNameResolved(const LLUUID &id, const std::string &name);
- static void predAvatarNameResolution(const LLVivoxVoiceClient::sessionStatePtr_t &session, LLUUID id, std::string name);
-
- boost::signals2::connection mAvatarNameCacheConnection;
-
- /////////////////////////////
- // Voice fonts
-
- void addVoiceFont(const S32 id,
- const std::string &name,
- const std::string &description,
- const LLDate &expiration_date,
- bool has_expired,
- const S32 font_type,
- const S32 font_status,
- const bool template_font = false);
- void accountGetSessionFontsResponse(int statusCode, const std::string &statusString);
- void accountGetTemplateFontsResponse(int statusCode, const std::string &statusString);
-
-private:
-
- LLVoiceVersionInfo mVoiceVersion;
-
- // Coroutine support methods
- //---
- void voiceControlCoro();
- void voiceControlStateMachine(S32 &coro_state);
-
- bool endAndDisconnectSession();
-
- bool callbackEndDaemon(const LLSD& data);
- bool startAndLaunchDaemon();
- bool provisionVoiceAccount();
- bool establishVoiceConnection();
- bool breakVoiceConnection(bool wait);
- bool loginToVivox();
- void logoutOfVivox(bool wait);
- bool retrieveVoiceFonts();
-
- bool requestParcelVoiceInfo();
-
- bool addAndJoinSession(const sessionStatePtr_t &nextSession);
- bool terminateAudioSession(bool wait);
-
- bool waitForChannel();
- bool runSession(const sessionStatePtr_t &session);
-
- void recordingAndPlaybackMode();
- int voiceRecordBuffer();
- int voicePlaybackBuffer();
-
- bool performMicTuning();
- //---
- /// Clean up objects created during a voice session.
- void cleanUp();
-
- bool mSessionTerminateRequested;
- bool mRelogRequested;
- // Number of times (in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine().
- // The larger it is the greater is possibility there is a problem with connection to voice server.
- // Introduced while fixing EXT-4313.
- int mSpatialJoiningNum;
-
- static void idle(void *user_data);
-
- LLHost mDaemonHost;
- LLSocket::ptr_t mSocket;
-
- // We should kill the voice daemon in case of connection alert
- bool mTerminateDaemon;
-
- friend class LLVivoxProtocolParser;
-
- std::string mAccountName;
- std::string mAccountPassword;
- std::string mAccountDisplayName;
-
- bool mTuningMode;
- float mTuningEnergy;
- std::string mTuningAudioFile;
- int mTuningMicVolume;
- bool mTuningMicVolumeDirty;
- int mTuningSpeakerVolume;
- bool mTuningSpeakerVolumeDirty;
- bool mDevicesListUpdated; // set to true when the device list has been updated
- // and false when the panelvoicedevicesettings has queried for an update status.
-
- std::string mSpatialSessionURI;
- std::string mSpatialSessionCredentials;
-
- std::string mMainSessionGroupHandle; // handle of the "main" session group.
-
- std::string mChannelName; // Name of the channel to be looked up
- sessionStatePtr_t mAudioSession; // Session state for the current audio session
-
- sessionStatePtr_t mNextAudioSession; // Session state for the audio session we're trying to join
-
- S32 mCurrentParcelLocalID; // Used to detect parcel boundary crossings
- std::string mCurrentRegionName; // Used to detect parcel boundary crossings
-
- bool mConnectorEstablished; // set by "Create Connector" response
- bool mAccountLoggedIn; // set by login message
- int mNumberOfAliases;
- U32 mCommandCookie;
-
- std::string mVoiceAccountServerURI;
- std::string mVoiceSIPURIHostName;
-
- int mLoginRetryCount;
-
- sessionMap mSessionsByHandle; // Active sessions, indexed by session handle. Sessions which are being initiated may not be in this map.
-#if 0
- sessionSet mSessions; // All sessions, not indexed. This is the canonical session list.
-#endif
-
- bool mBuddyListMapPopulated;
- bool mBlockRulesListReceived;
- bool mAutoAcceptRulesListReceived;
- buddyListMap mBuddyListMap;
-
- LLVoiceDeviceList mCaptureDevices;
- LLVoiceDeviceList mRenderDevices;
-
- std::string mCaptureDevice;
- std::string mRenderDevice;
- bool mCaptureDeviceDirty;
- bool mRenderDeviceDirty;
-
- bool mIsInitialized;
- bool mShutdownComplete;
-
- bool checkParcelChanged(bool update = false);
- bool switchChannel(std::string uri = std::string(), bool spatial = true, bool no_reconnect = false, bool is_p2p = false, std::string hash = "");
- void joinSession(const sessionStatePtr_t &session);
-
- std::string nameFromID(const LLUUID &id) const;
- bool IDFromName(const std::string name, LLUUID &uuid);
- std::string sipURIFromAvatar(LLVOAvatar *avatar);
- std::string sipURIFromName(std::string &name);
-
- // Returns the name portion of the SIP URI if the string looks vaguely like a SIP URI, or an empty string if not.
- std::string nameFromsipURI(const std::string &uri);
-
- bool inSpatialChannel(void);
- LLSD getAudioSessionChannelInfo();
- std::string getAudioSessionHandle();
-
- void sendPositionAndVolumeUpdate(void);
-
- void sendCaptureAndRenderDevices();
- void buildSetCaptureDevice(std::ostringstream &stream);
- void buildSetRenderDevice(std::ostringstream &stream);
-
-
- void sendFriendsListUpdates();
-
-#if 0
- // start a text IM session with the specified user
- // This will be asynchronous, the session may be established at a future time.
- sessionStatePtr_t startUserIMSession(const LLUUID& uuid);
-#endif
-
- void enforceTether(void);
-
- bool mSpatialCoordsDirty;
-
- LLVector3d mCameraPosition;
- LLVector3d mCameraRequestedPosition;
- LLVector3 mCameraVelocity;
- LLMatrix3 mCameraRot;
-
- LLVector3d mAvatarPosition;
- LLVector3 mAvatarVelocity;
- LLQuaternion mAvatarRot;
-
- bool mMuteMic;
- bool mMuteMicDirty;
- bool mHidden; //Set to true during teleport to hide the agent's position.
-
- // Set to true when the friends list is known to have changed.
- bool mFriendsListDirty;
-
- enum
- {
- earLocCamera = 0, // ear at camera
- earLocAvatar, // ear at avatar
- earLocMixed // ear at avatar location/camera direction
- };
-
- S32 mEarLocation;
-
- bool mSpeakerVolumeDirty;
- bool mSpeakerMuteDirty;
- int mSpeakerVolume;
-
- int mMicVolume;
- bool mMicVolumeDirty;
-
- bool mVoiceEnabled;
- bool mProcessChannels;
- bool mWriteInProgress;
- std::string mWriteString;
- size_t mWriteOffset;
-
- typedef std::set<LLVoiceClientParticipantObserver*> observer_set_t;
- observer_set_t mParticipantObservers;
-
- void notifyParticipantObservers();
-
- typedef std::set<LLVoiceClientStatusObserver*> status_observer_set_t;
- status_observer_set_t mStatusObservers;
-
- void notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status);
-
- typedef std::set<LLFriendObserver*> friend_observer_set_t;
- friend_observer_set_t mFriendObservers;
- void notifyFriendObservers();
-
- // Voice Fonts
-
- void expireVoiceFonts();
- void deleteVoiceFont(const LLUUID& id);
- void deleteAllVoiceFonts();
- void deleteVoiceFontTemplates();
-
- S32 getVoiceFontIndex(const LLUUID& id) const;
- S32 getVoiceFontTemplateIndex(const LLUUID& id) const;
-
- void accountGetSessionFontsSendMessage();
- void accountGetTemplateFontsSendMessage();
- void sessionSetVoiceFontSendMessage(const sessionStatePtr_t &session);
-
- void updateVoiceMorphingMenu();
- void notifyVoiceFontObservers();
-
- typedef enum e_voice_font_type
- {
- VOICE_FONT_TYPE_NONE = 0,
- VOICE_FONT_TYPE_ROOT = 1,
- VOICE_FONT_TYPE_USER = 2,
- VOICE_FONT_TYPE_UNKNOWN
- } EVoiceFontType;
-
- typedef enum e_voice_font_status
- {
- VOICE_FONT_STATUS_NONE = 0,
- VOICE_FONT_STATUS_FREE = 1,
- VOICE_FONT_STATUS_NOT_FREE = 2,
- VOICE_FONT_STATUS_UNKNOWN
- } EVoiceFontStatus;
-
- struct voiceFontEntry
- {
- voiceFontEntry(LLUUID& id);
- ~voiceFontEntry();
-
- LLUUID mID;
- S32 mFontIndex;
- std::string mName;
- LLDate mExpirationDate;
- S32 mFontType;
- S32 mFontStatus;
- bool mIsNew;
-
- LLFrameTimer mExpiryTimer;
- };
-
- bool mVoiceFontsReceived;
- bool mVoiceFontsNew;
- bool mVoiceFontListDirty;
- voice_effect_list_t mVoiceFontList;
- voice_effect_list_t mVoiceFontTemplateList;
-
- typedef std::map<const LLUUID, voiceFontEntry*> voice_font_map_t;
- voice_font_map_t mVoiceFontMap;
- voice_font_map_t mVoiceFontTemplateMap;
-
- typedef std::set<LLVoiceEffectObserver*> voice_font_observer_set_t;
- voice_font_observer_set_t mVoiceFontObservers;
-
- LLFrameTimer mVoiceFontExpiryTimer;
-
-
- // Audio capture buffer
-
- void captureBufferRecordStartSendMessage();
- void captureBufferRecordStopSendMessage();
- void captureBufferPlayStartSendMessage(const LLUUID& voice_font_id = LLUUID::null);
- void captureBufferPlayStopSendMessage();
-
- bool mCaptureBufferMode; // Disconnected from voice channels while using the capture buffer.
- bool mCaptureBufferRecording; // A voice sample is being captured.
- bool mCaptureBufferRecorded; // A voice sample is captured in the buffer ready to play.
- bool mCaptureBufferPlaying; // A voice sample is being played.
-
- LLTimer mCaptureTimer;
- LLUUID mPreviewVoiceFont;
- LLUUID mPreviewVoiceFontLast;
- S32 mPlayRequestCount;
- bool mIsInTuningMode;
- bool mIsInChannel;
- bool mIsJoiningSession;
- bool mIsWaitingForFonts;
- bool mIsLoggingIn;
- bool mIsLoggedIn;
- bool mIsProcessingChannels;
- bool mIsCoroutineActive;
-
- // This variables can last longer than vivox in coroutines so we need them as static
- static bool sShuttingDown;
- static bool sConnected;
- static LLPumpIO* sPump;
-
- LLEventMailDrop mVivoxPump;
-};
-
-
-/**
- * @class LLVivoxProtocolParser
- * @brief This class helps construct new LLIOPipe specializations
- * @see LLIOPipe
- *
- * THOROUGH_DESCRIPTION
- */
-class LLVivoxProtocolParser : public LLIOPipe
-{
- LOG_CLASS(LLVivoxProtocolParser);
-public:
- LLVivoxProtocolParser();
- virtual ~LLVivoxProtocolParser();
-
-protected:
- /* @name LLIOPipe virtual implementations
- */
- //@{
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
- std::string mInput;
-
- // Expat control members
- XML_Parser parser;
- int responseDepth;
- bool ignoringTags;
- bool isEvent;
- int ignoreDepth;
-
- // Members for processing responses. The values are transient and only valid within a call to processResponse().
- int returnCode;
- int statusCode;
- std::string statusString;
- std::string requestId;
- std::string actionString;
- std::string connectorHandle;
- std::string versionID;
- std::string mBuildID;
- std::string accountHandle;
- std::string sessionHandle;
- std::string sessionGroupHandle;
- std::string alias;
- std::string applicationString;
-
- // Members for processing events. The values are transient and only valid within a call to processResponse().
- std::string eventTypeString;
- int state;
- std::string uriString;
- bool isChannel;
- bool incoming;
- bool enabled;
- std::string nameString;
- std::string audioMediaString;
- std::string deviceString;
- std::string displayNameString;
- int participantType;
- bool isLocallyMuted;
- bool isModeratorMuted;
- bool isSpeaking;
- int volume;
- F32 energy;
- std::string messageHeader;
- std::string messageBody;
- std::string notificationType;
- bool hasText;
- bool hasAudio;
- bool hasVideo;
- bool terminated;
- std::string blockMask;
- std::string presenceOnly;
- std::string autoAcceptMask;
- std::string autoAddAsBuddy;
- int numberOfAliases;
- std::string subscriptionHandle;
- std::string subscriptionType;
- S32 id;
- std::string descriptionString;
- LLDate expirationDate;
- bool hasExpired;
- S32 fontType;
- S32 fontStatus;
- std::string mediaCompletionType;
-
- // Members for processing text between tags
- std::string textBuffer;
- bool accumulateText;
-
- void reset();
-
- void processResponse(std::string tag);
-
- static void XMLCALL ExpatStartTag(void *data, const char *el, const char **attr);
- static void XMLCALL ExpatEndTag(void *data, const char *el);
- static void XMLCALL ExpatCharHandler(void *data, const XML_Char *s, int len);
-
- void StartTag(const char *tag, const char **attr);
- void EndTag(const char *tag);
- void CharData(const char *buffer, int length);
- LLDate expiryTimeStampToLLDate(const std::string& vivox_ts);
-
-};
-
-class LLVivoxSecurity : public LLSingleton<LLVivoxSecurity>
-{
- LLSINGLETON(LLVivoxSecurity);
- virtual ~LLVivoxSecurity();
-
- public:
- std::string connectorHandle() { return mConnectorHandle; };
- std::string accountHandle() { return mAccountHandle; };
-
- private:
- std::string mConnectorHandle;
- std::string mAccountHandle;
-};
-
-class LLVoiceVivoxStats : public LLSingleton<LLVoiceVivoxStats>
-{
- LLSINGLETON(LLVoiceVivoxStats);
- LOG_CLASS(LLVoiceVivoxStats);
- virtual ~LLVoiceVivoxStats();
-
- private:
- F64SecondsImplicit mStartTime;
-
- U32 mConnectCycles;
-
- F64 mConnectTime;
- U32 mConnectAttempts;
-
- F64 mProvisionTime;
- U32 mProvisionAttempts;
-
- F64 mEstablishTime;
- U32 mEstablishAttempts;
-
- public:
-
- void reset();
- void connectionAttemptStart();
- void connectionAttemptEnd(bool success);
- void provisionAttemptStart();
- void provisionAttemptEnd(bool success);
- void establishAttemptStart();
- void establishAttemptEnd(bool success);
- LLSD read();
-};
-
-#endif //LL_VIVOX_VOICE_CLIENT_H
-
diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp
index 6d5a8eae6a..3b98ca49ef 100644
--- a/indra/newview/llvoicewebrtc.cpp
+++ b/indra/newview/llvoicewebrtc.cpp
@@ -61,10 +61,12 @@
#include "llrand.h"
#include "llviewerwindow.h"
#include "llviewercamera.h"
+#include "llviewerstats.h"
#include "llversioninfo.h"
#include "llviewernetwork.h"
#include "llnotificationsutil.h"
+#include "llnearbyvoicemoderation.h"
#include "llcorehttputil.h"
#include "lleventfilter.h"
@@ -80,6 +82,8 @@
const std::string WEBRTC_VOICE_SERVER_TYPE = "webrtc";
+const F32 STATS_TIMER_DELAY = 2.0;
+
namespace {
const F32 MAX_AUDIO_DIST = 50.0f;
@@ -2349,12 +2353,6 @@ void LLWebRTCVoiceClient::avatarNameResolved(const LLUUID &id, const std::string
sessionState::for_each(boost::bind(predAvatarNameResolution, _1, id, name));
}
-// Leftover from vivox PTSN
-std::string LLWebRTCVoiceClient::sipURIFromID(const LLUUID& id) const
-{
- return id.asString();
-}
-
LLSD LLWebRTCVoiceClient::getP2PChannelInfoTemplate(const LLUUID& id) const
{
return LLSD();
@@ -2969,6 +2967,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
}
mWebRTCAudioInterface->setReceiveVolume(mSpeakerVolume);
LLWebRTCVoiceClient::getInstance()->OnConnectionEstablished(mChannelID, mRegionID);
+ resetConnectionStats();
setVoiceConnectionState(VOICE_STATE_WAIT_FOR_DATA_CHANNEL);
break;
}
@@ -3022,6 +3021,13 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
sendJoin();
}
}
+
+ static LLTimer stats_timer;
+ if (stats_timer.getElapsedTimeF32() > STATS_TIMER_DELAY)
+ {
+ mWebRTCPeerConnectionInterface->gatherConnectionStats();
+ stats_timer.reset();
+ }
}
break;
}
@@ -3154,6 +3160,13 @@ void LLVoiceWebRTCConnection::OnDataReceivedImpl(const std::string &data, bool b
LL_WARNS("Voice") << "Expected object from data channel:" << data << LL_ENDL;
return;
}
+
+ bool is_primary_region = mPrimary;
+ if (!mPrimary && isSpatial() && gAgent.getRegion())
+ {
+ is_primary_region = (mRegionID == gAgent.getRegion()->getRegionID());
+ LL_WARNS() << "mPrimary is false, expected: " << is_primary_region << " connection state: " << getVoiceConnectionState() << LL_ENDL;
+ }
boost::json::object voice_data = voice_data_parsed.as_object();
boost::json::object mute;
boost::json::object user_gain;
@@ -3249,12 +3262,63 @@ void LLVoiceWebRTCConnection::OnDataReceivedImpl(const std::string &data, bool b
if (participant_obj.contains("m") && participant_obj["m"].is_bool())
{
- participant->mIsModeratorMuted = participant_obj["m"].as_bool();
+ bool is_moderator_muted = participant_obj["m"].as_bool();
+ if (isSpatial())
+ {
+ // ignore muted flags from non-primary server
+ if (is_primary_region || primary)
+ {
+ participant->mIsModeratorMuted = is_moderator_muted;
+ if (gAgentID == agent_id)
+ {
+ LLNearbyVoiceModeration::getInstance()->setMutedInfo(mChannelID, is_moderator_muted);
+ }
+ }
+ }
+ else
+ {
+ participant->mIsModeratorMuted = is_moderator_muted;
+ }
}
}
}
- }
+ else
+ {
+ if (isSpatial() && (is_primary_region || primary))
+ {
+ // mute info message can be received before join message, so try to mute again later
+ if (participant_obj.contains("m") && participant_obj["m"].is_bool())
+ {
+ LL_WARNS() << "Mute info msg received: " << participant_obj["m"].as_bool()
+ << " but participant " << agent_id
+ << " was not found in channel " << mChannelID << LL_ENDL;
+ bool is_moderator_muted = participant_obj["m"].as_bool();
+ std::string channel_id = mChannelID;
+ F32 delay { 1.5f };
+ doAfterInterval(
+ [channel_id, agent_id, is_moderator_muted]()
+ {
+ LLWebRTCVoiceClient::participantStatePtr_t participant =
+ LLWebRTCVoiceClient::getInstance()->findParticipantByID(channel_id, agent_id);
+ if (participant)
+ {
+ participant->mIsModeratorMuted = is_moderator_muted;
+ LL_WARNS() << "Participant " << agent_id << " is found after delay, is_muted: " << is_moderator_muted << LL_ENDL;
+ if (gAgentID == agent_id)
+ {
+ LLNearbyVoiceModeration::getInstance()->setMutedInfo(channel_id, is_moderator_muted);
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Participant " << agent_id << " is still not found in channel " << channel_id << LL_ENDL;
+ }
+ }, delay);
+ }
+ }
+ }
+ }
// tell the simulator to set the mute and volume data for this
// participant, if there are any updates.
boost::json::object root;
@@ -3326,6 +3390,112 @@ void LLVoiceWebRTCConnection::sendJoin()
mWebRTCDataInterface->sendData(json_data, false);
}
+void LLVoiceWebRTCConnection::OnStatsDelivered(const llwebrtc::LLWebRTCStatsMap& stats_data)
+{
+ LL::WorkQueue::postMaybe(mMainQueue, [=, this]
+ {
+ if (mShutDown)
+ {
+ return;
+ }
+ for (const auto& [stats_id, attributes] : stats_data)
+ {
+ if (attributes.contains("currentRoundTripTime"))
+ {
+ F32 rtt_seconds = 0.0f;
+ LLStringUtil::convertToF32(attributes.at("currentRoundTripTime"), rtt_seconds);
+ sample(LLStatViewer::WEBRTC_LATENCY, rtt_seconds * 1000.0f);
+ }
+ if (attributes.contains("availableOutgoingBitrate"))
+ {
+ F32 bitrate_bps = 0.0f;
+ LLStringUtil::convertToF32(attributes.at("availableOutgoingBitrate"), bitrate_bps);
+ sample(LLStatViewer::WEBRTC_UPLOAD_BANDWIDTH, bitrate_bps / 1000.0f);
+ }
+
+ // Stat type detection below is heuristic-based.
+ // It's relied on specific fields to distinguish outbound-rtp, remote-inbound-rtp, and inbound-rtp.
+ // This approach works with current WebRTC stats but may need updating later.
+
+ // Outbound RTP
+ if (attributes.contains("mediaSourceId"))
+ {
+ U32 out_packets_sent = 0;
+ LLStringUtil::convertToU32(attributes.at("packetsSent"), out_packets_sent);
+ sample(LLStatViewer::WEBRTC_PACKETS_OUT_SENT, out_packets_sent);
+ }
+ // Remote-Inbound RTP
+ else if (attributes.contains("localId"))
+ {
+ if (attributes.contains("packetsLost"))
+ {
+ U32 out_packets_lost = 0;
+ LLStringUtil::convertToU32(attributes.at("packetsLost"), out_packets_lost);
+ sample(LLStatViewer::WEBRTC_PACKETS_OUT_LOST, out_packets_lost);
+ }
+ if (attributes.contains("jitter"))
+ {
+ F32 jitter_seconds = 0.0f;
+ LLStringUtil::convertToF32(attributes.at("jitter"), jitter_seconds);
+ sample(LLStatViewer::WEBRTC_JITTER_OUT, jitter_seconds * 1000.0f);
+ }
+ }
+ // Inbound RTP
+ else if (attributes.contains("jitterBufferDelay"))
+ {
+ if (attributes.contains("packetsLost"))
+ {
+ U32 in_packets_lost = 0;
+ LLStringUtil::convertToU32(attributes.at("packetsLost"), in_packets_lost);
+ sample(LLStatViewer::WEBRTC_PACKETS_IN_LOST, in_packets_lost);
+ }
+ if (attributes.contains("packetsReceived"))
+ {
+ U32 in_packets_recv = 0;
+ LLStringUtil::convertToU32(attributes.at("packetsReceived"), in_packets_recv);
+ sample(LLStatViewer::WEBRTC_PACKETS_IN_RECEIVED, in_packets_recv);
+ }
+ if (attributes.contains("jitter"))
+ {
+ F32 jitter_seconds = 0.0f;
+ LLStringUtil::convertToF32(attributes.at("jitter"), jitter_seconds);
+ sample(LLStatViewer::WEBRTC_JITTER_IN, jitter_seconds * 1000.0f);
+ }
+ if (attributes.contains("jitterBufferDelay") && attributes.contains("jitterBufferEmittedCount"))
+ {
+ F32 total_delay_seconds = 0.0f;
+ F32 emitted_count_f = 0.0f;
+
+ // total delay in seconds
+ LLStringUtil::convertToF32(attributes.at("jitterBufferDelay"), total_delay_seconds);
+
+ // number of packets played out
+ LLStringUtil::convertToF32(attributes.at("jitterBufferEmittedCount"), emitted_count_f);
+ if (emitted_count_f > 0.0f)
+ {
+ F32 avg_delay_seconds = total_delay_seconds / emitted_count_f;
+ F32 avg_delay_ms = avg_delay_seconds * 1000.0f;
+ sample(LLStatViewer::WEBRTC_JITTER_BUFFER, avg_delay_seconds * 1000.0f);
+ }
+ }
+ }
+ }
+ });
+}
+
+void LLVoiceWebRTCConnection::resetConnectionStats()
+{
+ sample(LLStatViewer::WEBRTC_JITTER_BUFFER, 0);
+ sample(LLStatViewer::WEBRTC_JITTER_IN, 0);
+ sample(LLStatViewer::WEBRTC_JITTER_OUT, 0);
+ sample(LLStatViewer::WEBRTC_LATENCY, 0);
+ sample(LLStatViewer::WEBRTC_PACKETS_IN_LOST, 0);
+ sample(LLStatViewer::WEBRTC_PACKETS_IN_RECEIVED, 0);
+ sample(LLStatViewer::WEBRTC_PACKETS_OUT_SENT, 0);
+ sample(LLStatViewer::WEBRTC_PACKETS_OUT_LOST, 0);
+ sample(LLStatViewer::WEBRTC_UPLOAD_BANDWIDTH, 0);
+}
+
/////////////////////////////
// WebRTC Spatial Connection
diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h
index 8efbd1778f..818bce5bc3 100644
--- a/indra/newview/llvoicewebrtc.h
+++ b/indra/newview/llvoicewebrtc.h
@@ -87,7 +87,6 @@ public:
// Returns true if WebRTC has successfully logged in and is not in error state
bool isVoiceWorking() const override;
- std::string sipURIFromID(const LLUUID &id) const override;
LLSD getP2PChannelInfoTemplate(const LLUUID& id) const override;
void setHidden(bool hidden) override; // virtual
@@ -542,6 +541,8 @@ private:
static bool sShuttingDown;
LLEventMailDrop mWebRTCPump;
+
+ LLSD mLastWebRTCStats;
};
@@ -605,6 +606,8 @@ class LLVoiceWebRTCConnection :
//@{
void OnDataReceived(const std::string &data, bool binary) override;
void OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface) override;
+
+ void OnStatsDelivered(const llwebrtc::LLWebRTCStatsMap& stats_data) override;
//@}
void OnDataReceivedImpl(const std::string &data, bool binary);
@@ -642,6 +645,8 @@ class LLVoiceWebRTCConnection :
void OnVoiceConnectionRequestSuccess(const LLSD &body);
+ void resetConnectionStats();
+
protected:
typedef enum e_voice_connection_state
{
diff --git a/indra/newview/llwindowlistener.cpp b/indra/newview/llwindowlistener.cpp
index 6d234a9a34..38e49d0750 100644
--- a/indra/newview/llwindowlistener.cpp
+++ b/indra/newview/llwindowlistener.cpp
@@ -41,6 +41,8 @@
#include "llrootview.h"
#include "llsdutil.h"
#include "stringize.h"
+#include "llclipboard.h"
+#include "lleditmenuhandler.h"
#include <functional>
#include <typeinfo>
#include <map>
@@ -89,7 +91,8 @@ LLWindowListener::LLWindowListener(LLViewerWindow *window, const KeyboardGetter&
&LLWindowListener::getPaths,
LLSDMap("reply", LLSD()));
add("keyDown",
- keySomething + "keypress event.\n" + keyExplain + mask,
+ keySomething + "keypress event.\n" + keyExplain +
+ "The [\"char\"] parameter detects and handles non-ASCII characters seperately\n" + mask,
&LLWindowListener::keyDown);
add("keyUp",
keySomething + "key release event.\n" + keyExplain + mask,
@@ -107,6 +110,10 @@ LLWindowListener::LLWindowListener(LLViewerWindow *window, const KeyboardGetter&
"Given an integer number of [\"clicks\"], inject the requested mouse scroll event.\n"
"(positive clicks moves downward through typical content)",
&LLWindowListener::mouseScroll);
+ add("pasteText",
+ "Paste specified [\"text\"] into the current edit field\n"
+ "Optional [\"path\"] specifies target UI element (must be focusable).",
+ &LLWindowListener::pasteText);
}
template <typename MAPPED>
@@ -264,6 +271,20 @@ void LLWindowListener::keyDown(LLSD const & evt)
KEY key = getKEY(evt);
MASK mask = getMask(evt);
+ bool is_non_ascii = false;
+ llwchar uni_char = 0;
+
+ if (evt.has("char"))
+ {
+ LLWString wstr = utf8str_to_wstring(evt["char"].asString());
+ if (!wstr.empty())
+ {
+ uni_char = wstr[0];
+ // If the Unicode code point is outside ASCII range, use Unicode-only handling
+ is_non_ascii = (uni_char >= 0x80);
+ }
+ }
+
if (evt.has("path"))
{
std::string path(evt["path"]);
@@ -278,8 +299,17 @@ void LLWindowListener::keyDown(LLSD const & evt)
response.setResponse(target_view->getInfo());
gFocusMgr.setKeyboardFocus(target_view);
- gViewerInput.handleKey(key, mask, false);
- if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
+
+ if (is_non_ascii)
+ {
+ // For non-ASCII characters, only send the Unicode event
+ mWindow->handleUnicodeChar(uni_char, mask);
+ }
+ else
+ {
+ gViewerInput.handleKey(key, mask, false);
+ if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
+ }
}
else
{
@@ -290,8 +320,16 @@ void LLWindowListener::keyDown(LLSD const & evt)
}
else
{
- gViewerInput.handleKey(key, mask, false);
- if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
+ if (is_non_ascii)
+ {
+ // For non-ASCII characters, only send the Unicode event
+ mWindow->handleUnicodeChar(uni_char, mask);
+ }
+ else
+ {
+ gViewerInput.handleKey(key, mask, false);
+ if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
+ }
}
}
@@ -521,3 +559,60 @@ void LLWindowListener::mouseScroll(LLSD const & request)
mWindow->handleScrollWheel(NULL, clicks);
}
+
+void LLWindowListener::pasteText(LLSD const & evt)
+{
+ Response response(LLSD(), evt);
+
+ if (!evt.has("text"))
+ {
+ response.error(STRINGIZE(evt["op"].asString() << " request did not provide required \"text\" parameter"));
+ return;
+ }
+
+ std::string text_to_paste = evt["text"].asString();
+ if (evt.has("path"))
+ {
+ std::string path(evt["path"]);
+ LLView* target_view = LLUI::getInstance()->resolvePath(LLUI::getInstance()->getRootView(), path);
+ if (!target_view)
+ {
+ response.error(STRINGIZE(evt["op"].asString() << " request specified invalid \"path\": " << path));
+ return;
+ }
+ else if(!target_view->isAvailable())
+ {
+ response.error(STRINGIZE("Target view specified by \"path\": " << path << " is not visible"));
+ return;
+ }
+ else
+ {
+ // Focus the target view
+ gFocusMgr.setKeyboardFocus(target_view);
+ }
+ }
+
+ // Check if edit menu handler is available
+ if (!LLEditMenuHandler::gEditMenuHandler)
+ {
+ response.error(STRINGIZE(evt["op"].asString() << " request failed: no edit menu handler available"));
+ return;
+ }
+
+ // Save current clipboard contents
+ LLWString saved_clipboard;
+ LLClipboard::instance().pasteFromClipboard(saved_clipboard);
+
+ LLClipboard::instance().copyToClipboard(utf8str_to_wstring(text_to_paste), 0, static_cast<S32>(text_to_paste.size()));
+ LLEditMenuHandler::gEditMenuHandler->paste();
+
+ // Restore original clipboard contents if there were any
+ if (!saved_clipboard.empty())
+ {
+ LLClipboard::instance().copyToClipboard(saved_clipboard, 0, static_cast<S32>(saved_clipboard.size()));
+ }
+ else
+ {
+ LLClipboard::instance().reset();
+ }
+}
diff --git a/indra/newview/llwindowlistener.h b/indra/newview/llwindowlistener.h
index 9908a9c451..d3a16cfde9 100644
--- a/indra/newview/llwindowlistener.h
+++ b/indra/newview/llwindowlistener.h
@@ -47,6 +47,7 @@ public:
void mouseUp(LLSD const & evt);
void mouseMove(LLSD const & evt);
void mouseScroll(LLSD const & evt);
+ void pasteText(LLSD const & evt);
private:
LLViewerWindow * mWindow;
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index 2ad285eb1f..d627556a7c 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -4,13 +4,16 @@
<!-- Named Colors -->
<color
name="EmphasisColor"
- value="0.38 0.694 0.573 1" />
- <color
- name="EmphasisColor_13"
- value="0.38 0.694 0.573 0.13" />
+ value="0.3 0.82 1 1" />
<color
name="EmphasisColor_35"
- value="0.38 0.694 0.573 0.35" />
+ value="0.426 0.729 1.0 0.368" />
+ <color
+ name="SelectionColor"
+ value="0.706 0.851 1 1" />
+ <color
+ name="ScrollHoveredColor"
+ value="0.18 0.26 0.33 1" />
<color
name="BeaconColor"
value="0.749 0.298 0 1" />
@@ -53,6 +56,9 @@
<color
name="DkGray2"
value="0.169 0.169 0.169 1" />
+ <color
+ name="DkGrayLogin"
+ value="0.129 0.133 0.137 1" />
<color
name="MouseGray"
value="0.191 0.191 0.191 1" />
@@ -338,7 +344,7 @@
reference="EmphasisColor" />
<color
name="ConversationFriendColor"
- value="0.42 0.85 0.71 1" />
+ reference="EmphasisColor" />
<color
name="DefaultHighlightDark"
reference="White_10" />
@@ -359,7 +365,7 @@
reference="Black" />
<color
name="FilterTextColor"
- value="0.38 0.69 0.57 1" />
+ reference="EmphasisColor" />
<color
name="FloaterButtonImageColor"
reference="LtGray" />
@@ -377,7 +383,7 @@
reference="Black_50" />
<color
name="FocusColor"
- reference="EmphasisColor" />
+ value="0.7 0.7 0.7 1" />
<color
name="FolderViewLoadingMessageTextColor"
value="0.3344 0.5456 0.5159 1" />
@@ -595,7 +601,7 @@
reference="White" />
<color
name="NameTagFriend"
- value="0.447 0.784 0.663 1" />
+ reference="EmphasisColor" />
<color
name="NameTagLegacy"
reference="White" />
@@ -741,9 +747,6 @@
name="ScrollHighlightedColor"
reference="Unused?" />
<color
- name="ScrollHoveredColor"
- reference="EmphasisColor_13" />
- <color
name="ScrollSelectedBGColor"
reference="EmphasisColor_35" />
<color
@@ -762,6 +765,9 @@
name="SelectedOutfitTextColor"
reference="EmphasisColor" />
<color
+ name="WornOutfitTextColor"
+ value="0.54 0.73 0.87 1" />
+ <color
name="SearchableControlHighlightFontColor"
value="1 0 0 1" />
<color
@@ -792,6 +798,9 @@
name="SystemChatColor"
reference="LtGray" />
<color
+ name="SelectedBgReadOnlyColor"
+ value="0.15 0.21 0.27 1" />
+ <color
name="TextBgFocusColor"
reference="White" />
<color
@@ -863,18 +872,24 @@
name="ColorSwatchBorderColor"
value="0.45098 0.517647 0.607843 1"/>
<color
+ name="ColorSwatchBorderColorGray"
+ value="0.329 0.329 0.329 1"/>
+ <color
name="ChatTeleportSeparatorColor"
reference="Black" />
<color
name="ChatTimestampColor"
reference="White" />
<color
+ name="MenuBarStreamingBgColor"
+ reference="DkGray" />
+ <color
name="MenuBarBetaBgColor"
reference="DkBlue" />
- <color
- name="MenuBarProjectBgColor"
- reference="MdBlue" />
- <color
+ <color
+ name="MenuBarProjectBgColor"
+ reference="MdBlue" />
+ <color
name="MenuBarTestBgColor"
reference="DkRed" />
<color
@@ -984,7 +999,7 @@
value="1 0.14 0 1" />
<color
name="OutfitGalleryItemSelected"
- value="0.22 0.45 0.35 1" />
+ value="0.26 0.36 0.47 1"/>
<color
name="OutfitGalleryItemWorn"
value="0.33 0.58 0.47 1" />
@@ -995,6 +1010,9 @@
name="PanelGray"
value="0.27 0.27 0.27 1" />
<color
+ name="PanelDark"
+ value="0.078 0.078 0.078 1" />
+ <color
name="PerformanceMid"
value="1 0.8 0 1" />
<color
diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_Center.png b/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_Center.png
index ffc3c85ea2..2e84daaf6b 100644
--- a/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_Center.png
+++ b/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_Center.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_In.png b/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_In.png
index c8560c0869..1854cb87df 100644
--- a/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_In.png
+++ b/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_In.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_Center.png b/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_Center.png
index 2812d614e6..d009044ee1 100644
--- a/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_Center.png
+++ b/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_Center.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_In.png b/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_In.png
index ae2c57c207..a9415e9cc0 100644
--- a/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_In.png
+++ b/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_In.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Backward_On.png b/indra/newview/skins/default/textures/bottomtray/Movement_Backward_On.png
index 9f31d461b5..f22f6e23b6 100644
--- a/indra/newview/skins/default/textures/bottomtray/Movement_Backward_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Backward_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Down_On.png b/indra/newview/skins/default/textures/bottomtray/Movement_Down_On.png
index f7ed4c25fb..238d005bef 100644
--- a/indra/newview/skins/default/textures/bottomtray/Movement_Down_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Down_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Forward_On.png b/indra/newview/skins/default/textures/bottomtray/Movement_Forward_On.png
index d0a825a682..ad4a02ee27 100644
--- a/indra/newview/skins/default/textures/bottomtray/Movement_Forward_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Forward_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Left_On.png b/indra/newview/skins/default/textures/bottomtray/Movement_Left_On.png
index 2f81fb1588..1a134661eb 100644
--- a/indra/newview/skins/default/textures/bottomtray/Movement_Left_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Left_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Right_On.png b/indra/newview/skins/default/textures/bottomtray/Movement_Right_On.png
index 4f86e81a15..8c5bf3bc66 100644
--- a/indra/newview/skins/default/textures/bottomtray/Movement_Right_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Right_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_TurnLeft_On.png b/indra/newview/skins/default/textures/bottomtray/Movement_TurnLeft_On.png
index b211371e64..1eeab859e5 100644
--- a/indra/newview/skins/default/textures/bottomtray/Movement_TurnLeft_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_TurnLeft_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_TurnRight_On.png b/indra/newview/skins/default/textures/bottomtray/Movement_TurnRight_On.png
index e937c3f012..57762defe4 100644
--- a/indra/newview/skins/default/textures/bottomtray/Movement_TurnRight_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_TurnRight_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Movement_Up_On.png b/indra/newview/skins/default/textures/bottomtray/Movement_Up_On.png
index ed4902f3ee..512bd3b64e 100644
--- a/indra/newview/skins/default/textures/bottomtray/Movement_Up_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/Movement_Up_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl1.png b/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl1.png
index cd18ae310d..b1012e505e 100644
--- a/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl1.png
+++ b/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl1.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl2.png b/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl2.png
index b0ed6ee8eb..49cdadded7 100644
--- a/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl2.png
+++ b/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl2.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/bottomtray/VoicePTT_On.png b/indra/newview/skins/default/textures/bottomtray/VoicePTT_On.png
index be4881b64c..9afe58dcd1 100644
--- a/indra/newview/skins/default/textures/bottomtray/VoicePTT_On.png
+++ b/indra/newview/skins/default/textures/bottomtray/VoicePTT_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Cone_Selected.png b/indra/newview/skins/default/textures/build/Object_Cone_Selected.png
index d50dc69ffe..051c85d05d 100644
--- a/indra/newview/skins/default/textures/build/Object_Cone_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Cone_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Cube_Selected.png b/indra/newview/skins/default/textures/build/Object_Cube_Selected.png
index 3d6964530d..3560b36ec6 100644
--- a/indra/newview/skins/default/textures/build/Object_Cube_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Cube_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Cylinder_Selected.png b/indra/newview/skins/default/textures/build/Object_Cylinder_Selected.png
index 3ed0389961..8f752aaf4c 100644
--- a/indra/newview/skins/default/textures/build/Object_Cylinder_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Cylinder_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Grass_Selected.png b/indra/newview/skins/default/textures/build/Object_Grass_Selected.png
index 3ebd5ea7a1..90844abe94 100644
--- a/indra/newview/skins/default/textures/build/Object_Grass_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Grass_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Hemi_Cone_Selected.png b/indra/newview/skins/default/textures/build/Object_Hemi_Cone_Selected.png
index 3bdc4d1fd5..66e1c45567 100644
--- a/indra/newview/skins/default/textures/build/Object_Hemi_Cone_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Hemi_Cone_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Hemi_Cylinder_Selected.png b/indra/newview/skins/default/textures/build/Object_Hemi_Cylinder_Selected.png
index 0912442e29..48ae5969a1 100644
--- a/indra/newview/skins/default/textures/build/Object_Hemi_Cylinder_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Hemi_Cylinder_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Hemi_Sphere_Selected.png b/indra/newview/skins/default/textures/build/Object_Hemi_Sphere_Selected.png
index 33db4a2de8..eff8a231d6 100644
--- a/indra/newview/skins/default/textures/build/Object_Hemi_Sphere_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Hemi_Sphere_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Prism_Selected.png b/indra/newview/skins/default/textures/build/Object_Prism_Selected.png
index 9e80fe2b84..ab7921b97d 100644
--- a/indra/newview/skins/default/textures/build/Object_Prism_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Prism_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Pyramid_Selected.png b/indra/newview/skins/default/textures/build/Object_Pyramid_Selected.png
index d36bfa55d4..446951d992 100644
--- a/indra/newview/skins/default/textures/build/Object_Pyramid_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Pyramid_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Ring_Selected.png b/indra/newview/skins/default/textures/build/Object_Ring_Selected.png
index 962f6efb93..a23e6dba50 100644
--- a/indra/newview/skins/default/textures/build/Object_Ring_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Ring_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Sphere_Selected.png b/indra/newview/skins/default/textures/build/Object_Sphere_Selected.png
index 715d597144..daf39a658c 100644
--- a/indra/newview/skins/default/textures/build/Object_Sphere_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Sphere_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Tetrahedron_Selected.png b/indra/newview/skins/default/textures/build/Object_Tetrahedron_Selected.png
index b2ea680f23..28175f107e 100644
--- a/indra/newview/skins/default/textures/build/Object_Tetrahedron_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Tetrahedron_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Torus_Selected.png b/indra/newview/skins/default/textures/build/Object_Torus_Selected.png
index 1fc22686eb..049ca64f05 100644
--- a/indra/newview/skins/default/textures/build/Object_Torus_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Torus_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Tree_Selected.png b/indra/newview/skins/default/textures/build/Object_Tree_Selected.png
index 5bd87f8a2f..8b45d668aa 100644
--- a/indra/newview/skins/default/textures/build/Object_Tree_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Tree_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/build/Object_Tube_Selected.png b/indra/newview/skins/default/textures/build/Object_Tube_Selected.png
index a4c3f39e14..c94a984c41 100644
--- a/indra/newview/skins/default/textures/build/Object_Tube_Selected.png
+++ b/indra/newview/skins/default/textures/build/Object_Tube_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/containers/Accordion_Selected.png b/indra/newview/skins/default/textures/containers/Accordion_Selected.png
index 0616dea6a3..ab852007ab 100644
--- a/indra/newview/skins/default/textures/containers/Accordion_Selected.png
+++ b/indra/newview/skins/default/textures/containers/Accordion_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/containers/TabLeft_Flat_Off.png b/indra/newview/skins/default/textures/containers/TabLeft_Flat_Off.png
new file mode 100644
index 0000000000..d6c6bc41ec
--- /dev/null
+++ b/indra/newview/skins/default/textures/containers/TabLeft_Flat_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/containers/TabLeft_Flat_Selected.png b/indra/newview/skins/default/textures/containers/TabLeft_Flat_Selected.png
new file mode 100644
index 0000000000..cc310bbc26
--- /dev/null
+++ b/indra/newview/skins/default/textures/containers/TabLeft_Flat_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/containers/TabTop_First_Flat_Off.png b/indra/newview/skins/default/textures/containers/TabTop_First_Flat_Off.png
new file mode 100644
index 0000000000..177d341ba3
--- /dev/null
+++ b/indra/newview/skins/default/textures/containers/TabTop_First_Flat_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/containers/TabTop_First_Flat_Selected.png b/indra/newview/skins/default/textures/containers/TabTop_First_Flat_Selected.png
new file mode 100644
index 0000000000..54bd4d923d
--- /dev/null
+++ b/indra/newview/skins/default/textures/containers/TabTop_First_Flat_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/containers/TabTop_Last_Flat_Off.png b/indra/newview/skins/default/textures/containers/TabTop_Last_Flat_Off.png
new file mode 100644
index 0000000000..28a315665b
--- /dev/null
+++ b/indra/newview/skins/default/textures/containers/TabTop_Last_Flat_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/containers/TabTop_Last_Flat_Selected.png b/indra/newview/skins/default/textures/containers/TabTop_Last_Flat_Selected.png
new file mode 100644
index 0000000000..993e79b37f
--- /dev/null
+++ b/indra/newview/skins/default/textures/containers/TabTop_Last_Flat_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/containers/TabTop_Middle_Flat_Off.png b/indra/newview/skins/default/textures/containers/TabTop_Middle_Flat_Off.png
new file mode 100644
index 0000000000..1f5d926cc8
--- /dev/null
+++ b/indra/newview/skins/default/textures/containers/TabTop_Middle_Flat_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/containers/TabTop_Middle_Flat_Selected.png b/indra/newview/skins/default/textures/containers/TabTop_Middle_Flat_Selected.png
new file mode 100644
index 0000000000..e4e4d27d42
--- /dev/null
+++ b/indra/newview/skins/default/textures/containers/TabTop_Middle_Flat_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/containers/Toolbar_Middle_Selected.png b/indra/newview/skins/default/textures/containers/Toolbar_Middle_Selected.png
index 642113b135..62f82879cf 100644
--- a/indra/newview/skins/default/textures/containers/Toolbar_Middle_Selected.png
+++ b/indra/newview/skins/default/textures/containers/Toolbar_Middle_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Info_Over.png b/indra/newview/skins/default/textures/icons/Info_Over.png
index 0efd596d3e..1d00c2c175 100644
--- a/indra/newview/skins/default/textures/icons/Info_Over.png
+++ b/indra/newview/skins/default/textures/icons/Info_Over.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Inv_SysClosed.png b/indra/newview/skins/default/textures/icons/Inv_SysClosed.png
index 9af3b60cbd..19afa94cc4 100644
--- a/indra/newview/skins/default/textures/icons/Inv_SysClosed.png
+++ b/indra/newview/skins/default/textures/icons/Inv_SysClosed.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Inv_SysOpen.png b/indra/newview/skins/default/textures/icons/Inv_SysOpen.png
index 01e7dbff8f..7ca0f5a849 100644
--- a/indra/newview/skins/default/textures/icons/Inv_SysOpen.png
+++ b/indra/newview/skins/default/textures/icons/Inv_SysOpen.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/SL_Logo.png b/indra/newview/skins/default/textures/icons/SL_Logo.png
index 1eafc304f5..7b147df369 100644
--- a/indra/newview/skins/default/textures/icons/SL_Logo.png
+++ b/indra/newview/skins/default/textures/icons/SL_Logo.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/back_arrow_off.png b/indra/newview/skins/default/textures/icons/back_arrow_off.png
index ab82dfc0a7..0c96257470 100644
--- a/indra/newview/skins/default/textures/icons/back_arrow_off.png
+++ b/indra/newview/skins/default/textures/icons/back_arrow_off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/back_arrow_over.png b/indra/newview/skins/default/textures/icons/back_arrow_over.png
index ad8c1f8d2c..a7fac5ef99 100644
--- a/indra/newview/skins/default/textures/icons/back_arrow_over.png
+++ b/indra/newview/skins/default/textures/icons/back_arrow_over.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/back_arrow_press.png b/indra/newview/skins/default/textures/icons/back_arrow_press.png
index 8aecc3d876..0c96257470 100644
--- a/indra/newview/skins/default/textures/icons/back_arrow_press.png
+++ b/indra/newview/skins/default/textures/icons/back_arrow_press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/check_mark.png b/indra/newview/skins/default/textures/icons/check_mark.png
index 5431dd31c8..00ec32964d 100644
--- a/indra/newview/skins/default/textures/icons/check_mark.png
+++ b/indra/newview/skins/default/textures/icons/check_mark.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/hand.png b/indra/newview/skins/default/textures/icons/hand.png
index d8ef2e22fa..6effb7c77d 100644
--- a/indra/newview/skins/default/textures/icons/hand.png
+++ b/indra/newview/skins/default/textures/icons/hand.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/see_me_online.png b/indra/newview/skins/default/textures/icons/see_me_online.png
index 4059035b20..51d369003c 100644
--- a/indra/newview/skins/default/textures/icons/see_me_online.png
+++ b/indra/newview/skins/default/textures/icons/see_me_online.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/locked_image_dark.png b/indra/newview/skins/default/textures/locked_image_dark.png
new file mode 100644
index 0000000000..b952f2cfb0
--- /dev/null
+++ b/indra/newview/skins/default/textures/locked_image_dark.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/navbar/Favorite_Star_Active.png b/indra/newview/skins/default/textures/navbar/Favorite_Star_Active.png
index e27dbe2cad..cbb78cd514 100644
--- a/indra/newview/skins/default/textures/navbar/Favorite_Star_Active.png
+++ b/indra/newview/skins/default/textures/navbar/Favorite_Star_Active.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/navbar/Favorite_Star_Over.png b/indra/newview/skins/default/textures/navbar/Favorite_Star_Over.png
index 7909d54f2b..6b4092bf49 100644
--- a/indra/newview/skins/default/textures/navbar/Favorite_Star_Over.png
+++ b/indra/newview/skins/default/textures/navbar/Favorite_Star_Over.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/navbar/Row_Selection.png b/indra/newview/skins/default/textures/navbar/Row_Selection.png
index fc4f0c07ef..0eeb4f494c 100644
--- a/indra/newview/skins/default/textures/navbar/Row_Selection.png
+++ b/indra/newview/skins/default/textures/navbar/Row_Selection.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/square_selection.png b/indra/newview/skins/default/textures/square_selection.png
new file mode 100644
index 0000000000..9f344c4842
--- /dev/null
+++ b/indra/newview/skins/default/textures/square_selection.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index faf2bd9434..9a83176f26 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -124,7 +124,9 @@ with the same filename but different name
<texture name="Checkbox_Off_Disabled" file_name="widgets/Checkbox_Disabled.png" preload="true" />
<texture name="Checkbox_On_Disabled" file_name="widgets/Checkbox_On_Disabled.png" preload="true" />
<texture name="Checkbox_Off" file_name="widgets/Checkbox_Off.png" preload="true" />
+ <texture name="Checkbox_Slim_Off" file_name="widgets/Checkbox_Slim_Off.png" preload="true" />
<texture name="Checkbox_On" file_name="widgets/Checkbox_On.png" preload="true" />
+ <texture name="Checkbox_Slim_On" file_name="widgets/Checkbox_Slim_On.png" preload="true" />
<texture name="Checkbox_On_Press" file_name="widgets/Checkbox_On_Press.png" preload="true" />
<texture name="Checkbox_Press" file_name="widgets/Checkbox_Press.png" preload="true" />
<texture name="Check_Mark" file_name="icons/check_mark.png" preload="true" />
@@ -171,6 +173,8 @@ with the same filename but different name
<texture name="ComboButton_On" file_name="widgets/ComboButton_On.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="ComboButton_Off" file_name="widgets/ComboButton_Off.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="ComboButton_UpOff" file_name="widgets/ComboButton_UpOff.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
+ <texture name="ComboButton_Arrow" file_name="widgets/ComboButton_Arrow.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
+ <texture name="ComboButton_Transparent" file_name="widgets/ComboButton_Transparent.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="Container" file_name="containers/Container.png" preload="false" />
@@ -558,15 +562,16 @@ with the same filename but different name
<texture name="PushButton_On" file_name="widgets/PushButton_On.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
<texture name="PushButton_On_Selected" file_name="widgets/PushButton_On_Selected.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
<texture name="PushButton_Over" file_name="widgets/PushButton_Over.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
- <texture name="PushButton_Press" file_name="widgets/PushButton_Press.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
- <texture name="PushButton_Selected" file_name="widgets/PushButton_Selected.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
+ <texture name="PushButton_Selected" file_name="widgets/PushButton_Press.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
<texture name="PushButton_Selected_Press" file_name="widgets/PushButton_Selected_Press.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
<texture name="PushButton_Selected_Disabled" file_name="widgets/PushButton_Selected_Disabled.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
<texture name="PushButton_Login" file_name="widgets/PushButton_Login.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
<texture name="PushButton_Login_Over" file_name="widgets/PushButton_Login_Over.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
<texture name="PushButton_Login_Pressed" file_name="widgets/PushButton_Login_Pressed.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
-
+ <texture name="PushButton_Sign" file_name="widgets/PushButton_Sign.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
+ <texture name="PushButton_Sign_Over" file_name="widgets/PushButton_Sign_Over.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
+ <texture name="PushButton_Sign_Pressed" file_name="widgets/PushButton_Sign_Pressed.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
<texture name="RadioButton_Press" file_name="widgets/RadioButton_Press.png" preload="true" />
<texture name="RadioButton_On_Press" file_name="widgets/RadioButton_On_Press.png" preload="true" />
@@ -647,6 +652,8 @@ with the same filename but different name
<texture name="OBJECT_Icon" file_name="icons/object_icon.png" preload="true" />
<texture name="Unknown_Icon" file_name="icons/unknown_icon.png" preload="true" />
+ <texture name="Square_Selection" file_name="square_selection.png" preload="true" scale.left="16" scale.top="16" scale.right="112" scale.bottom="16" />
+
<texture name="Snapshot_Off" file_name="bottomtray/Snapshot_Off.png" preload="true" scale.left="4" scale.top="19" scale.right="22" scale.bottom="4" />
<texture name="Snapshot_Download" file_name="snapshot_download.png" preload="false" />
<texture name="Snapshot_Email" file_name="snapshot_email.png" preload="false" />
@@ -655,6 +662,7 @@ with the same filename but different name
<texture name="startup_logo" file_name="windows/startup_logo.png" preload="true" />
<texture name="login_sl_logo" file_name="windows/login_sl_logo.png" preload="true" />
+ <texture name="login_sl_logo_horizontal" file_name="windows/login_sl_logo_horizontal.png" preload="true" />
<texture name="login_sl_logo_small" file_name="windows/login_sl_logo_small.png" preload="true" />
<texture name="first_login_image" file_name="windows/first_login_image.jpg" preload="true" />
@@ -684,6 +692,15 @@ with the same filename but different name
<texture name="TabIcon_Places_Off" file_name="taskpanel/TabIcon_Places_Off.png" preload="false" />
<texture name="TabIcon_Things_Off" file_name="taskpanel/TabIcon_Things_Off.png" preload="false" />
+ <texture name="TabLeft_Flat_Off" file_name="containers/TabLeft_Flat_Off.png" preload="true" scale.left="4" scale.top="19" scale.right="22" scale.bottom="4" />
+ <texture name="TabLeft_Flat_Selected" file_name="containers/TabLeft_Flat_Selected.png" preload="true" scale.left="4" scale.top="19" scale.right="22" scale.bottom="4" />
+ <texture name="TabTop_First_Flat_Off" file_name="containers/TabTop_First_Flat_Off.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" />
+ <texture name="TabTop_Last_Flat_Off" file_name="containers/TabTop_Last_Flat_Off.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" />
+ <texture name="TabTop_Middle_Flat_Off" file_name="containers/TabTop_Middle_Flat_Off.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" />
+ <texture name="TabTop_First_Flat_Selected" file_name="containers/TabTop_First_Flat_Selected.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" />
+ <texture name="TabTop_Last_Flat_Selected" file_name="containers/TabTop_Last_Flat_Selected.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" />
+ <texture name="TabTop_Middle_Flat_Selected" file_name="containers/TabTop_Middle_Flat_Selected.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" />
+
<texture name="TabTop_Right_Off" file_name="containers/TabTop_Right_Off.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" />
<texture name="TabTop_Right_Selected" file_name="containers/TabTop_Right_Selected.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" />
<texture name="TabTop_Right_Flashing" file_name="containers/TabTop_Right_Flashing.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" />
@@ -701,7 +718,9 @@ with the same filename but different name
<texture name="TextField_Search_Off" file_name="widgets/TextField_Search_Off.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" />
<texture name="TextField_Disabled" file_name="widgets/TextField_Disabled.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" />
<texture name="TextField_Active" file_name="widgets/TextField_Active.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" />
+ <texture name="TextField_Highlight" file_name="widgets/TextField_Highlight.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" />
<texture name="TextField_Search_Highlight" file_name="widgets/TextField_Search_Highlight.png" preload="true" scale.left="9" scale.top="12" scale.right="248" scale.bottom="12" />
+ <texture name="TextField_Transparent" file_name="widgets/TextField_Transparent.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="Thumbnail_Fallback" file_name="icons/thumbnail_fallback_icon.png" preload="true" />
@@ -869,6 +888,7 @@ with the same filename but different name
<texture name="badge_warn.j2c" />
<texture name="badge_ok.j2c" />
<texture name="materials_ui_x_24.png" />
+ <texture name="locked_image" file_name="locked_image_dark.png" preload="true"/>
<texture name="Progress_1" file_name="icons/Progress_1.png" preload="true" />
<texture name="Progress_2" file_name="icons/Progress_2.png" preload="true" />
diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_Disabled.png b/indra/newview/skins/default/textures/widgets/Checkbox_Disabled.png
index 8439f82e29..383ff8f6e3 100644
--- a/indra/newview/skins/default/textures/widgets/Checkbox_Disabled.png
+++ b/indra/newview/skins/default/textures/widgets/Checkbox_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_Off.png b/indra/newview/skins/default/textures/widgets/Checkbox_Off.png
index cb9a04d84f..66f12496cb 100644
--- a/indra/newview/skins/default/textures/widgets/Checkbox_Off.png
+++ b/indra/newview/skins/default/textures/widgets/Checkbox_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_On.png b/indra/newview/skins/default/textures/widgets/Checkbox_On.png
index 0ec090504a..549bbde5cd 100644
--- a/indra/newview/skins/default/textures/widgets/Checkbox_On.png
+++ b/indra/newview/skins/default/textures/widgets/Checkbox_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_On_Disabled.png b/indra/newview/skins/default/textures/widgets/Checkbox_On_Disabled.png
index 5759f7de69..9c80670837 100644
--- a/indra/newview/skins/default/textures/widgets/Checkbox_On_Disabled.png
+++ b/indra/newview/skins/default/textures/widgets/Checkbox_On_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_On_Press.png b/indra/newview/skins/default/textures/widgets/Checkbox_On_Press.png
index ba46e91c55..903c61f01b 100644
--- a/indra/newview/skins/default/textures/widgets/Checkbox_On_Press.png
+++ b/indra/newview/skins/default/textures/widgets/Checkbox_On_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_Press.png b/indra/newview/skins/default/textures/widgets/Checkbox_Press.png
index 5f5a33d878..96dfd7267c 100644
--- a/indra/newview/skins/default/textures/widgets/Checkbox_Press.png
+++ b/indra/newview/skins/default/textures/widgets/Checkbox_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_Slim_Off.png b/indra/newview/skins/default/textures/widgets/Checkbox_Slim_Off.png
new file mode 100644
index 0000000000..99af0397d5
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/Checkbox_Slim_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_Slim_On.png b/indra/newview/skins/default/textures/widgets/Checkbox_Slim_On.png
new file mode 100644
index 0000000000..cabecf1467
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/Checkbox_Slim_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/ComboButton_Arrow.png b/indra/newview/skins/default/textures/widgets/ComboButton_Arrow.png
new file mode 100644
index 0000000000..7961967458
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/ComboButton_Arrow.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/ComboButton_Disabled.png b/indra/newview/skins/default/textures/widgets/ComboButton_Disabled.png
index ebeb813349..5b2bc7b163 100644
--- a/indra/newview/skins/default/textures/widgets/ComboButton_Disabled.png
+++ b/indra/newview/skins/default/textures/widgets/ComboButton_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/ComboButton_Off.png b/indra/newview/skins/default/textures/widgets/ComboButton_Off.png
index 4f573cf6fa..7199470307 100644
--- a/indra/newview/skins/default/textures/widgets/ComboButton_Off.png
+++ b/indra/newview/skins/default/textures/widgets/ComboButton_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/ComboButton_Selected.png b/indra/newview/skins/default/textures/widgets/ComboButton_Selected.png
index 1a834bfbbc..715b401ce5 100644
--- a/indra/newview/skins/default/textures/widgets/ComboButton_Selected.png
+++ b/indra/newview/skins/default/textures/widgets/ComboButton_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/ComboButton_Transparent.png b/indra/newview/skins/default/textures/widgets/ComboButton_Transparent.png
new file mode 100644
index 0000000000..4b978877e1
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/ComboButton_Transparent.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/ComboButton_UpOff.png b/indra/newview/skins/default/textures/widgets/ComboButton_UpOff.png
index 5a067aca7c..9e74524be4 100644
--- a/indra/newview/skins/default/textures/widgets/ComboButton_UpOff.png
+++ b/indra/newview/skins/default/textures/widgets/ComboButton_UpOff.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/ComboButton_UpSelected.png b/indra/newview/skins/default/textures/widgets/ComboButton_UpSelected.png
index ff56367147..aa8865c33d 100644
--- a/indra/newview/skins/default/textures/widgets/ComboButton_UpSelected.png
+++ b/indra/newview/skins/default/textures/widgets/ComboButton_UpSelected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/DropDown_Disabled.png b/indra/newview/skins/default/textures/widgets/DropDown_Disabled.png
index 9a69f7e0d9..fff0cfaff2 100644
--- a/indra/newview/skins/default/textures/widgets/DropDown_Disabled.png
+++ b/indra/newview/skins/default/textures/widgets/DropDown_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/DropDown_Off.png b/indra/newview/skins/default/textures/widgets/DropDown_Off.png
index b118e7a7d4..9f6a2313b9 100644
--- a/indra/newview/skins/default/textures/widgets/DropDown_Off.png
+++ b/indra/newview/skins/default/textures/widgets/DropDown_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/DropDown_On.png b/indra/newview/skins/default/textures/widgets/DropDown_On.png
index 613a8c2ff6..a498465940 100644
--- a/indra/newview/skins/default/textures/widgets/DropDown_On.png
+++ b/indra/newview/skins/default/textures/widgets/DropDown_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/DropDown_Press.png b/indra/newview/skins/default/textures/widgets/DropDown_Press.png
index fa3a152df1..b6bf4d1c22 100644
--- a/indra/newview/skins/default/textures/widgets/DropDown_Press.png
+++ b/indra/newview/skins/default/textures/widgets/DropDown_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/ListItem_Over.png b/indra/newview/skins/default/textures/widgets/ListItem_Over.png
index e72c1c4020..9316567e7b 100644
--- a/indra/newview/skins/default/textures/widgets/ListItem_Over.png
+++ b/indra/newview/skins/default/textures/widgets/ListItem_Over.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/ListItem_Select.png b/indra/newview/skins/default/textures/widgets/ListItem_Select.png
index 0e16a8b454..cd65d347d6 100644
--- a/indra/newview/skins/default/textures/widgets/ListItem_Select.png
+++ b/indra/newview/skins/default/textures/widgets/ListItem_Select.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/MarketplaceBtn_Off.png b/indra/newview/skins/default/textures/widgets/MarketplaceBtn_Off.png
index de71f763d3..b2767c6174 100644
--- a/indra/newview/skins/default/textures/widgets/MarketplaceBtn_Off.png
+++ b/indra/newview/skins/default/textures/widgets/MarketplaceBtn_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/MarketplaceBtn_Selected.png b/indra/newview/skins/default/textures/widgets/MarketplaceBtn_Selected.png
index 8bfa3acb42..de50b29f79 100644
--- a/indra/newview/skins/default/textures/widgets/MarketplaceBtn_Selected.png
+++ b/indra/newview/skins/default/textures/widgets/MarketplaceBtn_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Disabled.png b/indra/newview/skins/default/textures/widgets/PushButton_Disabled.png
index e99ec4b14b..64a9a2d885 100644
--- a/indra/newview/skins/default/textures/widgets/PushButton_Disabled.png
+++ b/indra/newview/skins/default/textures/widgets/PushButton_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Login.png b/indra/newview/skins/default/textures/widgets/PushButton_Login.png
index 8e7d932ab1..7e892d2b0a 100644
--- a/indra/newview/skins/default/textures/widgets/PushButton_Login.png
+++ b/indra/newview/skins/default/textures/widgets/PushButton_Login.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Login_Over.png b/indra/newview/skins/default/textures/widgets/PushButton_Login_Over.png
index 038ba23be2..9110889d6c 100644
--- a/indra/newview/skins/default/textures/widgets/PushButton_Login_Over.png
+++ b/indra/newview/skins/default/textures/widgets/PushButton_Login_Over.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Login_Pressed.png b/indra/newview/skins/default/textures/widgets/PushButton_Login_Pressed.png
index 828aa1a139..bf38c2cd75 100644
--- a/indra/newview/skins/default/textures/widgets/PushButton_Login_Pressed.png
+++ b/indra/newview/skins/default/textures/widgets/PushButton_Login_Pressed.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Off.png b/indra/newview/skins/default/textures/widgets/PushButton_Off.png
index 29eeed7c78..113c371a4d 100644
--- a/indra/newview/skins/default/textures/widgets/PushButton_Off.png
+++ b/indra/newview/skins/default/textures/widgets/PushButton_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/PushButton_On.png b/indra/newview/skins/default/textures/widgets/PushButton_On.png
index 65d92a9d82..db70f75dd6 100644
--- a/indra/newview/skins/default/textures/widgets/PushButton_On.png
+++ b/indra/newview/skins/default/textures/widgets/PushButton_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Over.png b/indra/newview/skins/default/textures/widgets/PushButton_Over.png
index 819f27c0ba..67dfa0ca75 100644
--- a/indra/newview/skins/default/textures/widgets/PushButton_Over.png
+++ b/indra/newview/skins/default/textures/widgets/PushButton_Over.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Press.png b/indra/newview/skins/default/textures/widgets/PushButton_Press.png
index b0a92d8ffe..8dfa9030b1 100644
--- a/indra/newview/skins/default/textures/widgets/PushButton_Press.png
+++ b/indra/newview/skins/default/textures/widgets/PushButton_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Selected_Press.png b/indra/newview/skins/default/textures/widgets/PushButton_Selected_Press.png
index 8588576fb0..062fcf9246 100644
--- a/indra/newview/skins/default/textures/widgets/PushButton_Selected_Press.png
+++ b/indra/newview/skins/default/textures/widgets/PushButton_Selected_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Sign.png b/indra/newview/skins/default/textures/widgets/PushButton_Sign.png
new file mode 100644
index 0000000000..f1c27f8c9b
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/PushButton_Sign.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Sign_Over.png b/indra/newview/skins/default/textures/widgets/PushButton_Sign_Over.png
new file mode 100644
index 0000000000..efef8bebad
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/PushButton_Sign_Over.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Sign_Pressed.png b/indra/newview/skins/default/textures/widgets/PushButton_Sign_Pressed.png
new file mode 100644
index 0000000000..ec3409e8b8
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/PushButton_Sign_Pressed.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_Disabled.png b/indra/newview/skins/default/textures/widgets/RadioButton_Disabled.png
index 32ec25fe0e..fb98907be2 100644
--- a/indra/newview/skins/default/textures/widgets/RadioButton_Disabled.png
+++ b/indra/newview/skins/default/textures/widgets/RadioButton_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_Off.png b/indra/newview/skins/default/textures/widgets/RadioButton_Off.png
index 5d267af5dc..231aead651 100644
--- a/indra/newview/skins/default/textures/widgets/RadioButton_Off.png
+++ b/indra/newview/skins/default/textures/widgets/RadioButton_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_On.png b/indra/newview/skins/default/textures/widgets/RadioButton_On.png
index e6bf0db157..066872ff82 100644
--- a/indra/newview/skins/default/textures/widgets/RadioButton_On.png
+++ b/indra/newview/skins/default/textures/widgets/RadioButton_On.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_On_Disabled.png b/indra/newview/skins/default/textures/widgets/RadioButton_On_Disabled.png
index 72aae43618..43af5bec2f 100644
--- a/indra/newview/skins/default/textures/widgets/RadioButton_On_Disabled.png
+++ b/indra/newview/skins/default/textures/widgets/RadioButton_On_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_On_Press.png b/indra/newview/skins/default/textures/widgets/RadioButton_On_Press.png
index f3883b82b3..6870a48129 100644
--- a/indra/newview/skins/default/textures/widgets/RadioButton_On_Press.png
+++ b/indra/newview/skins/default/textures/widgets/RadioButton_On_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_Press.png b/indra/newview/skins/default/textures/widgets/RadioButton_Press.png
index 0025256045..0fb0054bfb 100644
--- a/indra/newview/skins/default/textures/widgets/RadioButton_Press.png
+++ b/indra/newview/skins/default/textures/widgets/RadioButton_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/ScrollThumb_Horiz.png b/indra/newview/skins/default/textures/widgets/ScrollThumb_Horiz.png
index 9afc907c1c..eb9563e0ee 100644
--- a/indra/newview/skins/default/textures/widgets/ScrollThumb_Horiz.png
+++ b/indra/newview/skins/default/textures/widgets/ScrollThumb_Horiz.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/ScrollThumb_Vert.png b/indra/newview/skins/default/textures/widgets/ScrollThumb_Vert.png
index ede643e528..144a7cba25 100644
--- a/indra/newview/skins/default/textures/widgets/ScrollThumb_Vert.png
+++ b/indra/newview/skins/default/textures/widgets/ScrollThumb_Vert.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Disabled.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Disabled.png
index d9f05d33ec..8ad008ba51 100644
--- a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Disabled.png
+++ b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected.png
index d2342f6538..ca5f84a088 100644
--- a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected.png
+++ b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Disabled.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Disabled.png
index 6223ad8dfe..9b1531a11e 100644
--- a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Disabled.png
+++ b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Press.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Press.png
index 101d5a0930..28f5bf37f7 100644
--- a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Press.png
+++ b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/SliderThumb_Disabled.png b/indra/newview/skins/default/textures/widgets/SliderThumb_Disabled.png
index 5cfa3ae4e1..fb98907be2 100644
--- a/indra/newview/skins/default/textures/widgets/SliderThumb_Disabled.png
+++ b/indra/newview/skins/default/textures/widgets/SliderThumb_Disabled.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/SliderThumb_Off.png b/indra/newview/skins/default/textures/widgets/SliderThumb_Off.png
index 66cdcbeb94..231aead651 100644
--- a/indra/newview/skins/default/textures/widgets/SliderThumb_Off.png
+++ b/indra/newview/skins/default/textures/widgets/SliderThumb_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/SliderThumb_Press.png b/indra/newview/skins/default/textures/widgets/SliderThumb_Press.png
index 0bf8e43e81..0fb0054bfb 100644
--- a/indra/newview/skins/default/textures/widgets/SliderThumb_Press.png
+++ b/indra/newview/skins/default/textures/widgets/SliderThumb_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/SliderTrack_Horiz.png b/indra/newview/skins/default/textures/widgets/SliderTrack_Horiz.png
index 720830f83f..65cfaf4c62 100644
--- a/indra/newview/skins/default/textures/widgets/SliderTrack_Horiz.png
+++ b/indra/newview/skins/default/textures/widgets/SliderTrack_Horiz.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/Stepper_Down_Off.png b/indra/newview/skins/default/textures/widgets/Stepper_Down_Off.png
index 51d269bd45..720946aba6 100644
--- a/indra/newview/skins/default/textures/widgets/Stepper_Down_Off.png
+++ b/indra/newview/skins/default/textures/widgets/Stepper_Down_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/Stepper_Down_Press.png b/indra/newview/skins/default/textures/widgets/Stepper_Down_Press.png
index b4f19b7dbb..505fa6c82c 100644
--- a/indra/newview/skins/default/textures/widgets/Stepper_Down_Press.png
+++ b/indra/newview/skins/default/textures/widgets/Stepper_Down_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/Stepper_Up_Off.png b/indra/newview/skins/default/textures/widgets/Stepper_Up_Off.png
index a01d928aef..9482e4773e 100644
--- a/indra/newview/skins/default/textures/widgets/Stepper_Up_Off.png
+++ b/indra/newview/skins/default/textures/widgets/Stepper_Up_Off.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/Stepper_Up_Press.png b/indra/newview/skins/default/textures/widgets/Stepper_Up_Press.png
index d5b672d943..ca311768c4 100644
--- a/indra/newview/skins/default/textures/widgets/Stepper_Up_Press.png
+++ b/indra/newview/skins/default/textures/widgets/Stepper_Up_Press.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/TextField_Highlight.png b/indra/newview/skins/default/textures/widgets/TextField_Highlight.png
new file mode 100644
index 0000000000..71c2a5dbc3
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/TextField_Highlight.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/TextField_Transparent.png b/indra/newview/skins/default/textures/widgets/TextField_Transparent.png
new file mode 100644
index 0000000000..1735184387
--- /dev/null
+++ b/indra/newview/skins/default/textures/widgets/TextField_Transparent.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/track_control_moon_back.png b/indra/newview/skins/default/textures/widgets/track_control_moon_back.png
index 03d1e805e1..1e2ce7bc83 100644
--- a/indra/newview/skins/default/textures/widgets/track_control_moon_back.png
+++ b/indra/newview/skins/default/textures/widgets/track_control_moon_back.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/track_control_moon_front.png b/indra/newview/skins/default/textures/widgets/track_control_moon_front.png
index cdc52fe08a..25f2914ecc 100644
--- a/indra/newview/skins/default/textures/widgets/track_control_moon_front.png
+++ b/indra/newview/skins/default/textures/widgets/track_control_moon_front.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/track_control_sphere.png b/indra/newview/skins/default/textures/widgets/track_control_sphere.png
index 60a81d1fea..adfb51edd2 100644
--- a/indra/newview/skins/default/textures/widgets/track_control_sphere.png
+++ b/indra/newview/skins/default/textures/widgets/track_control_sphere.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/widgets/track_control_sun_back.png b/indra/newview/skins/default/textures/widgets/track_control_sun_back.png
index b3191ccc5d..98bae90332 100644
--- a/indra/newview/skins/default/textures/widgets/track_control_sun_back.png
+++ b/indra/newview/skins/default/textures/widgets/track_control_sun_back.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/windows/Inspector_I.png b/indra/newview/skins/default/textures/windows/Inspector_I.png
index 843f6e9fbe..d51cf43051 100644
--- a/indra/newview/skins/default/textures/windows/Inspector_I.png
+++ b/indra/newview/skins/default/textures/windows/Inspector_I.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/windows/Window_Background.png b/indra/newview/skins/default/textures/windows/Window_Background.png
index 9864ec0db8..83a09584c1 100644
--- a/indra/newview/skins/default/textures/windows/Window_Background.png
+++ b/indra/newview/skins/default/textures/windows/Window_Background.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/windows/Window_Foreground.png b/indra/newview/skins/default/textures/windows/Window_Foreground.png
index a86b236504..1f4f9040bc 100644
--- a/indra/newview/skins/default/textures/windows/Window_Foreground.png
+++ b/indra/newview/skins/default/textures/windows/Window_Foreground.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/windows/login_sl_logo_horizontal.png b/indra/newview/skins/default/textures/windows/login_sl_logo_horizontal.png
new file mode 100644
index 0000000000..f56d0bd542
--- /dev/null
+++ b/indra/newview/skins/default/textures/windows/login_sl_logo_horizontal.png
Binary files differ
diff --git a/indra/newview/skins/default/xui/da/floater_joystick.xml b/indra/newview/skins/default/xui/da/floater_joystick.xml
index 49e1397e9f..c756bc6969 100644
--- a/indra/newview/skins/default/xui/da/floater_joystick.xml
+++ b/indra/newview/skins/default/xui/da/floater_joystick.xml
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="Joystick" title="JOYSTICK OPSÆTNING">
<check_box label="Aktiver Joystick:" name="enable_joystick"/>
- <spinner label="X akse mapping" name="JoystickAxis1"/>
- <spinner label="Y akse mapping" name="JoystickAxis2"/>
- <spinner label="Z akse mapping" name="JoystickAxis0"/>
- <spinner label="Hældning mapping" name="JoystickAxis4"/>
- <spinner label="Drejning mapping" name="JoystickAxis5"/>
- <spinner label="Rulning mapping" name="JoystickAxis3"/>
- <spinner label="Zoom mapping" name="JoystickAxis6"/>
+ <spinner label="X akse mapping" name="JoystickAxis1" label_width="115" width="155"/>
+ <spinner label="Y akse mapping" name="JoystickAxis2" label_width="115" width="155"/>
+ <spinner label="Z akse mapping" name="JoystickAxis0" label_width="115" width="155"/>
+ <spinner label="Hældning mapping" name="JoystickAxis4" label_width="115" width="155"/>
+ <spinner label="Drejning mapping" name="JoystickAxis5" label_width="115" width="155"/>
+ <spinner label="Rulning mapping" name="JoystickAxis3" label_width="115" width="155"/>
+ <spinner label="Zoom mapping" name="JoystickAxis6" label_width="115" width="155"/>
<check_box label="Direkte zoom" name="ZoomDirect"/>
<check_box label="3D Cursor" name="Cursor3D"/>
<check_box label="Auto opret" name="AutoLeveling"/>
diff --git a/indra/newview/skins/default/xui/da/floater_whitelist_entry.xml b/indra/newview/skins/default/xui/da/floater_whitelist_entry.xml
index 443e84b64a..e05be4e310 100644
--- a/indra/newview/skins/default/xui/da/floater_whitelist_entry.xml
+++ b/indra/newview/skins/default/xui/da/floater_whitelist_entry.xml
@@ -3,7 +3,7 @@
<text name="media_label">
Indtast en URL eller et URL mønster for at tilføje til listen med godkendte domæner
</text>
- <line_editor name="whitelist_entry" tool_tip="Indtast en URL eller et URL mønster for at godkende side(r)"/>
+ <line_editor name="whitelist_entry" tool_tip="Indtast en URL eller et URL mønster for at godkende side(r)" bottom_delta="25"/>
<button label="OK" name="ok_btn"/>
<button label="Annullér" name="cancel_btn"/>
</floater>
diff --git a/indra/newview/skins/default/xui/da/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/da/panel_preferences_alerts.xml
index 7caa17d514..fa245416cf 100644
--- a/indra/newview/skins/default/xui/da/panel_preferences_alerts.xml
+++ b/indra/newview/skins/default/xui/da/panel_preferences_alerts.xml
@@ -4,6 +4,7 @@
Vis mig når:
</text>
<check_box label="Når jeg bruger eller får L$" name="notify_money_change_checkbox"/>
+ <check_box name="notify_money_spend_checkbox" left_delta="70"/>
<check_box label="Når mine venner logger på eller af" name="friends_online_notify_checkbox"/>
<text name="show_label">
Vis altid:
diff --git a/indra/newview/skins/default/xui/da/panel_preferences_sound.xml b/indra/newview/skins/default/xui/da/panel_preferences_sound.xml
index 26d2ae4abd..acae39061b 100644
--- a/indra/newview/skins/default/xui/da/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/da/panel_preferences_sound.xml
@@ -30,7 +30,7 @@
<radio_item label="Avatar position" name="1"/>
</radio_group>
<check_box label="Bevæg avatar-læber når der snakkes" name="enable_lip_sync"/>
- <check_box label="Skift tale tænd/sluk når jeg trykker:" name="push_to_talk_toggle_check" tool_tip="Når du er i skift-modus, vil hvert tryk tænde eller slukke din mikrofon. Når du ikke er i skift-modus, vil din mikrofon kun være tændt når knappen/tasten holdes nede (som en Walkie Talkie)"/>
+ <check_box label="Skift tale tænd/sluk når jeg trykker" name="push_to_talk_toggle_check" tool_tip="Når du er i skift-modus, vil hvert tryk tænde eller slukke din mikrofon. Når du ikke er i skift-modus, vil din mikrofon kun være tændt når knappen/tasten holdes nede (som en Walkie Talkie)"/>
<line_editor label="Tryk-for-tale udløser" name="modifier_combo"/>
<button label="Angiv taste" name="set_voice_hotkey_button"/>
<button name="set_voice_middlemouse_button" tool_tip="Nulstil til midterste muse-knap"/>
diff --git a/indra/newview/skins/default/xui/de/panel_login_first.xml b/indra/newview/skins/default/xui/de/panel_login_first.xml
deleted file mode 100644
index 038001157e..0000000000
--- a/indra/newview/skins/default/xui/de/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php?lang=de
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Benutzername" name="username_combo" tool_tip="Bei der Registrierung gewählter Benutzername wie „berndschmidt12“ oder „Liebe Sonne“"/>
- <line_editor label="Kennwort" name="password_edit"/>
- <button label="Anmelden" name="connect_btn"/>
- <check_box label="Details speichern" name="remember_check"/>
- <text name="forgot_password_text">
- Kennwort vergessen
- </text>
- <text name="sign_up_text">
- Registrieren
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Ihr erster Schritt ist Learning Island. Suchen Sie die Pforte!
- </text>
- <text name="image_caption_right">
- Erkunden Sie dann Social Island und lernen Sie andere Einwohner kennen!
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml
index c5b42b6dae..ffb9c0f78e 100644
--- a/indra/newview/skins/default/xui/en/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_about_land.xml
@@ -974,7 +974,7 @@
layout="topleft"
left="28"
name="Set to group:"
- top_pad="5"
+ top_pad="9"
width="176">
Set to group:
</text>
@@ -1022,7 +1022,7 @@
layout="topleft"
left="28"
name="Owned by others:"
- top_pad="5"
+ top_pad="9"
width="176">
Owned by others:
</text>
@@ -1593,7 +1593,7 @@ Only large parcels can be listed in search.
left="10"
name="with media:"
top="10"
- width="100">
+ width="110">
Type:
</text>
<combo_box
@@ -1620,7 +1620,7 @@ Only large parcels can be listed in search.
layout="topleft"
left="10"
name="at URL:"
- width="100"
+ width="110"
top_pad="10">
Home Page:
</text>
@@ -1632,7 +1632,7 @@ Only large parcels can be listed in search.
max_length_bytes="255"
name="media_url"
select_on_focus="true"
- width="300"
+ width="290"
top_delta="0"/>
<button
follows="left|top"
@@ -1659,13 +1659,13 @@ Only large parcels can be listed in search.
follows="left|top"
height="20"
layout="topleft"
- left="110"
+ left="120"
max_length_bytes="255"
name="url_description"
select_on_focus="true"
tool_tip="Text displayed next to play/load button"
top_delta="0"
- width="300" />
+ width="290" />
<text
type="string"
length="1"
@@ -1685,7 +1685,7 @@ Only large parcels can be listed in search.
follows="left|top"
height="80"
layout="topleft"
- left="110"
+ left="120"
name="media texture"
tool_tip="Click to choose a picture"
top_delta="0"
@@ -1698,7 +1698,7 @@ Only large parcels can be listed in search.
layout="topleft"
left_pad="8"
name="replace_texture_help"
- width="300"
+ width="290"
word_wrap="true"
top_delta="0">
Objects using this texture will show the movie or web page after you click the play arrow. Select the thumbnail to choose a different texture.
@@ -1707,7 +1707,7 @@ Only large parcels can be listed in search.
height="16"
label="Auto scale"
layout="topleft"
- left="107"
+ left="117"
name="media_auto_scale"
top_pad="-10"
tool_tip="Checking this option will scale the content for this parcel automatically. It may be slightly slower and lower quality visually but no other texture scaling or alignment will be required."
@@ -1721,7 +1721,7 @@ Only large parcels can be listed in search.
left="10"
name="media_size"
tool_tip="Size to render Web media, leave 0 for default."
- width="100"
+ width="110"
top_pad="10">
Size:
</text>
@@ -1776,7 +1776,7 @@ Only large parcels can be listed in search.
left="10"
name="Options:"
top_pad="10"
- width="100">
+ width="110">
Options:
</text>
<check_box
@@ -1786,7 +1786,7 @@ Only large parcels can be listed in search.
left_pad="-3"
name="media_loop"
tool_tip="Play media in a loop. When the media has finished playing, it will restart from the beginning."
- top_delta="-1"
+ top_delta="1"
width="200" />
</panel>
<panel
diff --git a/indra/newview/skins/default/xui/en/floater_add_payment_method.xml b/indra/newview/skins/default/xui/en/floater_add_payment_method.xml
index 870ddee554..308f4feb5a 100644
--- a/indra/newview/skins/default/xui/en/floater_add_payment_method.xml
+++ b/indra/newview/skins/default/xui/en/floater_add_payment_method.xml
@@ -50,7 +50,6 @@
follows="top|left|right"
height="24"
label="Get started"
- font="SansSerifMedium"
layout="topleft"
left="320"
name="continue_btn"
@@ -59,6 +58,7 @@
image_hover_unselected="PushButton_Login_Over"
label_color="White"
top_pad ="15"
+ pad_bottom="1"
width="140"/>
<button
follows="top|left|right"
@@ -66,6 +66,7 @@
label="Later"
layout="topleft"
left_pad="9"
+ pad_bottom="1"
name="close_btn"
width="90"/>
<icon
@@ -97,7 +98,6 @@
type="string"
length="1"
follows="top|left"
- font="SansSerifMedium"
text_color="White"
height="75"
width="260"
@@ -112,7 +112,6 @@
type="string"
length="1"
follows="top|left"
- font="SansSerifMedium"
text_color="White"
height="75"
width="260"
@@ -126,7 +125,6 @@
type="string"
length="1"
follows="top|left"
- font="SansSerifMedium"
text_color="White"
height="75"
width="260"
diff --git a/indra/newview/skins/default/xui/en/floater_adjust_environment.xml b/indra/newview/skins/default/xui/en/floater_adjust_environment.xml
index 889eeb5369..d6dc112dce 100644
--- a/indra/newview/skins/default/xui/en/floater_adjust_environment.xml
+++ b/indra/newview/skins/default/xui/en/floater_adjust_environment.xml
@@ -47,15 +47,15 @@
name="ambient_lbl"
height="10"
layout="topleft"
- left="10"
+ left="7"
top="5"
- width="80">Ambient:</text>
+ width="80">Ambient</text>
<color_swatch can_apply_immediately="true"
follows="left|top"
height="40"
label_height="0"
layout="topleft"
- left_delta="0"
+ left_delta="3"
name="ambient_light"
top_pad="5"
width="60"/>
@@ -63,15 +63,15 @@
name="blue_horizon_lbl"
height="10"
layout="topleft"
- left_delta="0"
+ left="7"
top_pad="10"
- width="80">Blue Horizon:</text>
+ width="80">Blue Horizon</text>
<color_swatch can_apply_immediately="true"
follows="left|top"
height="40"
label_height="0"
layout="topleft"
- left_delta="0"
+ left_delta="3"
name="blue_horizon"
top_pad="5"
width="60"/>
@@ -79,15 +79,15 @@
name="blue_density_lbl"
height="10"
layout="topleft"
- left_delta="0"
+ left="7"
top_pad="10"
- width="80">Blue Density:</text>
+ width="80">Blue Density</text>
<color_swatch can_apply_immediately="true"
follows="left|top"
height="40"
label_height="0"
layout="topleft"
- left_delta="0"
+ left_delta="3"
name="blue_density"
top_pad="5"
width="60"/>
@@ -107,7 +107,7 @@
layout="topleft"
right="-12"
top="5"
- width="60">Sun Color:</text>
+ width="60">Sun Color</text>
<color_swatch can_apply_immediately="true"
follows="left|top"
height="10"
@@ -123,7 +123,7 @@
layout="topleft"
left_delta="0"
top_pad="5"
- width="80">Cloud Color:</text>
+ width="80">Cloud Color</text>
<color_swatch can_apply_immediately="true"
follows="left|top"
height="10"
@@ -139,7 +139,7 @@
left_delta="0"
top_pad="10"
name="cloud_map_label"
- width="80">Cloud Image:</text>
+ width="80">Cloud Image</text>
<texture_picker height="63"
layout="topleft"
left_delta="0"
@@ -152,7 +152,7 @@
left_delta="0"
top_pad="-13"
name="water_map_label"
- width="80">Water Image:</text>
+ width="80">Water Image</text>
<texture_picker height="63"
layout="topleft"
left_delta="0"
diff --git a/indra/newview/skins/default/xui/en/floater_avatar_picker.xml b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml
index adbce0d982..0c82cbb00c 100644
--- a/indra/newview/skins/default/xui/en/floater_avatar_picker.xml
+++ b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml
@@ -63,7 +63,7 @@
layout="topleft"
left="10"
name="InstructSearchResidentName"
- top="8"
+ top="7"
width="220">
Type part of a person&apos;s name:
</text>
@@ -76,7 +76,7 @@
height="23"
left_delta="0"
name="Edit"
- top_pad="0"
+ top_pad="3"
width="65" />
<button
follows="top|right"
diff --git a/indra/newview/skins/default/xui/en/floater_bulk_perms.xml b/indra/newview/skins/default/xui/en/floater_bulk_perms.xml
index 7636284b4b..17631ad30c 100644
--- a/indra/newview/skins/default/xui/en/floater_bulk_perms.xml
+++ b/indra/newview/skins/default/xui/en/floater_bulk_perms.xml
@@ -29,7 +29,7 @@
control_name="BulkChangeIncludeAnimations"
height="16"
name="check_animation"
- top="24"
+ top="30"
left="10"
width="16" />
<icon
@@ -73,7 +73,7 @@
name="check_gesture"
left="95"
width="16"
- top="25" />
+ top="30" />
<icon
height="16"
image_name="Inv_Gesture"
@@ -116,7 +116,7 @@
control_name="BulkChangeIncludeScripts"
height="16"
name="check_script"
- top="25"
+ top="30"
left="180"
width="16"
/>
@@ -161,7 +161,7 @@
height="16"
name="check_settings"
left="245"
- top="25"
+ top="30"
width="16" />
<icon
height="16"
@@ -291,7 +291,7 @@
height="16"
label="Copy"
layout="topleft"
- top_pad="0"
+ top_pad="3"
name="next_owner_copy"
tool_tip="Next owner can make unlimited copies of this object. Copies maintain creator information, and can never be more permissive than the item being copied."
width="92">
@@ -302,7 +302,7 @@
control_name="BulkChangeNextOwnerTransfer"
enabled_control="BulkChangeNextOwnerCopy"
height="16"
- top_pad="0"
+ top_pad="3"
initial_value="true"
label="Transfer"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/floater_buy_currency.xml b/indra/newview/skins/default/xui/en/floater_buy_currency.xml
index e8e83301be..5e0903a40f 100644
--- a/indra/newview/skins/default/xui/en/floater_buy_currency.xml
+++ b/indra/newview/skins/default/xui/en/floater_buy_currency.xml
@@ -93,7 +93,6 @@
type="string"
length="1"
follows="top|left"
- font="SansSerifMedium"
height="16"
layout="topleft"
left="20"
@@ -105,7 +104,6 @@
<text
type="string"
length="1"
- font="SansSerifMedium"
follows="top|left"
halign="right"
height="16"
@@ -128,7 +126,6 @@
type="string"
length="1"
follows="top|left"
- font="SansSerifMedium"
height="16"
layout="topleft"
left="20"
@@ -140,7 +137,6 @@
<text
type="string"
length="1"
- font="SansSerifMedium"
follows="top|left"
halign="right"
height="16"
@@ -163,7 +159,6 @@
type="string"
length="1"
follows="top|left"
- font="SansSerifMedium"
font.style="BOLD"
height="16"
layout="topleft"
@@ -176,7 +171,6 @@
<text
type="string"
length="1"
- font="SansSerifMedium"
follows="top|left"
halign="right"
height="16"
@@ -207,7 +201,6 @@
type="string"
length="1"
follows="top|left"
- font="SansSerifMedium"
height="16"
top_pad="15"
layout="topleft"
@@ -217,7 +210,6 @@
Choose amount to buy
</text>
<text
- font="SansSerifMedium"
type="string"
length="1"
follows="left|top"
@@ -233,7 +225,6 @@
type="string"
max_length_bytes="10"
halign="right"
- font="SansSerifMedium"
select_on_focus="true"
follows="top|left"
top_delta="-4"
@@ -247,7 +238,6 @@
<text
type="string"
length="1"
- font="SansSerifMedium"
text_color="EmphasisColor"
follows="top|left"
halign="right"
@@ -276,7 +266,6 @@
</text>
<text
type="string"
- font="SansSerifMedium"
length="1"
follows="top|left"
height="16"
@@ -290,7 +279,6 @@
<text
type="string"
length="1"
- font="SansSerifMedium"
follows="top|left"
top_delta="0"
height="16"
@@ -350,7 +338,6 @@ Re-enter amount to see the latest exchange rate.
length="1"
follows="top|left"
layout="topleft"
- font="SansSerifMedium"
top="10"
left="20"
width="310"
diff --git a/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml b/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml
index 787b2f8be4..b911e9b6f5 100644
--- a/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml
+++ b/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml
@@ -290,7 +290,7 @@
<button
follows="top|left"
height="23"
- width="110"
+ width="113"
label="Clone Track From"
left="10"
top_pad="10"
@@ -298,7 +298,7 @@
<button
follows="top|left"
height="23"
- width="110"
+ width="113"
label="Load Track From"
top_pad="0"
left_delta="0"
@@ -306,7 +306,7 @@
<button
follows="top|left"
height="23"
- width="110"
+ width="113"
label="Clear Track"
top_pad="0"
left_delta="0"
diff --git a/indra/newview/skins/default/xui/en/floater_edit_hover_height.xml b/indra/newview/skins/default/xui/en/floater_edit_hover_height.xml
index c831684594..41e8d3dc8a 100644
--- a/indra/newview/skins/default/xui/en/floater_edit_hover_height.xml
+++ b/indra/newview/skins/default/xui/en/floater_edit_hover_height.xml
@@ -5,7 +5,7 @@
can_minimize="true"
can_close="true"
can_resize="false"
- height="80"
+ height="84"
width="515"
layout="topleft"
name="HoverHeight"
@@ -39,6 +39,6 @@
label="Bind Camera view"
layout="topleft"
name="BindCameraCheck"
- top_pad="7"
+ top_pad="14"
width="237"/>
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_font_test.xml b/indra/newview/skins/default/xui/en/floater_font_test.xml
index 61cb91e2f3..8070ed55e6 100644
--- a/indra/newview/skins/default/xui/en/floater_font_test.xml
+++ b/indra/newview/skins/default/xui/en/floater_font_test.xml
@@ -5,7 +5,7 @@
height="800"
layout="topleft"
min_height="175"
- min_width="154"
+ min_width="390"
name="contents"
help_topic="contents"
title="FONT TEST"
diff --git a/indra/newview/skins/default/xui/en/floater_god_tools.xml b/indra/newview/skins/default/xui/en/floater_god_tools.xml
index f8ec696af9..e94669bba4 100644
--- a/indra/newview/skins/default/xui/en/floater_god_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_god_tools.xml
@@ -6,7 +6,7 @@
name="godtools floater"
help_topic="godtools_floater"
title="GOD TOOLS"
- width="400">
+ width="410">
<tab_container
follows="left|top"
height="364"
@@ -15,7 +15,7 @@
name="GodTools Tabs"
tab_position="top"
top="20"
- width="400">
+ width="410">
<panel
border="true"
follows="left|top|right|bottom"
@@ -72,11 +72,11 @@
follows="left|top|right"
height="20"
layout="topleft"
- left_pad="0"
+ left_pad="5"
max_length_bytes="63"
name="region name"
top_delta="0"
- width="250">
+ width="294">
<line_editor.commit_callback
function="RegionTools.ChangeAnything" />
</line_editor>
@@ -233,13 +233,13 @@
border_style="line"
border_thickness="1"
follows="top|right"
- height="16"
+ height="18"
layout="topleft"
- left_delta="108"
+ left_delta="90"
max_length_bytes="10"
name="estate"
top_delta="0"
- width="50" />
+ width="100" />
<text
type="string"
length="1"
@@ -249,7 +249,7 @@
layout="topleft"
left="200"
name="parent id"
- top_pad="4"
+ top_pad="7"
width="190">
Parent ID:
</text>
@@ -257,14 +257,14 @@
border_style="line"
border_thickness="1"
follows="top|right"
- height="16"
+ height="18"
layout="topleft"
- left_delta="108"
+ left_delta="90"
max_length_bytes="10"
name="parentestate"
tool_tip="This is the parent estate for this region"
top_delta="0"
- width="50">
+ width="100">
<line_editor.commit_callback
function="RegionTools.ChangeAnything" />
</line_editor>
@@ -276,22 +276,22 @@
layout="topleft"
left="200"
name="Grid Pos: "
- top_pad="4"
- width="190">
+ top_pad="7"
+ width="90">
Grid Pos:
</text>
<line_editor
border_style="line"
border_thickness="1"
follows="top|right"
- height="16"
+ height="18"
layout="topleft"
- left_delta="88"
+ left_pad="0"
max_length_bytes="10"
name="gridposx"
tool_tip="This is the grid x position for this region"
top_delta="0"
- width="50">
+ width="46">
<line_editor.commit_callback
function="RegionTools.ChangeAnything" />
</line_editor>
@@ -299,14 +299,14 @@
border_style="line"
border_thickness="1"
follows="top|right"
- height="16"
+ height="18"
layout="topleft"
- left_pad="10"
+ left_pad="8"
max_length_bytes="10"
name="gridposy"
tool_tip="This is the grid y position for this region"
top_delta="0"
- width="40">
+ width="46">
<line_editor.commit_callback
function="RegionTools.ChangeAnything" />
</line_editor>
@@ -318,20 +318,20 @@
layout="topleft"
left="200"
name="Redirect to Grid: "
- top_pad="4"
- width="88">
+ top_pad="7"
+ width="90">
Redirect to Grid:
</text>
<line_editor
border_style="line"
border_thickness="1"
follows="top|right"
- height="16"
+ height="18"
layout="topleft"
left_pad="0"
max_length_bytes="10"
name="redirectx"
- width="50">
+ width="46">
<line_editor.commit_callback
function="RegionTools.ChangeAnything" />
</line_editor>
@@ -339,13 +339,13 @@
border_style="line"
border_thickness="1"
follows="top|right"
- height="16"
+ height="18"
layout="topleft"
- left_pad="10"
+ left_pad="8"
max_length_bytes="10"
name="redirecty"
top_delta="0"
- width="40">
+ width="46">
<line_editor.commit_callback
function="RegionTools.ChangeAnything" />
</line_editor>
@@ -407,10 +407,10 @@
label="Refresh"
label_selected="Refresh"
layout="topleft"
- left="278"
+ left="280"
name="Refresh"
tool_tip="Click here to refresh the above information"
- top_pad="10"
+ top_pad="14"
width="110">
<button.commit_callback
function="RegionTools.Refresh" />
@@ -526,7 +526,7 @@
height="16"
label="Disable Physics"
layout="topleft"
- left_delta="120"
+ left_delta="136"
name="disable physics"
tool_tip="Set this to disable all physics in this region"
top_delta="0"
diff --git a/indra/newview/skins/default/xui/en/floater_inventory_settings.xml b/indra/newview/skins/default/xui/en/floater_inventory_settings.xml
index a51e7a844a..5dd3dfa2bf 100644
--- a/indra/newview/skins/default/xui/en/floater_inventory_settings.xml
+++ b/indra/newview/skins/default/xui/en/floater_inventory_settings.xml
@@ -27,7 +27,6 @@
left_pad="12"
top_delta="2"
name="multi_folder_txt"
- font="SansSerifMedium"
text_color="White"
width="300">
Double-click on folder in multi-folder view:
@@ -37,7 +36,6 @@
follows="left|top"
top_pad="8"
layout="topleft"
- font="SansSerifMedium"
left="60"
width="300"
height="66"
@@ -90,7 +88,6 @@
left_pad="12"
top_delta="2"
name="single_folder_txt"
- font="SansSerifMedium"
text_color="White"
width="300">
Double-click on folder in single-folder view:
@@ -100,7 +97,6 @@
follows="left|top"
top_pad="8"
layout="topleft"
- font="SansSerifMedium"
left="60"
width="300"
height="44"
@@ -142,10 +138,9 @@
layout="topleft"
left_pad="13"
name="find_original_txt"
- font="SansSerifMedium"
text_color="White"
top_delta="1"
- width="300">
+ width="310">
Clicking on "Show in inventory" or "Find original"
</text>
<radio_group
@@ -153,7 +148,6 @@
follows="left|top"
top_pad="8"
layout="topleft"
- font="SansSerifMedium"
left="60"
width="300"
height="44"
@@ -196,7 +190,6 @@
left_pad="12"
top_delta="2"
name="favorites_txt"
- font="SansSerifMedium"
text_color="White"
width="300">
Favorites
@@ -206,7 +199,6 @@
layout="topleft"
follows="left|top"
top_pad="8"
- font="SansSerifMedium"
left="60"
width="300"
height="18"
@@ -219,7 +211,6 @@
follows="left|top"
top_pad="5"
layout="topleft"
- font="SansSerifMedium"
left="60"
width="150"
height="18"
@@ -232,7 +223,6 @@
follows="left|top"
top_pad="5"
layout="topleft"
- font="SansSerifMedium"
left="60"
width="150"
height="18"
@@ -276,7 +266,6 @@
left_pad="12"
top_delta="2"
name="single_folder_txt"
- font="SansSerifMedium"
text_color="White"
width="300">
Pressing enter on an avatar attachment
diff --git a/indra/newview/skins/default/xui/en/floater_live_material_editor.xml b/indra/newview/skins/default/xui/en/floater_live_material_editor.xml
index 5b7dab6a52..a104923f8d 100644
--- a/indra/newview/skins/default/xui/en/floater_live_material_editor.xml
+++ b/indra/newview/skins/default/xui/en/floater_live_material_editor.xml
@@ -4,9 +4,9 @@
can_resize="true"
default_tab_group="1"
height="790"
- width="256"
+ width="267"
min_height="500"
- min_width="256"
+ min_width="267"
layout="topleft"
name="material editor"
help_topic="material_editor"
@@ -17,7 +17,7 @@
top="18"
left="4"
height="768"
- width="250"
+ width="261"
follows="all"
layout="topleft"
color="DkGray2"
diff --git a/indra/newview/skins/default/xui/en/floater_material_editor.xml b/indra/newview/skins/default/xui/en/floater_material_editor.xml
index 21ceeafeea..f894e94622 100644
--- a/indra/newview/skins/default/xui/en/floater_material_editor.xml
+++ b/indra/newview/skins/default/xui/en/floater_material_editor.xml
@@ -4,9 +4,9 @@
can_resize="true"
default_tab_group="1"
height="891"
- width="256"
+ width="267"
min_height="500"
- min_width="256"
+ min_width="267"
layout="topleft"
name="material editor"
help_topic="material_editor"
@@ -20,7 +20,7 @@
top="18"
left="4"
height="768"
- width="250"
+ width="261"
follows="all"
layout="topleft"
color="DkGray2"
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index 39e9de0980..fb828b804a 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -1407,7 +1407,7 @@
follows="top|left"
height="15"
layout="topleft"
- left="220"
+ left="240"
name="pelvis_offset_label"
text_color="White"
top="8"
@@ -1421,12 +1421,13 @@
max_val="3.0"
name="pelvis_offset"
top_pad="10"
+ left="340"
value="0.0"
width="80"/>
<text
follows="top|left"
height="17"
- left="425"
+ left="435"
name="skin_too_many_joints"
text_color="Orange"
top="7"
@@ -1437,7 +1438,7 @@
<text
follows="top|left"
height="32"
- left="425"
+ left="435"
name="skin_unknown_joint"
text_color="Orange"
top="8"
@@ -1879,7 +1880,7 @@ Analysed:
top="5"
left_pad="20"
name="label_display"
- width="50">
+ width="53">
Display...
</text>
<check_box
@@ -1889,7 +1890,7 @@ Analysed:
layout="topleft"
left_delta="0"
name="show_edges"
- top_pad="8">
+ top_pad="10">
</check_box>
<check_box
follows="top|left"
@@ -1897,7 +1898,7 @@ Analysed:
label_text.text_color="White"
layout="topleft"
name="show_physics"
- top_pad="8">
+ top_pad="10">
</check_box>
<check_box
follows="top|left"
@@ -1905,7 +1906,7 @@ Analysed:
label_text.text_color="White"
layout="topleft"
name="show_textures"
- top_pad="8">
+ top_pad="10">
</check_box>
<check_box
follows="top|left"
@@ -1913,7 +1914,7 @@ Analysed:
label_text.text_color="White"
layout="topleft"
name="show_skin_weight"
- top_pad="8">
+ top_pad="10">
</check_box>
<check_box
follows="top|left"
@@ -1923,7 +1924,7 @@ Analysed:
width="130"
layout="topleft"
name="show_joint_overrides"
- top_pad="8">
+ top_pad="10">
</check_box>
<check_box
follows="top|left"
@@ -1931,7 +1932,7 @@ Analysed:
label_text.text_color="White"
layout="topleft"
name="show_joint_positions"
- top_pad="17">
+ top_pad="21">
</check_box>
<text
follows="top|left"
diff --git a/indra/newview/skins/default/xui/en/floater_my_environments.xml b/indra/newview/skins/default/xui/en/floater_my_environments.xml
index 8c9c450d7c..88fd8bf585 100644
--- a/indra/newview/skins/default/xui/en/floater_my_environments.xml
+++ b/indra/newview/skins/default/xui/en/floater_my_environments.xml
@@ -41,6 +41,7 @@
mouse_opaque="true"
name="icon_settingsdays"
left="4"
+ top="9"
width="16" />
<check_box
height="16"
@@ -48,7 +49,7 @@
layout="topleft"
left_pad="2"
name="chk_days"
- top_delta="0"
+ top_delta="2"
width="60" />
<icon
height="16"
@@ -57,6 +58,7 @@
mouse_opaque="true"
name="icon_settingsskies"
left_pad="10"
+ top="9"
width="16" />
<check_box
height="16"
@@ -64,7 +66,7 @@
layout="topleft"
left_pad="2"
name="chk_skies"
- top_delta="0"
+ top_delta="2"
width="60" />
<icon
height="16"
@@ -73,6 +75,7 @@
mouse_opaque="true"
name="icon_settingswater"
left_pad="10"
+ top="9"
width="16" />
<check_box
height="16"
@@ -80,7 +83,7 @@
layout="topleft"
left_pad="2"
name="chk_water"
- top_delta="0"
+ top_delta="2"
width="60" />
<filter_editor
follows="left|top|right"
@@ -89,7 +92,7 @@
layout="topleft"
left="4"
name="flt_search"
- top_pad="6"
+ top_pad="4"
right="-4" />
</layout_panel>
<layout_panel
diff --git a/indra/newview/skins/default/xui/en/floater_my_inventory.xml b/indra/newview/skins/default/xui/en/floater_my_inventory.xml
index 881c1f7469..def57abfe4 100644
--- a/indra/newview/skins/default/xui/en/floater_my_inventory.xml
+++ b/indra/newview/skins/default/xui/en/floater_my_inventory.xml
@@ -12,7 +12,7 @@
save_visibility="true"
reuse_instance="true"
title="INVENTORY"
- width="418" >
+ width="424" >
<panel
class="sidepanel_inventory"
name="main_panel"
diff --git a/indra/newview/skins/default/xui/en/floater_new_feature_notification.xml b/indra/newview/skins/default/xui/en/floater_new_feature_notification.xml
index 9981e5d893..66c229e698 100644
--- a/indra/newview/skins/default/xui/en/floater_new_feature_notification.xml
+++ b/indra/newview/skins/default/xui/en/floater_new_feature_notification.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater
- height="130"
+ height="140"
width="300"
layout="topleft"
name="floater_new_feature_notification"
@@ -40,7 +40,7 @@ New feature
text_color="White"
layout="topleft"
left="10"
- height="40"
+ height="50"
top_pad="14"
right="-10"
word_wrap="true"
diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml
index dac8a71b2d..5fb9eeb2de 100644
--- a/indra/newview/skins/default/xui/en/floater_performance.xml
+++ b/indra/newview/skins/default/xui/en/floater_performance.xml
@@ -65,10 +65,10 @@
text_color="White"
height="20"
layout="topleft"
- left="395"
+ left="392"
top="7"
name="fps_desc1_lbl"
- width="150">
+ width="153">
Allow 5-10 seconds for
</text>
<text
@@ -78,7 +78,7 @@
layout="topleft"
top_pad="-3"
name="fps_desc2_lbl"
- width="150">
+ width="153">
changes to take full effect.
</text>
</panel>
@@ -265,7 +265,7 @@
left="10"
name="complexity_info"
top_pad="0"
- width="455">
+ width="490">
Reduce the complexity of your avatar if you aren't satisfied with current FPS.
</text>
<icon
diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml
index 4b0e0bb221..b7d992bcb4 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences.xml
@@ -82,8 +82,8 @@
name="pref core"
tab_group="1"
tab_position="left"
- tab_width="140"
- tab_padding_right="0"
+ tab_width="136"
+ tab_padding_right="4"
top="40"
width="658">
<panel
diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
index 2a18134491..99dca7b395 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
@@ -664,7 +664,7 @@
increment="8"
initial_value="160"
label="Sky:"
- label_width="145"
+ label_width="164"
layout="topleft"
left="420"
min_val="16"
@@ -750,7 +750,7 @@
control_name="RenderShadowDetail"
height="18"
layout="topleft"
- left_delta="130"
+ left_delta="175"
top_delta="0"
name="ShadowDetail"
width="150">
@@ -800,7 +800,7 @@
control_name="RenderReflectionProbeDetail"
height="18"
layout="topleft"
- left_delta="130"
+ left_delta="175"
top_delta="0"
name="ReflectionDetail"
width="150">
@@ -836,7 +836,7 @@
control_name="RenderReflectionProbeLevel"
height="18"
layout="topleft"
- left_delta="130"
+ left_delta="175"
top_delta="0"
name="ReflectionLevel"
width="150">
@@ -868,7 +868,7 @@
name="ReflectionProbeCount"
text_readonly_color="LabelDisabledColor"
top_delta="22"
- width="128">
+ width="130">
Max Reflection Probes:
</text>
@@ -877,7 +877,7 @@
height="18"
layout="topleft"
label="Max. Reflection Probes:"
- left_delta="130"
+ left_delta="175"
top_delta="0"
name="ProbeCount"
width="150">
@@ -911,7 +911,7 @@
increment="0.1"
initial_value="160"
label="Exposure:"
- label_width="145"
+ label_width="164"
layout="topleft"
left="420"
min_val="0.5"
@@ -955,7 +955,7 @@
control_name="RenderHeroProbeResolution"
height="18"
layout="topleft"
- left_delta="130"
+ left_delta="175"
top_delta="0"
name="MirrorResolution"
width="150">
@@ -995,7 +995,7 @@
control_name="RenderHeroProbeUpdateRate"
height="18"
layout="topleft"
- left_delta="130"
+ left_delta="175"
top_delta="0"
name="HeroProbeUpdateRate"
width="150">
@@ -1026,7 +1026,7 @@
increment="0.1"
initial_value="160"
label="Sharpening:"
- label_width="145"
+ label_width="164"
layout="topleft"
left="420"
min_val="0.0"
@@ -1055,7 +1055,7 @@
control_name="RenderTonemapType"
height="18"
layout="topleft"
- left_delta="130"
+ left_delta="175"
top_delta="0"
name="TonemapType"
width="150">
@@ -1077,7 +1077,7 @@
initial_value="1"
label="Tone Mapping Mix:"
tool_tip="Mix between linear and tone mapped colors"
- label_width="145"
+ label_width="164"
layout="topleft"
left="420"
min_val="0.0"
diff --git a/indra/newview/skins/default/xui/en/floater_stats.xml b/indra/newview/skins/default/xui/en/floater_stats.xml
index 1600c422c3..191db4f854 100644
--- a/indra/newview/skins/default/xui/en/floater_stats.xml
+++ b/indra/newview/skins/default/xui/en/floater_stats.xml
@@ -418,6 +418,64 @@
</stat_view>
</stat_view>
</stat_view>
+ <stat_view name="voice"
+ label="Voice"
+ setting="OpenDebugStatVoice">
+ <stat_bar
+ name="webrtc_latency"
+ label="Latency"
+ stat="webrtc_latency"
+ unit_label="ms"
+ decimal_digits="1"/>
+ <stat_bar
+ name="webrtc_upload_bandwidth"
+ label="Upload bandwidth"
+ stat="webrtc_upload_bandwidth"
+ unit_label="kbps"
+ decimal_digits="0"/>
+ <stat_view name="incoming_audio"
+ label="Incoming audio"
+ setting="OpenDebugStatVoiceIncoming">
+ <stat_bar
+ name="incoming_packet_recv"
+ label="Packets received"
+ stat="webrtc_packets_in_recv"/>
+ <stat_bar
+ name="packets_in_lost"
+ label="Packets lost"
+ stat="webrtc_packets_in_lost"/>
+ <stat_bar
+ name="jitter_in"
+ label="Jitter"
+ stat="webrtc_jitter_in"
+ unit_label="ms"
+ decimal_digits="1"/>
+ <stat_bar
+ name="jitter_buffer"
+ label="Jitter buffer"
+ stat="webrtc_jitter_buffer"
+ unit_label="ms"
+ decimal_digits="1"/>
+ </stat_view>
+ <stat_view name="outgoing_audio"
+ label="Outgoing audio"
+ setting="OpenDebugStatVoiceOutgoing">
+ <stat_bar
+ name="packets_out_sent"
+ label="Packets sent"
+ stat="webrtc_packets_out_sent"/>
+ <stat_bar
+ name="packets_out_lost"
+ label="Packets lost"
+ stat="webrtc_packets_out_lost"/>
+ <stat_bar
+ name="jitter_out"
+ label="Jitter"
+ stat="webrtc_jitter_out"
+ unit_label="ms"
+ decimal_digits="1"/>
+ </stat_view>
+ </stat_view>
</container_view>
</scroll_container>
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_telehub.xml b/indra/newview/skins/default/xui/en/floater_telehub.xml
index 9d4fb82ec6..7108005f00 100644
--- a/indra/newview/skins/default/xui/en/floater_telehub.xml
+++ b/indra/newview/skins/default/xui/en/floater_telehub.xml
@@ -2,7 +2,7 @@
<!-- Explicit left edge to avoid overlapping build tools -->
<floater
legacy_header_height="18"
- height="250"
+ height="260"
layout="topleft"
name="telehub"
help_topic="telehub"
diff --git a/indra/newview/skins/default/xui/en/floater_test_slapp.xml b/indra/newview/skins/default/xui/en/floater_test_slapp.xml
index 5a13a0147e..35f5961285 100644
--- a/indra/newview/skins/default/xui/en/floater_test_slapp.xml
+++ b/indra/newview/skins/default/xui/en/floater_test_slapp.xml
@@ -17,7 +17,6 @@
follows="left|top|right"
height="16"
name="trusted_txt"
- font="SansSerifMedium"
text_color="white"
layout="topleft"
left="16">
diff --git a/indra/newview/skins/default/xui/en/floater_test_textbox.xml b/indra/newview/skins/default/xui/en/floater_test_textbox.xml
index 023df69f0f..e736fc58b2 100644
--- a/indra/newview/skins/default/xui/en/floater_test_textbox.xml
+++ b/indra/newview/skins/default/xui/en/floater_test_textbox.xml
@@ -99,7 +99,7 @@
font.name="SansSerifSmall"
name="test_text10"
tool_tip="text">
- SansSerifSmall
+ SansSerif
The 华文细黑 brown fox ヒラキjumped over the lazy dog.
</text>
<text
@@ -111,7 +111,7 @@
font.name="SansSerifMedium"
name="test_text11"
tool_tip="text">
- SansSerif
+ SansSerifMedium
The 华文细黑 brown fox ヒラキjumped over the lazy dog.
</text>
<text
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index d3a872c9d5..d94a6c71b5 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -84,11 +84,14 @@
left="10"
name="button focus"
tool_tip="Focus"
- width="35">
- <button.commit_callback
- function="BuildTool.setTool"
- parameter="Focus" />
- </button>
+ width="35"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1">
+ <button.commit_callback
+ function="BuildTool.setTool"
+ parameter="Focus" />
+ </button>
<button
follows="left|top"
height="25"
@@ -99,7 +102,10 @@
left_pad="10"
name="button move"
tool_tip="Move"
- width="35">
+ width="35"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1">
<button.commit_callback
function="BuildTool.setTool"
parameter="Move" />
@@ -114,7 +120,10 @@
left_pad="10"
name="button edit"
tool_tip="Edit"
- width="35">
+ width="35"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1">
<button.commit_callback
function="BuildTool.setTool"
parameter="Edit" />
@@ -129,7 +138,10 @@
left_pad="10"
name="button create"
tool_tip="Create"
- width="35">
+ width="35"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1">
<button.commit_callback
function="BuildTool.setTool"
parameter="Create" />
@@ -144,7 +156,10 @@
left_pad="10"
name="button land"
tool_tip="Land"
- width="35">
+ width="35"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1">
<button.commit_callback
function="BuildTool.setTool"
parameter="Land" />
@@ -161,15 +176,19 @@
left="8"
name="text status"
top_pad="3"
- width="285">
+ width="285"
+ font="DejaVu"
+ font.size="LSmall">
Drag to move, shift-drag to copy
</text>
<radio_group
layout="topleft"
left="10"
- height="70"
- top="59"
- name="focus_radio_group">
+ height="70"
+ top="59"
+ name="focus_radio_group"
+ font="DejaVu"
+ font.size="LSmall" >
<radio_item
top_pad="6"
label="Zoom"
@@ -198,16 +217,20 @@
top_delta="-2"
left_delta="100"
name="slider zoom"
- width="134">
+ width="134"
+ font="DejaVu"
+ font.size="LSmall">
<slider_bar.commit_callback
function="BuildTool.commitZoom"/>
</slider_bar>
<radio_group
- left="10"
- height="70"
- top="59"
+ left="10"
+ height="70"
+ top="59"
layout="topleft"
- name="move_radio_group">
+ name="move_radio_group"
+ font="DejaVu"
+ font.size="LSmall" >
<radio_item
top_pad="6"
label="Move"
@@ -232,7 +255,9 @@
top="55"
height="70"
layout="topleft"
- name="edit_radio_group">
+ name="edit_radio_group"
+ font="DejaVu"
+ font.size="LSmall" >
<radio_item
label="Move"
layout="topleft"
@@ -263,7 +288,9 @@
label="Edit linked"
layout="topleft"
name="checkbox edit linked parts"
- top_pad="-18">
+ top_pad="-18"
+ font="DejaVu"
+ font.size="LSmall">
<check_box.commit_callback
function="BuildTool.selectComponent"/>
</check_box>
@@ -276,7 +303,10 @@
layout="topleft"
left="143"
name="link_btn"
- width="50">
+ width="50"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1">
<button.commit_callback
function="BuildTool.LinkObjects"/>
</button>
@@ -287,7 +317,10 @@
layout="topleft"
left_pad="2"
name="unlink_btn"
- width="90">
+ width="90"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1">
<button.commit_callback
function="BuildTool.UnlinkObjects"/>
</button>
@@ -298,10 +331,12 @@
layout="topleft"
left="143"
name="checkbox uniform"
- top="48"
+ top="47"
label_text.wrap="true"
label_text.width="100"
- width="134" />
+ width="134"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
control_name="ScaleStretchTextures"
height="19"
@@ -310,18 +345,22 @@
layout="topleft"
left="143"
name="checkbox stretch textures"
- top_pad="-4"
+ top_pad="-2"
follows="left|top"
- width="134" />
+ width="134"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
control_name="SnapEnabled"
height="18"
initial_value="true"
label="Snap"
layout="topleft"
- top_pad="0"
+ top_pad="-1"
name="checkbox snap to grid"
- width="134" />
+ width="134"
+ font="DejaVu"
+ font.size="LSmall"/>
<combo_box
height="20"
layout="topleft"
@@ -331,7 +370,9 @@
top="83"
left="195"
top_pad="0"
- width="60">
+ width="60"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall">
<combo_box.item
label="World"
name="World"
@@ -577,7 +618,7 @@
layout="topleft"
left_delta="0"
name="checkbox copy selection"
- top_delta="15"
+ top_delta="17"
width="134" />
<check_box
control_name="CreateToolCopyCenters"
@@ -587,7 +628,7 @@
layout="topleft"
left_delta="18"
name="checkbox copy centers"
- top="85"
+ top="92"
width="134" />
<check_box
control_name="CreateToolCopyRotates"
@@ -596,7 +637,7 @@
layout="topleft"
left_delta="0"
name="checkbox copy rotates"
- top_delta="16"
+ top_delta="17"
width="134" />
<radio_group
height="105"
@@ -604,7 +645,9 @@
left="4"
name="land_radio_group"
top="54"
- width="114">
+ width="114"
+ font="DejaVu"
+ font.size="LSmall" >
<radio_item
height="19"
label="Select Land"
@@ -746,7 +789,8 @@
length="1"
height="16"
follows="left|top"
- font="SansSerifSmall"
+ font="DejaVu"
+ font.size="LSmall"
layout="topleft"
left="10"
name="selection_empty"
@@ -760,7 +804,8 @@
length="1"
height="16"
follows="left|top"
- font="SansSerifSmall"
+ font="DejaVu"
+ font.size="LSmall"
layout="topleft"
left="10"
name="selection_faces"
@@ -775,7 +820,8 @@
length="1"
height="16"
follows="left|top"
- font="SansSerifSmall"
+ font="DejaVu"
+ font.size="LSmall"
layout="topleft"
left="10"
name="selection_count"
@@ -830,7 +876,9 @@
tab_height="25"
open_tabs_on_drag_and_drop="true"
top="173"
- width="295">
+ width="295"
+ font="DejaVu"
+ font.size="LSmall">
<panel
border="false"
@@ -904,7 +952,9 @@
left="10"
name="Name:"
top="5"
- width="90">
+ width="90"
+ font="DejaVu"
+ font.size="LSmall">
Name:
</text>
<line_editor
@@ -923,7 +973,9 @@
left="10"
name="Description:"
top_pad="3"
- width="90">
+ width="90"
+ font="DejaVu"
+ font.size="LSmall">
Description:
</text>
<line_editor
@@ -945,7 +997,9 @@
layout="topleft"
name="Creator:"
top_pad="7"
- width="90">
+ width="90"
+ font="DejaVu"
+ font.size="LSmall">
Creator:
</text>
<avatar_icon
@@ -967,7 +1021,6 @@
height="29"
layout="topleft"
name="Creator Name"
- font="SansSerifSmall"
top_delta="-1"
translate="false"
width="170"
@@ -984,7 +1037,9 @@
layout="topleft"
name="Owner:"
top_pad="3"
- width="90">
+ width="90"
+ font="DejaVu"
+ font.size="LSmall">
Owner:
</text>
<avatar_icon
@@ -1015,7 +1070,8 @@
height="29"
layout="topleft"
name="Owner Name"
- font="SansSerifSmall"
+ font="DejaVu"
+ font.size="LSmall"
left_pad="1"
top_delta="-1"
translate="false"
@@ -1033,7 +1089,9 @@
height="18"
name="Group:"
top_pad="3"
- width="75">
+ width="75"
+ font="DejaVu"
+ font.size="LSmall">
Group:
</text>
<name_box
@@ -1053,7 +1111,10 @@
name="button set group"
tab_stop="false"
tool_tip="Choose a group to share this object's permissions"
- width="23" />
+ width="23"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1" />
<check_box
height="19"
follows="left|top"
@@ -1063,7 +1124,9 @@
tool_tip="Allow all members of the set group to share your modify permissions for this object. You must Deed to enable role restrictions."
top_pad="5"
left="100"
- width="87" />
+ width="87"
+ font="DejaVu"
+ font.size="LSmall" />
<button
follows="top|left"
height="23"
@@ -1073,7 +1136,10 @@
name="button deed"
left_pad="19"
tool_tip="Deeding gives this item away with next owner permissions. Group shared objects can be deeded by a group officer."
- width="80" />
+ width="80"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1" />
<text
type="string"
length="1"
@@ -1083,7 +1149,9 @@
top_pad="10"
left="10"
name="label click action"
- width="82">
+ width="82"
+ font="DejaVu"
+ font.size="LSmall" >
Click to:
</text>
<combo_box
@@ -1093,7 +1161,9 @@
name="clickaction"
width="130"
left_pad="10"
- tool_tip="A click action enables you to interact with an object with a single left click. Each click action has a special cursor indicating what it does. Some click actions have requirements to function. For example Touch and Pay require scripts" >
+ tool_tip="A click action enables you to interact with an object with a single left click. Each click action has a special cursor indicating what it does. Some click actions have requirements to function. For example Touch and Pay require scripts"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall" >
<combo_box.item
label="Touch (default)"
name="Touch/grab(default)"
@@ -1134,7 +1204,9 @@
name="checkbox for sale"
left="7"
width="97"
- tool_tip="Lets people buy this object, its content or it copy inworld for specified price." />
+ tool_tip="Lets people buy this object, its content or it copy inworld for specified price."
+ font="DejaVu"
+ font.size="LSmall" />
<!-- NEW PRICE SPINNER
Objects are allowed to be for sale for L$0 to invoke buy UI behavior
even though the user gets a free copy.
@@ -1152,7 +1224,9 @@ even though the user gets a free copy.
min_val="0"
height="20"
max_val="999999999"
- tool_tip="Object cost." />
+ tool_tip="Object cost."
+ font="DejaVu"
+ font.size="LSmall" />
<!-- NEW SALE TYPE COMBO BOX -->
<combo_box
left_pad="8"
@@ -1166,7 +1240,9 @@ even though the user gets a free copy.
mouse_opaque="true"
name="sale type"
width="89"
- tool_tip="Select whether purchaser will receive a copy, copy of the content or item itself." >
+ tool_tip="Select whether purchaser will receive a copy, copy of the content or item itself."
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall" >
<combo_box.item
name="Copy"
label="Copy"
@@ -1188,7 +1264,9 @@ even though the user gets a free copy.
layout="topleft"
left="7"
name="search_check"
- tool_tip="Let people see this object in search results" />
+ tool_tip="Let people see this object in search results"
+ font="DejaVu"
+ font.size="LSmall" />
<panel
border="false"
follows="left|top"
@@ -1212,7 +1290,9 @@ even though the user gets a free copy.
follows="left|top|right"
layout="topleft"
name="perm_modify"
- width="264">
+ width="264"
+ font="DejaVu"
+ font.size="LSmall" >
You can modify this object
</text>
<text
@@ -1220,7 +1300,9 @@ even though the user gets a free copy.
follows="left|top"
name="Anyone can:"
width="250"
- left="10">
+ left="10"
+ font="DejaVu"
+ font.size="LSmall" >
Anyone:
</text>
<check_box
@@ -1230,7 +1312,9 @@ even though the user gets a free copy.
name="checkbox allow everyone move"
tool_tip="Anyone can move the object."
left="10"
- width="85" />
+ width="85"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
height="19"
label="Copy"
@@ -1238,14 +1322,18 @@ even though the user gets a free copy.
left_pad="0"
name="checkbox allow everyone copy"
tool_tip="Anyone can take a copy of the object. Object and all of its contents must be copy and transfer permissive."
- width="90" />
+ width="90"
+ font="DejaVu"
+ font.size="LSmall" />
<text
type="string"
follows="left|top"
height="19"
name="Next owner can:"
width="250"
- left="10">
+ left="10"
+ font="DejaVu"
+ font.size="LSmall" >
Next owner:
</text>
<check_box
@@ -1256,7 +1344,9 @@ even though the user gets a free copy.
height="10"
name="checkbox next owner can modify"
tool_tip="Next owner can edit properties like item name or scale of this object."
- width="85" />
+ width="85"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
follows="left|top|right"
height="19"
@@ -1265,7 +1355,9 @@ even though the user gets a free copy.
left_pad="0"
name="checkbox next owner can copy"
tool_tip="Next owner can make unlimited copies of this object. Copies maintain creator information, and can never be more permissive than the item being copied."
- width="80" />
+ width="80"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
follows="left|top|right"
height="19"
@@ -1275,7 +1367,9 @@ even though the user gets a free copy.
left_pad="0"
top_delta="0"
tool_tip="Next owner can give away or resell this object."
- width="100" />
+ width="100"
+ font="DejaVu"
+ font.size="LSmall" />
<!-- *NOTE: These "B/O/G/E/N/F fields may overlap "perm_modify" above,
but that's OK, this is used only for debugging. -->
<text
@@ -1288,7 +1382,9 @@ even though the user gets a free copy.
left="230"
name="B:"
height="10"
- width="80">
+ width="80"
+ font="DejaVu"
+ font.size="LSmall" >
B:
</text>
<text
@@ -1301,7 +1397,9 @@ even though the user gets a free copy.
top_pad="2"
name="O:"
height="10"
- width="80">
+ width="80"
+ font="DejaVu"
+ font.size="LSmall" >
O:
</text>
<text
@@ -1314,7 +1412,9 @@ even though the user gets a free copy.
top_pad="2"
name="G:"
height="10"
- width="80">
+ width="80"
+ font="DejaVu"
+ font.size="LSmall" >
G:
</text>
<text
@@ -1327,7 +1427,9 @@ even though the user gets a free copy.
layout="topleft"
name="E:"
height="10"
- width="80">
+ width="80"
+ font="DejaVu"
+ font.size="LSmall" >
E:
</text>
<text
@@ -1340,7 +1442,9 @@ even though the user gets a free copy.
top_pad="2"
name="N:"
height="10"
- width="80">
+ width="80"
+ font="DejaVu"
+ font.size="LSmall" >
N:
</text>
<text
@@ -1353,7 +1457,9 @@ even though the user gets a free copy.
top_pad="2"
name="F:"
height="10"
- width="80">
+ width="80"
+ font="DejaVu"
+ font.size="LSmall" >
F:
</text>
</panel>
@@ -1373,7 +1479,9 @@ even though the user gets a free copy.
name="pathfinding_attributes_label"
top_pad="4"
width="150"
- left="10">
+ left="10"
+ font="DejaVu"
+ font.size="LSmall" >
Pathfinding attributes:
</text>
<text
@@ -1383,7 +1491,9 @@ even though the user gets a free copy.
name="pathfinding_attributes_value"
width="130"
word_wrap="false"
- left_pad="0">
+ left_pad="0"
+ font="DejaVu"
+ font.size="LSmall" >
</text>
</panel>
</panel>
@@ -1408,7 +1518,9 @@ even though the user gets a free copy.
tool_tip="Prevents object from being moved or deleted. Frequently useful during building to avoid unintended edits."
top_pad="5"
left="10"
- width="123" />
+ width="123"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
height="19"
label="Physical"
@@ -1416,7 +1528,9 @@ even though the user gets a free copy.
name="Physical Checkbox Ctrl"
tool_tip="Allows object to be pushed and affected by gravity"
top_pad="0"
- width="123" />
+ width="123"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
height="19"
label="Temporary"
@@ -1424,7 +1538,9 @@ even though the user gets a free copy.
name="Temporary Checkbox Ctrl"
tool_tip="Causes object to be deleted 1 minute after creation"
top_pad="0"
- width="123" />
+ width="123"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
height="19"
label="Phantom"
@@ -1432,7 +1548,9 @@ even though the user gets a free copy.
name="Phantom Checkbox Ctrl"
tool_tip="Causes object to not collide with other objects or avatars"
top_pad="0"
- width="123" />
+ width="123"
+ font="DejaVu"
+ font.size="LSmall" />
<view_border
bevel_style="none"
follows="top|left"
@@ -1441,7 +1559,9 @@ even though the user gets a free copy.
left_delta="0"
name="object_horizontal"
top_pad="10"
- width="95" />
+ width="95"
+ font="DejaVu"
+ font.size="LSmall" />
<menu_button
menu_filename="menu_copy_paste_pos.xml"
follows="top|left"
@@ -1465,7 +1585,9 @@ even though the user gets a free copy.
tool_tip="Position (meters)"
left_pad="8"
top_delta="0"
- width="121">
+ width="121"
+ font="DejaVu"
+ font.size="LSmall" >
Position (m)
</text>
<spinner
@@ -1482,7 +1604,9 @@ even though the user gets a free copy.
name="Pos X"
text_enabled_color="1 0 0.3 .7"
top_pad="8"
- width="87" />
+ width="87"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -1497,7 +1621,9 @@ even though the user gets a free copy.
name="Pos Y"
text_enabled_color="EmphasisColor"
top_pad="3"
- width="87" />
+ width="87"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -1512,7 +1638,9 @@ even though the user gets a free copy.
name="Pos Z"
text_enabled_color="0 0.8 1 .65"
top_pad="3"
- width="87" />
+ width="87"
+ font="DejaVu"
+ font.size="LSmall" />
<menu_button
menu_filename="menu_copy_paste_size.xml"
follows="top|left"
@@ -1525,7 +1653,7 @@ even though the user gets a free copy.
top_pad="13"
name="clipboard_size_btn"
tool_tip="Paste options"
- width="19"/>
+ width="19" />
<text
type="string"
length="1"
@@ -1536,7 +1664,9 @@ even though the user gets a free copy.
top_delta="0"
name="label size"
tool_tip="Size (meters)"
- width="121">
+ width="121"
+ font="DejaVu"
+ font.size="LSmall" >
Size (m)
</text>
<spinner
@@ -1553,7 +1683,9 @@ even though the user gets a free copy.
name="Scale X"
text_enabled_color="1 1 1 1"
top_pad="8"
- width="87" />
+ width="87"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -1568,7 +1700,9 @@ even though the user gets a free copy.
name="Scale Y"
text_enabled_color="1 1 1 1"
top_pad="3"
- width="87" />
+ width="87"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -1583,7 +1717,9 @@ even though the user gets a free copy.
name="Scale Z"
text_enabled_color="1 1 1 1"
top_pad="3"
- width="87" />
+ width="87"
+ font="DejaVu"
+ font.size="LSmall" />
<menu_button
menu_filename="menu_copy_paste_rot.xml"
follows="top|left"
@@ -1607,7 +1743,9 @@ even though the user gets a free copy.
top_delta="0"
name="label rotation"
tool_tip="Rotation (degrees)"
- width="121">
+ width="121"
+ font="DejaVu"
+ font.size="LSmall" >
Rotation (°)
</text>
<spinner
@@ -1625,7 +1763,9 @@ even though the user gets a free copy.
name="Rot X"
text_enabled_color="1 1 1 1"
top_pad="8"
- width="87" />
+ width="87"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
decimal_digits="2"
follows="left|top"
@@ -1641,7 +1781,9 @@ even though the user gets a free copy.
name="Rot Y"
text_enabled_color="1 1 1 1"
top_pad="3"
- width="87" />
+ width="87"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
decimal_digits="2"
follows="left|top"
@@ -1657,7 +1799,9 @@ even though the user gets a free copy.
name="Rot Z"
text_enabled_color="1 1 1 1"
top_pad="3"
- width="87" />
+ width="87"
+ font="DejaVu"
+ font.size="LSmall" />
<!-- <text
type="string"
length="1"
@@ -1686,7 +1830,9 @@ even though the user gets a free copy.
name="comboBaseType"
top="6"
left="125"
- width="125">
+ width="125"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall" >
<combo_box.item
label="Box"
name="Box"
@@ -1742,7 +1888,9 @@ even though the user gets a free copy.
left="125"
name="text cut"
top_pad="5"
- width="150">
+ width="150"
+ font="DejaVu"
+ font.size="LSmall" >
Path Cut (begin/end)
</text>
<spinner
@@ -1757,7 +1905,9 @@ even though the user gets a free copy.
max_val="0.98"
name="cut begin"
top_pad="4"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="16"
@@ -1770,7 +1920,9 @@ even though the user gets a free copy.
min_val="0.02"
name="cut end"
top_delta="0"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<text
type="string"
length="1"
@@ -1780,7 +1932,9 @@ even though the user gets a free copy.
left="125"
name="text hollow"
top_pad="7"
- width="68">
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" >
Hollow
</text>
<text
@@ -1791,7 +1945,9 @@ even though the user gets a free copy.
layout="topleft"
left_pad="10"
name="text skew"
- width="63">
+ width="63"
+ font="DejaVu"
+ font.size="LSmall" >
Skew
</text>
<spinner
@@ -1805,7 +1961,9 @@ even though the user gets a free copy.
max_val="95"
name="Scale 1"
top_pad="4"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
decimal_digits="2"
follows="left|top"
@@ -1818,7 +1976,9 @@ even though the user gets a free copy.
min_val="-0.95"
name="Skew"
top_delta="0"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<text
type="string"
length="1"
@@ -1828,7 +1988,9 @@ even though the user gets a free copy.
left="125"
name="Hollow Shape"
top_pad="7"
- width="150">
+ width="150"
+ font="DejaVu"
+ font.size="LSmall" >
Hollow Shape
</text>
<combo_box
@@ -1837,7 +1999,9 @@ even though the user gets a free copy.
left_delta="0"
name="hole"
top_pad="-2"
- width="150">
+ width="150"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall" >
<combo_box.item
label="Default"
name="Default"
@@ -1864,7 +2028,9 @@ even though the user gets a free copy.
left_delta="0"
name="text twist"
top_pad="7"
- width="150">
+ width="150"
+ font="DejaVu"
+ font.size="LSmall" >
Twist (begin/end)
</text>
<spinner
@@ -1881,7 +2047,9 @@ even though the user gets a free copy.
min_val="-180"
name="Twist Begin"
top_pad="4"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
decimal_digits="0"
follows="left|top"
@@ -1896,7 +2064,9 @@ even though the user gets a free copy.
min_val="-180"
name="Twist End"
top_delta="0"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<text
type="string"
length="1"
@@ -1906,7 +2076,9 @@ even though the user gets a free copy.
left="125"
name="scale_taper"
top_pad="7"
- width="150">
+ width="150"
+ font="DejaVu"
+ font.size="LSmall" >
Taper
</text>
<text
@@ -1919,7 +2091,9 @@ even though the user gets a free copy.
left_delta="0"
name="scale_hole"
top_delta="0"
- width="150">
+ width="150"
+ font="DejaVu"
+ font.size="LSmall" >
Hole Size
</text>
<spinner
@@ -1935,7 +2109,9 @@ even though the user gets a free copy.
min_val="-1"
name="Taper Scale X"
top_pad="4"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
decimal_digits="2"
follows="left|top"
@@ -1949,7 +2125,9 @@ even though the user gets a free copy.
min_val="-1"
name="Taper Scale Y"
top_delta="0"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<text
type="string"
length="1"
@@ -1959,7 +2137,9 @@ even though the user gets a free copy.
left="125"
name="text topshear"
top_pad="5"
- width="141">
+ width="141"
+ font="DejaVu"
+ font.size="LSmall" >
Top Shear
</text>
<spinner
@@ -1976,7 +2156,9 @@ even though the user gets a free copy.
min_val="-0.5"
name="Shear X"
top_pad="4"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
decimal_digits="2"
follows="left|top"
@@ -1991,7 +2173,9 @@ even though the user gets a free copy.
min_val="-0.5"
name="Shear Y"
top_delta="0"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<text
visible="false"
type="string"
@@ -2002,7 +2186,9 @@ even though the user gets a free copy.
left="125"
name="advanced_cut"
top_pad="7"
- width="150">
+ width="150"
+ font="DejaVu"
+ font.size="LSmall" >
Profile Cut (begin/end)
</text>
<text
@@ -2015,7 +2201,9 @@ even though the user gets a free copy.
left_delta="0"
name="advanced_dimple"
top_delta="0"
- width="150">
+ width="150"
+ font="DejaVu"
+ font.size="LSmall" >
Dimple (begin/end)
</text>
<text
@@ -2027,7 +2215,9 @@ even though the user gets a free copy.
left_delta="0"
name="advanced_slice"
top_delta="0"
- width="150">
+ width="150"
+ font="DejaVu"
+ font.size="LSmall" >
Slice (begin/end)
</text>
<spinner
@@ -2042,7 +2232,9 @@ even though the user gets a free copy.
max_val="0.98"
name="Path Limit Begin"
top_pad="3"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -2055,7 +2247,9 @@ even though the user gets a free copy.
min_val="0.02"
name="Path Limit End"
top_delta="0"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<text
visible="false"
type="string"
@@ -2066,7 +2260,9 @@ even though the user gets a free copy.
left="125"
name="text taper2"
top_pad="7"
- width="150">
+ width="150"
+ font="DejaVu"
+ font.size="LSmall" >
Taper
</text>
<spinner
@@ -2083,7 +2279,9 @@ even though the user gets a free copy.
min_val="-1"
name="Taper X"
top_pad="3"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
visible="false"
decimal_digits="2"
@@ -2098,7 +2296,9 @@ even though the user gets a free copy.
min_val="-1"
name="Taper Y"
top_delta="0"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<text
visible="false"
type="string"
@@ -2109,7 +2309,9 @@ even though the user gets a free copy.
left="125"
name="text radius delta"
top_pad="7"
- width="78">
+ width="78"
+ font="DejaVu"
+ font.size="LSmall" >
Radius
</text>
<text
@@ -2121,7 +2323,9 @@ even though the user gets a free copy.
layout="topleft"
left_delta="78"
name="text revolutions"
- width="68">
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" >
Revolutions
</text>
<spinner
@@ -2135,7 +2339,9 @@ even though the user gets a free copy.
min_val="-1"
name="Radius Offset"
top_pad="4"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
visible="false"
decimal_digits="2"
@@ -2148,7 +2354,9 @@ even though the user gets a free copy.
min_val="1"
name="Revolutions"
top_delta="0"
- width="68" />
+ width="68"
+ font="DejaVu"
+ font.size="LSmall" />
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -2161,7 +2369,9 @@ even though the user gets a free copy.
tool_tip="Click to choose a picture"
top="70"
visible="false"
- width="145" />
+ width="145"
+ caption_text.font="DejaVu"
+ caption_text.font.size="LSmall" />
<check_box
height="19"
label="Mirror"
@@ -2171,7 +2381,9 @@ even though the user gets a free copy.
tool_tip="Flips sculpted prim along the X axis"
top_pad="8"
visible="false"
- width="130" />
+ width="130"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
height="19"
label="Inside-out"
@@ -2181,7 +2393,9 @@ even though the user gets a free copy.
tool_tip="Inverts the sculpted prims normals, making it appear inside-out"
top_pad="4"
visible="false"
- width="121" />
+ width="121"
+ font="DejaVu"
+ font.size="LSmall" />
<text
type="string"
length="1"
@@ -2192,7 +2406,9 @@ even though the user gets a free copy.
name="label sculpt type"
top_pad="10"
visible="false"
- width="130">
+ width="130"
+ font="DejaVu"
+ font.size="LSmall" >
Stitching type
</text>
<combo_box
@@ -2202,7 +2418,9 @@ even though the user gets a free copy.
name="sculpt type control"
top_pad="4"
visible="false"
- width="150">
+ width="150"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall" >
<combo_box.item
label="Sphere"
name="Sphere"
@@ -2259,7 +2477,9 @@ even though the user gets a free copy.
name="select_single"
top="5"
width="252"
- word_wrap="true">
+ word_wrap="true"
+ font="DejaVu"
+ font.size="LSmall" >
Select only one primitive to edit features.
</text>
<text
@@ -2271,7 +2491,9 @@ even though the user gets a free copy.
left="10"
name="edit_object"
top="5"
- width="252">
+ width="252"
+ font="DejaVu"
+ font.size="LSmall" >
Edit object features:
</text>
<check_box
@@ -2282,7 +2504,9 @@ even though the user gets a free copy.
name="Animated Mesh Checkbox Ctrl"
tool_tip="Allows rigged mesh objects to be animated independently"
top_pad="10"
- width="121" />
+ width="121"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
height="10"
label="Flexible Path"
@@ -2292,7 +2516,9 @@ even though the user gets a free copy.
name="Flexible1D Checkbox Ctrl"
tool_tip="Allows object to flex about the Z axis (Client-side only)"
top_pad="15"
- width="121" />
+ width="121"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -2305,7 +2531,9 @@ even though the user gets a free copy.
max_val="3"
name="FlexNumSections"
top_pad="10"
- width="128" />
+ width="128"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -2319,7 +2547,9 @@ even though the user gets a free copy.
min_val="-10"
name="FlexGravity"
top_pad="4"
- width="128" />
+ width="128"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -2332,7 +2562,9 @@ even though the user gets a free copy.
max_val="10"
name="FlexFriction"
top_pad="4"
- width="128" />
+ width="128"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -2345,7 +2577,9 @@ even though the user gets a free copy.
max_val="10"
name="FlexWind"
top_pad="4"
- width="128" />
+ width="128"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -2358,7 +2592,9 @@ even though the user gets a free copy.
max_val="10"
name="FlexTension"
top_pad="4"
- width="128" />
+ width="128"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -2372,7 +2608,9 @@ even though the user gets a free copy.
min_val="-10"
name="FlexForceX"
top_pad="4"
- width="128" />
+ width="128"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -2386,7 +2624,9 @@ even though the user gets a free copy.
min_val="-10"
name="FlexForceY"
top_pad="4"
- width="128" />
+ width="128"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -2400,7 +2640,9 @@ even though the user gets a free copy.
min_val="-10"
name="FlexForceZ"
top_pad="4"
- width="128" />
+ width="128"
+ font="DejaVu"
+ font.size="LSmall" />
<view_border
bevel_style="none"
follows="top|left"
@@ -2409,7 +2651,9 @@ even though the user gets a free copy.
left="8"
name="object_horizontal"
top_pad="10"
- width="278" />
+ width="278"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
height="16"
label="Light"
@@ -2418,7 +2662,9 @@ even though the user gets a free copy.
name="Light Checkbox Ctrl"
tool_tip="Causes object to emit light"
top_pad="8"
- width="60" />
+ width="60"
+ font="DejaVu"
+ font.size="LSmall" />
<color_swatch
can_apply_immediately="true"
color="0.5 0.5 0.5 1"
@@ -2430,7 +2676,9 @@ even though the user gets a free copy.
top_pad="-17"
name="colorswatch"
tool_tip="Click to open color picker"
- width="40" />
+ width="40"
+ font="DejaVu"
+ font.size="LSmall" />
<texture_picker
allow_no_texture="true"
top_delta="0"
@@ -2443,7 +2691,9 @@ even though the user gets a free copy.
mouse_opaque="true"
name="light texture control"
tool_tip="Click to choose a projection image (only has effect with deferred rendering enabled)"
- width="32" />
+ width="32"
+ caption_text.font="DejaVu"
+ caption_text.font.size="LSmall" />
<menu_button
menu_filename="menu_copy_paste_light.xml"
follows="top|left"
@@ -2467,7 +2717,9 @@ even though the user gets a free copy.
left="10"
name="Light Intensity"
top_pad="26"
- width="128" />
+ width="128"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner bottom_delta="0"
decimal_digits="3"
follows="left|top"
@@ -2481,7 +2733,9 @@ even though the user gets a free copy.
min_val="0"
mouse_opaque="true"
name="Light FOV"
- width="120" />
+ width="120"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner follows="left|top"
height="19"
initial_value="5"
@@ -2492,7 +2746,9 @@ even though the user gets a free copy.
max_val="20"
name="Light Radius"
top_pad="3"
- width="128" />
+ width="128"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner bottom_delta="0"
decimal_digits="3"
follows="left|top"
@@ -2506,7 +2762,9 @@ even though the user gets a free copy.
min_val="-20"
mouse_opaque="true"
name="Light Focus"
- width="120" />
+ width="120"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner follows="left|top"
height="19"
increment="0.25"
@@ -2518,7 +2776,9 @@ even though the user gets a free copy.
max_val="2"
name="Light Falloff"
top_pad="3"
- width="128" />
+ width="128"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner bottom_delta="0"
decimal_digits="3"
follows="left|top"
@@ -2532,7 +2792,9 @@ even though the user gets a free copy.
min_val="0"
mouse_opaque="true"
name="Light Ambiance"
- width="120" />
+ width="120"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
height="16"
label="Reflection Probe"
@@ -2541,15 +2803,19 @@ even though the user gets a free copy.
name="Reflection Probe"
tool_tip="Adjusts how objects within this volume receive reflections when PBR is enabled"
top_pad="10"
- width="60" />
+ width="60"
+ font="DejaVu"
+ font.size="LSmall" />
<combo_box
height="19"
top_delta="0"
- left="144"
+ left="144"
follows="left|top"
name="Probe Volume Type"
tool_tip="Choose the probe influence volume"
- width="140">
+ width="140"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall" >
<combo_box.item
label="Sphere"
name="Sphere"
@@ -2568,7 +2834,9 @@ even though the user gets a free copy.
name="Probe Dynamic"
tool_tip="When enabled, Avatars will appear in reflections within this probe's influence volume."
bottom_delta="19"
- width="60" />
+ width="60"
+ font="DejaVu"
+ font.size="LSmall" />
<text
bottom_delta="-8"
@@ -2580,7 +2848,9 @@ even though the user gets a free copy.
left="10"
name="Probe Update Label"
text_readonly_color="LabelDisabledColor"
- width="100">
+ width="100"
+ font="DejaVu"
+ font.size="LSmall" >
Probe Update
</text>
<combo_box
@@ -2590,7 +2860,9 @@ even though the user gets a free copy.
follows="left|top"
name="Probe Update Type"
tool_tip="Determines how the probe updates. Static updates the slowest and without avatars. Dynamic updates more frequently, with avatars visible in the probes. Mirror (Environment) turns this probe into a realtime planar projected probe that only reflects the environment, but does not calculate ambiance. Mirror (Everything) is similar to Mirror (Environment), but it reflects particles and avatars."
- width="140">
+ width="140"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall" >
<combo_box.item
label="Static"
name="Static"
@@ -2621,7 +2893,9 @@ even though the user gets a free copy.
min_val="0"
mouse_opaque="true"
name="Probe Ambiance"
- width="120" />
+ width="120"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner bottom_delta="0"
decimal_digits="3"
follows="left|top"
@@ -2635,7 +2909,9 @@ even though the user gets a free copy.
min_val="0"
mouse_opaque="true"
name="Probe Near Clip"
- width="120" />
+ width="120"
+ font="DejaVu"
+ font.size="LSmall" />
<text
type="string"
length="1"
@@ -2644,7 +2920,9 @@ even though the user gets a free copy.
layout="topleft"
name="label physicsshapetype"
top="38"
- width="121">
+ width="121"
+ font="DejaVu"
+ font.size="LSmall" >
Physics Shape Type:
</text>
<combo_box
@@ -2654,13 +2932,17 @@ even though the user gets a free copy.
follows="left|top"
name="Physics Shape Type Combo Ctrl"
tool_tip="Choose the physics shape type"
- width="108"/>
+ width="108"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall" />
<combo_box
height="19"
layout="topleft"
name="material"
top_pad="5"
- width="150">
+ width="150"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall" >
<combo_box.item
label="Stone"
name="Stone"
@@ -2703,7 +2985,9 @@ even though the user gets a free copy.
max_val="28"
name="Physics Gravity"
top_pad="10"
- width="132" />
+ width="132"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
@@ -2718,7 +3002,9 @@ even though the user gets a free copy.
min_val="0"
name="Physics Friction"
top_pad="4"
- width="132" />
+ width="132"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
@@ -2734,7 +3020,9 @@ even though the user gets a free copy.
min_val="1"
name="Physics Density"
top_pad="4"
- width="132" />
+ width="132"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
@@ -2749,7 +3037,9 @@ even though the user gets a free copy.
min_val="0"
name="Physics Restitution"
top_pad="8"
- width="132" />
+ width="132"
+ font="DejaVu"
+ font.size="LSmall" />
</panel>
<panel
label="Texture"
@@ -2777,7 +3067,10 @@ even though the user gets a free copy.
left="8"
name="button new script"
top="10"
- width="134" />
+ width="134"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1" />
<button
follows="left|top"
height="23"
@@ -2785,7 +3078,10 @@ even though the user gets a free copy.
layout="topleft"
left_pad="8"
name="button permissions"
- width="134" />
+ width="134"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1" />
<filter_editor
follows="left|top|right"
label="Enter filter text"
@@ -2822,7 +3118,8 @@ even though the user gets a free copy.
<text
type="string"
length="1"
- font="SansSerifBig"
+ font="DejaVu"
+ font.size="Small"
follows="left|top"
height="19"
layout="topleft"
@@ -2841,7 +3138,9 @@ even though the user gets a free copy.
left="30"
name="label_area_price"
top="48"
- width="150">
+ width="150"
+ font="DejaVu"
+ font.size="LSmall" >
Price: L$[PRICE] for [AREA] m²
</text>
<text
@@ -2853,7 +3152,9 @@ even though the user gets a free copy.
left_delta="0"
name="label_area"
top_delta="0"
- width="150">
+ width="150"
+ font="DejaVu"
+ font.size="LSmall" >
Area: [AREA] m²
</text>
<button
@@ -2865,7 +3166,10 @@ even though the user gets a free copy.
left_delta="0"
name="button about land"
top_pad="4"
- width="125" />
+ width="125"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1" />
<check_box
control_name="ShowParcelOwners"
height="19"
@@ -2875,11 +3179,14 @@ even though the user gets a free copy.
name="checkbox show owners"
tool_tip="Colorize the parcels according to the type of owner: &#10;&#10;Green = Your land &#10;Aqua = Your group&apos;s land &#10;Red = Owned by others &#10;Yellow = For sale &#10;Purple = For auction &#10;Grey = Public"
top_pad="8"
- width="205" />
+ width="205"
+ font="DejaVu"
+ font.size="LSmall" />
<text
type="string"
length="1"
- font="SansSerifBig"
+ font="DejaVu"
+ font.size="Small"
follows="left|top"
height="19"
layout="topleft"
@@ -2898,7 +3205,10 @@ even though the user gets a free copy.
left="30"
name="button subdivide land"
top="172"
- width="125" />
+ width="125"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1" />
<button
follows="left|top"
height="23"
@@ -2908,11 +3218,15 @@ even though the user gets a free copy.
left_delta="0"
name="button join land"
top_pad="4"
- width="125" />
+ width="125"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1" />
<text
type="string"
length="1"
- font="SansSerifBig"
+ font="DejaVu"
+ font.size="Small"
follows="left|top"
height="19"
layout="topleft"
@@ -2931,7 +3245,10 @@ even though the user gets a free copy.
left="30"
name="button buy land"
top="276"
- width="125" />
+ width="125"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1" />
<button
follows="left|top"
height="23"
@@ -2941,7 +3258,10 @@ even though the user gets a free copy.
left_delta="0"
name="button abandon land"
top_pad="4"
- width="125" />
+ width="125"
+ font="DejaVu"
+ font.size="LSmall"
+ pad_bottom="1" />
</panel>
<!-- end of tabs -->
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_toybox.xml b/indra/newview/skins/default/xui/en/floater_toybox.xml
index 7fe9830d23..d75d2e0db7 100644
--- a/indra/newview/skins/default/xui/en/floater_toybox.xml
+++ b/indra/newview/skins/default/xui/en/floater_toybox.xml
@@ -16,7 +16,6 @@
width="650">
<text
follows="left|top"
- font="SansSerifMedium"
valign="top"
halign="left"
height="20"
@@ -31,7 +30,6 @@
</text>
<text
follows="left|top"
- font="SansSerifMedium"
valign="top"
halign="left"
height="20"
@@ -49,7 +47,7 @@
button_display_mode="icons_with_text"
follows="all"
left="20"
- button_icon_and_text.button_width.max="140"
+ button_icon_and_text.button_width.max="172"
button_icon_and_text.button_width.min="70"
name="toybox_toolbar"
pad_left="5"
diff --git a/indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml b/indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml
index c0d260ef59..279a05748d 100644
--- a/indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml
+++ b/indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml
@@ -22,7 +22,7 @@
increment="0.025"
initial_value="0.5"
label="Voice Chat"
- label_width="60"
+ label_width="62"
layout="topleft"
left="15"
top="50"
diff --git a/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml b/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml
index 4e75b2b29c..fdc1e64e05 100644
--- a/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml
+++ b/indra/newview/skins/default/xui/en/floater_whitelist_entry.xml
@@ -10,12 +10,12 @@
title="WHITELIST ENTRY"
width="390">
- <text type="string" length="1" bottom="20" follows="top|left" height="15" layout="topleft"
- left="10" name="media_label" top="20">
+ <text type="string" length="1" follows="top|left|right" height="30" layout="topleft"
+ left="10" name="media_label" top="20" right="-10" word_wrap="true">
Enter a URL or URL pattern to add to the list of allowed domains
</text>
- <line_editor bottom_delta="40" enabled="true" follows="left|top" font="SansSerif"
+ <line_editor bottom_delta="15" enabled="true" follows="left|top" font="SansSerif"
height="20" left="10" name="whitelist_entry"
tool_tip="Enter a URL or URL pattern to White List"
width="350" />
diff --git a/indra/newview/skins/default/xui/en/floater_world_map.xml b/indra/newview/skins/default/xui/en/floater_world_map.xml
index b0635a2229..4e64b09c1e 100644
--- a/indra/newview/skins/default/xui/en/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/en/floater_world_map.xml
@@ -167,7 +167,7 @@
follows="top|right"
halign="left"
height="16"
- top_delta="-2"
+ top_delta="-5"
left_pad="7"
layout="topleft"
name="person_label"
@@ -181,9 +181,9 @@
layout="topleft"
left="3"
name="infohub_chk"
- top_pad="3"
+ top_pad="7"
width="22" />
- <icon
+ <icon
follows="top|right"
height="16"
image_name="map_infohub.tga"
@@ -191,7 +191,7 @@
left_pad="0"
mouse_opaque="true"
name="infohub"
- top_delta="0"
+ top_delta="-3"
width="16" />
<text
type="string"
@@ -199,7 +199,7 @@
follows="top|right"
halign="left"
height="16"
- top_delta="2"
+ top_delta="0"
left_pad="3"
layout="topleft"
name="infohub_label"
@@ -213,7 +213,7 @@
layout="topleft"
left="3"
name="land_for_sale_chk"
- top_pad="2"
+ top_pad="8"
width="22" />
<icon
follows="top|right"
@@ -222,16 +222,16 @@
layout="topleft"
mouse_opaque="true"
name="landforsale"
- top_delta="0"
+ top_delta="-3"
left_pad="0"
width="16" />
- <text
+ <text
type="string"
length="1"
follows="top|right"
halign="left"
height="16"
- top_delta="2"
+ top_delta="1"
left_pad="3"
layout="topleft"
name="land_sale_label"
@@ -257,7 +257,7 @@
layout="topleft"
left_pad="0"
name="auction_label"
- top_delta="3"
+ top_delta="1"
width="170">
land auction
</text>
@@ -270,7 +270,7 @@
mouse_opaque="true"
name="square2_owner"
left="20"
- top_pad="-5"
+ top_pad="-2"
width="16" />
<text
type="string"
@@ -280,7 +280,7 @@
layout="topleft"
left_pad="0"
name="by_owner_label"
- top_delta="3"
+ top_delta="0"
width="100">
by owner
</text>
@@ -290,7 +290,7 @@
control_name="MapShowGridCoords"
layout="topleft"
follows="top|right"
- top_pad="2"
+ top_pad="5"
left="3"
height="16"
width="22"
@@ -300,8 +300,8 @@
type="string"
layout="topleft"
follows="top|right"
- top_delta="2"
- left_pad="3"
+ top_delta="-2"
+ left_pad="2"
height="16"
width="220"
halign="left"
@@ -357,7 +357,7 @@
height="16"
layout="topleft"
left="135"
- top_pad="1"
+ top_pad="5"
name="event_chk"
width="22" />
<icon
@@ -367,6 +367,7 @@
layout="topleft"
mouse_opaque="true"
name="event"
+ top_delta="-2"
left_pad="0"
width="18" />
<text
@@ -375,7 +376,7 @@
follows="top|right"
halign="left"
height="16"
- top_delta="2"
+ top_delta="0"
left_pad="3"
layout="topleft"
name="pg_label"
@@ -391,7 +392,7 @@
layout="topleft"
left="135"
name="events_mature_chk"
- top_pad="3"
+ top_pad="7"
width="22" />
<icon
follows="top|right"
@@ -400,16 +401,16 @@
layout="topleft"
mouse_opaque="true"
name="events_mature_icon"
- top_delta="0"
+ top_delta="-2"
left_pad="0"
width="18" />
- <text
+ <text
type="string"
length="1"
follows="top|right"
halign="left"
height="16"
- top_delta="2"
+ top_delta="0"
left_pad="3"
layout="topleft"
name="events_mature_label"
@@ -424,7 +425,7 @@
layout="topleft"
left="135"
name="events_adult_chk"
- top_pad="3"
+ top_pad="7"
width="22" />
<icon
follows="top|right"
@@ -434,15 +435,15 @@
left_pad="0"
mouse_opaque="true"
name="events_adult_icon"
- top_delta="0"
+ top_delta="-2"
width="18" />
- <text
+ <text
type="string"
length="1"
follows="top|right"
halign="left"
height="16"
- top_delta="2"
+ top_delta="0"
left_pad="3"
layout="topleft"
name="events_adult_label"
diff --git a/indra/newview/skins/default/xui/en/fonts.xml b/indra/newview/skins/default/xui/en/fonts.xml
index 45ec1e27f1..1ad01ee120 100644
--- a/indra/newview/skins/default/xui/en/fonts.xml
+++ b/indra/newview/skins/default/xui/en/fonts.xml
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<fonts>
- <font name="default" comment="default font files (global fallbacks)">
- <file>DejaVuSans.ttf</file>
+ <font
+ name="default"
+ comment="default font files (global fallbacks)">
+ <file load_collection="true" font_weight="400">InterVariableFont.ttf</file>
+ <file size_delta="-0.5">DejaVuSans.ttf</file>
<file functor="is_emoji">TwemojiSVG.ttf</file>
<os name="Windows">
<file>meiryo.TTC</file>
@@ -31,9 +34,11 @@
</os>
</font>
- <font name="SansSerifBold"
- comment="Name of bold sans-serif font">
- <file>DejaVuSans-Bold.ttf</file>
+ <font
+ name="SansSerifBold"
+ comment="Name of bold sans-serif font">
+ <file load_collection="true" flags="bold" font_weight="700">InterVariableFont.ttf</file>
+ <file size_delta="-0.5">DejaVuSans-Bold.ttf</file>
<os name="Windows">
<file>arialbd.ttf</file>
</os>
@@ -42,8 +47,11 @@
</os>
</font>
- <font name="SansSerif" comment="Name of san-serif font (Truetype file name)">
- <file>DejaVuSans.ttf</file>
+ <font
+ name="SansSerif"
+ comment="Name of san-serif font (Truetype file name)">
+ <file load_collection="true" font_weight="400">InterVariableFont.ttf</file>
+ <file size_delta="-0.5">DejaVuSans.ttf</file>
<os name="Windows">
<file>arial.ttf</file>
</os>
@@ -52,31 +60,38 @@
</os>
</font>
- <font name="SansSerif"
- comment="Name of bold sans-serif font"
- font_style="BOLD">
- <file>DejaVuSans-Bold.ttf</file>
+ <font
+ name="SansSerif"
+ comment="Name of bold sans-serif font"
+ font_style="BOLD">
+ <file load_collection="true" flags="bold" font_weight="700">InterVariableFont.ttf</file>
+ <file size_delta="-0.5">DejaVuSans-Bold.ttf</file>
</font>
- <font name="SansSerif"
- comment="Name of italic sans-serif font"
- font_style="ITALIC">
- <file>DejaVuSans-Oblique.ttf</file>
+ <font
+ name="SansSerif"
+ comment="Name of italic sans-serif font"
+ font_style="ITALIC">
+ <file load_collection="true" font_weight="400">InterItalicVariableFont.ttf</file>
+ <file size_delta="-0.5">DejaVuSans-Oblique.ttf</file>
</font>
- <font name="SansSerif"
- comment="Name of bold italic sans-serif font"
- font_style="BOLD|ITALIC">
- <file>DejaVuSans-BoldOblique.ttf</file>
+ <font
+ name="SansSerif"
+ comment="Name of bold italic sans-serif font"
+ font_style="BOLD|ITALIC">
+ <file load_collection="true" flags="bold" font_weight="700">InterItalicVariableFont.ttf</file>
+ <file size_delta="-0.5">DejaVuSans-BoldOblique.ttf</file>
</font>
<font name="Emoji"
comment="Name of emoji font">
<file>TwemojiSVG.ttf</file>
</font>
-
- <font name="Monospace"
- comment="Name of monospace font">
+
+ <font
+ name="Monospace"
+ comment="Name of monospace font">
<file>DejaVuSansMono.ttf</file>
</font>
@@ -103,9 +118,11 @@
<file>DejaVuSans-BoldOblique.ttf</file>
</font>
- <font name="Helvetica"
- comment="Name of Helvetica font">
- <file>DejaVuSans.ttf</file>
+ <font
+ name="Helvetica"
+ comment="Name of Helvetica font">
+ <file font_weight="400">InterVariableFont.ttf</file>
+ <file size_delta="-0.5">DejaVuSans.ttf</file>
<os name="Windows">
<file>arial.ttf</file>
</os>
@@ -114,10 +131,12 @@
</os>
</font>
- <font name="Helvetica"
- comment="Name of Helvetica font (bold)"
- font_style="BOLD">
- <file>DejaVuSans-Bold.ttf</file>
+ <font
+ name="Helvetica"
+ comment="Name of Helvetica font (bold)"
+ font_style="BOLD">
+ <file flags="bold" font_weight="700">InterVariableFont.ttf</file>
+ <file size_delta="-0.5">DejaVuSans-Bold.ttf</file>
<os name="Windows">
<file>arialbd.ttf</file>
</os>
@@ -126,10 +145,12 @@
</os>
</font>
- <font name="Helvetica"
- comment="Name of Helvetica font (italic)"
- font_style="ITALIC">
- <file>DejaVuSans-Oblique.ttf</file>
+ <font
+ name="Helvetica"
+ comment="Name of Helvetica font (italic)"
+ font_style="ITALIC">
+ <file font_weight="400">InterItalicVariableFont.ttf</file>
+ <file size_delta="-0.5">DejaVuSans-Oblique.ttf</file>
<os name="Windows">
<file>ariali.ttf</file>
</os>
@@ -138,10 +159,12 @@
</os>
</font>
- <font name="Helvetica"
- comment="Name of Helvetica font (bold italic)"
- font_style="BOLD|ITALIC">
- <file>DejaVuSans-BoldOblique.ttf</file>
+ <font
+ name="Helvetica"
+ comment="Name of Helvetica font (bold italic)"
+ font_style="BOLD|ITALIC">
+ <file font_weight="800">InterItalicVariableFont.ttf</file>
+ <file size_delta="-0.5">DejaVuSans-BoldOblique.ttf</file>
<os name="Windows">
<file>arialbi.ttf</file>
</os>
@@ -150,33 +173,38 @@
</os>
</font>
- <font name="OverrideTest"
- comment="Name of font to test overriding">
+ <font
+ name="OverrideTest"
+ comment="Name of font to test overriding">
<file>times.ttf</file>
- <file>DejaVuSans.ttf</file>
+ <file font_weight="400">InterVariableFont.ttf</file>
</font>
<font_size name="Monospace"
- comment="Size for monospaced font (points, or 1/72 of an inch)"
- size="8.0"
- />
+ comment="Size for monospaced font (points, or 1/72 of an inch)"
+ size="8.0"
+ />
<font_size name="Huge"
- comment="Size of huge font (points, or 1/72 of an inch)"
- size="16.0"
- />
+ comment="Size of huge font (points, or 1/72 of an inch)"
+ size="16.0"
+ />
<font_size name="Large"
- comment="Size of large font (points, or 1/72 of an inch)"
- size="10.6"
- />
+ comment="Size of large font (points, or 1/72 of an inch)"
+ size="11.0"
+ />
<font_size name="Medium"
- comment="Size of medium font (points, or 1/72 of an inch)"
- size="8.6"
- />
+ comment="Size of medium font (points, or 1/72 of an inch)"
+ size="10"
+ />
<font_size name="Small"
- comment="Size of small font (points, or 1/72 of an inch)"
- size="7.6"
- />
- <font_size name="SmallLSL"
+ comment="Size of small font (points, or 1/72 of an inch)"
+ size="9"
+ />
+ <font_size name="LSmall"
+ comment="Legacy size of small font (points, or 1/72 of an inch)"
+ size="7.6"
+ />
+<font_size name="SmallLSL"
comment="Size of small font for LSL editor (points, or 1/72 of an inch)"
size="7"
/>
diff --git a/indra/newview/skins/default/xui/en/inspect_group.xml b/indra/newview/skins/default/xui/en/inspect_group.xml
index c190d9610f..226454df7c 100644
--- a/indra/newview/skins/default/xui/en/inspect_group.xml
+++ b/indra/newview/skins/default/xui/en/inspect_group.xml
@@ -9,7 +9,7 @@
bg_opaque_image="Inspector_Background"
can_close="false"
can_minimize="false"
- height="158"
+ height="188"
layout="topleft"
name="inspect_group"
single_instance="true"
@@ -47,7 +47,7 @@
</text>
<text
follows="all"
- height="45"
+ height="65"
left="8"
name="group_details"
use_ellipses="true"
@@ -80,7 +80,7 @@ L$123 to join
height="23"
label="Join"
left="8"
- top="125"
+ top="156"
name="join_btn"
width="103"
commit_callback.function="InspectGroup.Join"/>
@@ -89,7 +89,7 @@ L$123 to join
height="23"
label="Leave"
left="8"
- top="125"
+ top="156"
name="leave_btn"
width="103"
commit_callback.function="InspectGroup.Leave"/>
@@ -98,7 +98,7 @@ L$123 to join
height="23"
label="View Profile"
name="view_profile_btn"
- top="125"
+ top="156"
left="117"
width="103"
commit_callback.function="InspectGroup.ViewProfile" />
diff --git a/indra/newview/skins/default/xui/en/menu_conversation.xml b/indra/newview/skins/default/xui/en/menu_conversation.xml
index 62cdaa5886..5a28f0dde5 100644
--- a/indra/newview/skins/default/xui/en/menu_conversation.xml
+++ b/indra/newview/skins/default/xui/en/menu_conversation.xml
@@ -176,57 +176,60 @@
<on_click function="Group.DoToSelected" parameter="leave_group"/>
<on_enable function="Avatar.EnableItem" parameter="can_leave_group" />
</menu_item_call>
- <menu_item_separator layout="topleft" name="Moderator Options Separator"/>
- <context_menu
- label="Moderator Options"
- layout="topleft"
- name="Moderator Options">
- <menu_item_check
- label="Allow text chat"
- layout="topleft"
- name="AllowTextChat">
- <on_check function="Avatar.CheckItem" parameter="is_allowed_text_chat" />
- <on_click function="Avatar.DoToSelected" parameter="toggle_allow_text_chat" />
- <on_enable function="Avatar.EnableItem" parameter="can_allow_text_chat" />
- </menu_item_check>
- <menu_item_separator layout="topleft" name="moderate_voice_separator" />
- <menu_item_call
- label="Mute this participant"
- layout="topleft"
- name="ModerateVoiceMuteSelected">
- <on_click function="Avatar.DoToSelected" parameter="selected" />
- <on_enable function="Avatar.EnableItem" parameter="can_mute" />
- <on_visible function="Avatar.VisibleItem" parameter="show_mute" />
- </menu_item_call>
+ <menu_item_separator layout="topleft" name="Moderator Options Separator"/>
+ <context_menu
+ label="Moderator Options"
+ layout="topleft"
+ name="Moderator Options">
+ <menu_item_check
+ label="Allow text chat"
+ layout="topleft"
+ name="AllowTextChat">
+ <on_check function="Avatar.CheckItem" parameter="is_allowed_text_chat" />
+ <on_click function="Avatar.DoToSelected" parameter="toggle_allow_text_chat" />
+ <on_enable function="Avatar.EnableItem" parameter="can_allow_text_chat" />
+ <on_visible function="Avatar.VisibleItem" parameter="can_allow_text_chat" />
+ </menu_item_check>
+ <menu_item_separator layout="topleft" name="moderate_voice_separator">
+ <on_visible function="Avatar.VisibleItem" parameter="can_allow_text_chat" />
+ </menu_item_separator>
+ <menu_item_call
+ label="Mute this participant"
+ layout="topleft"
+ name="ModerateVoiceMuteSelected">
+ <on_click function="Avatar.DoToSelected" parameter="selected" />
+ <on_enable function="Avatar.EnableItem" parameter="can_mute" />
+ <on_visible function="Avatar.VisibleItem" parameter="show_mute" />
+ </menu_item_call>
+ <menu_item_call
+ label="Unmute this participant"
+ layout="topleft"
+ name="ModerateVoiceUnMuteSelected">
+ <on_click function="Avatar.DoToSelected" parameter="selected" />
+ <on_enable function="Avatar.EnableItem" parameter="can_unmute" />
+ <on_visible function="Avatar.VisibleItem" parameter="show_unmute" />
+ </menu_item_call>
+ <menu_item_call
+ label="Mute everyone"
+ layout="topleft"
+ name="ModerateVoiceMute">
+ <on_click function="Avatar.DoToSelected" parameter="mute_all" />
+ <on_enable function="Avatar.EnableItem" parameter="can_moderate_voice" />
+ </menu_item_call>
+ <menu_item_call
+ label="Unmute everyone"
+ layout="topleft"
+ name="ModerateVoiceUnmute">
+ <on_click function="Avatar.DoToSelected" parameter="unmute_all" />
+ <on_enable function="Avatar.EnableItem" parameter="can_moderate_voice" />
+ </menu_item_call>
+ </context_menu>
+ <menu_item_separator layout="topleft" name="Group Ban Separator"/>
<menu_item_call
- label="Unmute this participant"
- layout="topleft"
- name="ModerateVoiceUnMuteSelected">
- <on_click function="Avatar.DoToSelected" parameter="selected" />
- <on_enable function="Avatar.EnableItem" parameter="can_unmute" />
- <on_visible function="Avatar.VisibleItem" parameter="show_unmute" />
- </menu_item_call>
- <menu_item_call
- label="Mute everyone"
- layout="topleft"
- name="ModerateVoiceMute">
- <on_click function="Avatar.DoToSelected" parameter="mute_all" />
- <on_enable function="Avatar.EnableItem" parameter="can_moderate_voice" />
- </menu_item_call>
- <menu_item_call
- label="Unmute everyone"
- layout="topleft"
- name="ModerateVoiceUnmute">
- <on_click function="Avatar.DoToSelected" parameter="unmute_all" />
- <on_enable function="Avatar.EnableItem" parameter="can_moderate_voice" />
- </menu_item_call>
- </context_menu>
- <menu_item_separator layout="topleft" name="Group Ban Separator"/>
- <menu_item_call
- label="Ban member"
- layout="topleft"
- name="BanMember">
- <on_click function="Avatar.DoToSelected" parameter="ban_member" />
- <on_enable function="Avatar.EnableItem" parameter="can_ban_member" />
- </menu_item_call>
+ label="Ban member"
+ layout="topleft"
+ name="BanMember">
+ <on_click function="Avatar.DoToSelected" parameter="ban_member" />
+ <on_enable function="Avatar.EnableItem" parameter="can_ban_member" />
+ </menu_item_call>
</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_conversation_log_view.xml b/indra/newview/skins/default/xui/en/menu_conversation_log_view.xml
index 864bec5d9a..1e10a984da 100644
--- a/indra/newview/skins/default/xui/en/menu_conversation_log_view.xml
+++ b/indra/newview/skins/default/xui/en/menu_conversation_log_view.xml
@@ -34,6 +34,16 @@
function="CallLog.Check"
parameter="sort_friends_on_top" />
</menu_item_check>
+ <menu_item_check
+ label="Show muted"
+ name="show_muted">
+ <on_click
+ function="CallLog.Action"
+ parameter="show_blocked" />
+ <on_check
+ function="CallLog.Check"
+ parameter="show_blocked" />
+ </menu_item_check>
<menu_item_separator />
<menu_item_call
label="View Nearby chat history..."
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index d616d474c0..42ec875bcd 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -9235,6 +9235,23 @@ Your voice has been muted by moderator.
</notification>
<notification
+ icon="notifytip.tga"
+ name="NearbyVoiceMutedByModerator"
+ type="notifytip">
+ The moderator has muted your voice chat.
+People in this location will not hear you if you speak.
+ <tag>voice</tag>
+ </notification>
+
+ <notification
+ icon="notifytip.tga"
+ name="NearbyVoiceUnmutedByModerator"
+ type="notifytip">
+ Your voice chat can now be heard by people in this location.
+ <tag>voice</tag>
+ </notification>
+
+ <notification
icon="alertmodal.tga"
name="FailedToGetBenefits"
type="alertmodal">
diff --git a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
index ca6e94397d..f9b65e3f13 100644
--- a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
@@ -61,7 +61,7 @@
left_pad="5"
name="avatar_name"
parse_urls="false"
- top="6"
+ top="5"
use_ellipses="true"
value="(loading)"
width="180" />
diff --git a/indra/newview/skins/default/xui/en/panel_blocked_list_item.xml b/indra/newview/skins/default/xui/en/panel_blocked_list_item.xml
index 5ac0bf54de..6b4312a22a 100644
--- a/indra/newview/skins/default/xui/en/panel_blocked_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_blocked_list_item.xml
@@ -65,7 +65,7 @@
left_pad="5"
name="item_name"
parse_urls="false"
- top="6"
+ top="4"
use_ellipses="true"
width="180" />
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_chat_header.xml b/indra/newview/skins/default/xui/en/panel_chat_header.xml
index 4f48911376..dde2df7128 100644
--- a/indra/newview/skins/default/xui/en/panel_chat_header.xml
+++ b/indra/newview/skins/default/xui/en/panel_chat_header.xml
@@ -23,7 +23,7 @@
<text
parse_urls="false"
allow_scroll="false"
- v_pad = "6"
+ v_pad = "4"
read_only = "true"
follows="left|right"
font.style="BOLD"
@@ -49,7 +49,7 @@
left_pad="5"
name="time_box"
right="-5"
- top="7"
+ top="5"
value="23:30"
width="110" />
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_chiclet_bar.xml b/indra/newview/skins/default/xui/en/panel_chiclet_bar.xml
index 5406497930..c43f82c0f1 100644
--- a/indra/newview/skins/default/xui/en/panel_chiclet_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_chiclet_bar.xml
@@ -109,7 +109,7 @@
image_overlay_alignment="center"
image_pressed="WellButton_Lit"
image_pressed_selected="WellButton_Lit_Selected"
- image_selected="PushButton_Press"
+ image_selected="PushButton_Selected"
label_color="Black"
left="0"
name="Unread"
diff --git a/indra/newview/skins/default/xui/en/panel_conversation_list_item.xml b/indra/newview/skins/default/xui/en/panel_conversation_list_item.xml
index 7902588598..90e367543e 100644
--- a/indra/newview/skins/default/xui/en/panel_conversation_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_conversation_list_item.xml
@@ -78,7 +78,7 @@
left="5"
name="conversation_title"
parse_urls="false"
- top="6"
+ top="4"
use_ellipses="true"
value="(loading)"
width="35" />
@@ -86,6 +86,7 @@
auto_update="true"
follows="top|right"
draw_border="false"
+ top="6"
height="16"
layout="topleft"
left_pad="5"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_shape.xml b/indra/newview/skins/default/xui/en/panel_edit_shape.xml
index c1d743c3da..2bd25b43bd 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_shape.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_shape.xml
@@ -15,7 +15,7 @@
<string name="height_value_label_color" translate="false">White</string>
<text
follows="top|left|right"
- font="SansSerifSmallBold"
+ font="SansSerifSmall"
halign="right"
height="12"
layout="topleft"
@@ -36,7 +36,7 @@
layout="topleft"
left="10"
name="accordion_panel"
- top_pad="0"
+ top_pad="5"
width="313">
<accordion
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_experience_search.xml b/indra/newview/skins/default/xui/en/panel_experience_search.xml
index bb07476ad0..7867361623 100644
--- a/indra/newview/skins/default/xui/en/panel_experience_search.xml
+++ b/indra/newview/skins/default/xui/en/panel_experience_search.xml
@@ -47,12 +47,14 @@
<text
name="lbl name part"
left="0"
+ top_pad="1"
follows="top|left|right"
right="-1">
Enter part of the name:
</text>
<line_editor
left="0"
+ top_pad="9"
follows="left|top|right"
name="edit"
height="18"
@@ -121,7 +123,7 @@
draw_heading="true"
left="0"
right="-1"
- height="239"
+ height="236"
top_pad="4"
follows="all"
column_padding="5"
diff --git a/indra/newview/skins/default/xui/en/panel_gltf_material.xml b/indra/newview/skins/default/xui/en/panel_gltf_material.xml
index 45df40bc05..697c6e60b7 100644
--- a/indra/newview/skins/default/xui/en/panel_gltf_material.xml
+++ b/indra/newview/skins/default/xui/en/panel_gltf_material.xml
@@ -7,7 +7,7 @@
top="0"
left="0"
height="768"
- width="247">
+ width="257">
<check_box
follows="left|top"
layout="topleft"
@@ -20,7 +20,7 @@
<panel
border="true"
follows="left|top"
- width="246"
+ width="256"
height="196"
layout="topleft"
left="1"
@@ -175,7 +175,7 @@
<panel
border="true"
follows="left|top"
- width="246"
+ width="256"
height="175"
layout="topleft"
left="1"
@@ -252,7 +252,7 @@
layout="topleft"
left_delta="0"
top_pad="5"
- width="96"
+ width="105"
name="roughness_factor_lbl">
Roughness Factor
</text>
@@ -273,7 +273,7 @@
<panel
border="true"
follows="left|top"
- width="246"
+ width="256"
height="175"
layout="topleft"
left="1"
@@ -343,7 +343,7 @@
<panel
border="true"
follows="left|top"
- width="246"
+ width="256"
height="175"
layout="topleft"
left="1"
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 74bc7736f9..260dc02ae3 100644
--- a/indra/newview/skins/default/xui/en/panel_group_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_general.xml
@@ -64,8 +64,7 @@ Hover your mouse over the options for more help.
use_ellipses="true"
width="168" />
<text
- font="SansSerifMedium"
- text_color="white"
+ text_color="white"
type="string"
follows="left|top"
height="16"
diff --git a/indra/newview/skins/default/xui/en/panel_group_list_item.xml b/indra/newview/skins/default/xui/en/panel_group_list_item.xml
index ff6af88707..dff00e4e60 100644
--- a/indra/newview/skins/default/xui/en/panel_group_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_list_item.xml
@@ -44,7 +44,7 @@
layout="topleft"
left_pad="5"
name="group_name"
- top="6"
+ top="4"
use_ellipses="true"
value="Unknown"
width="242" />
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 1162dcf20d..2ecc4585ba 100644
--- a/indra/newview/skins/default/xui/en/panel_group_notices.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_notices.xml
@@ -28,7 +28,7 @@ You can turn off Notices on the General tab.
left="5"
name="lbl2"
right="-1"
- top="5"
+ top="3"
width="300">
Notices are kept for 14 days.
Maximum 200 per group daily
@@ -42,7 +42,7 @@ Maximum 200 per group daily
left="0"
right="-1"
name="notice_list"
- top_pad="0"
+ top_pad="6"
width="304">
<scroll_list.columns
label=""
@@ -276,7 +276,6 @@ Maximum 200 per group daily
width="313">
<text
type="string"
- font="SansSerifMedium"
height="16"
layout="topleft"
left="10"
diff --git a/indra/newview/skins/default/xui/en/panel_hint.xml b/indra/newview/skins/default/xui/en/panel_hint.xml
index 7442136761..741ed5af41 100644
--- a/indra/newview/skins/default/xui/en/panel_hint.xml
+++ b/indra/newview/skins/default/xui/en/panel_hint.xml
@@ -3,7 +3,6 @@
width="205"
height="34">
<text name="hint_title"
- font="SansSerifMedium"
left="8"
right="180"
top="8"
diff --git a/indra/newview/skins/default/xui/en/panel_hint_image.xml b/indra/newview/skins/default/xui/en/panel_hint_image.xml
index d712245df8..3e3205531f 100644
--- a/indra/newview/skins/default/xui/en/panel_hint_image.xml
+++ b/indra/newview/skins/default/xui/en/panel_hint_image.xml
@@ -4,7 +4,6 @@
height="40"
layout="topleft">
<text name="hint_title"
- font="SansSerifMedium"
left="8"
right="290"
top="8"
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index 27b74a46ce..482cbef236 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -6,7 +6,7 @@
name="panel_login"
focus_root="true"
background_visible="true"
- bg_opaque_color="0.16 0.16 0.16 1"
+ bg_opaque_color="DkGrayLogin"
background_opaque="true"
width="1024">
<panel.string
@@ -18,182 +18,379 @@
https://join.secondlife.com/
</panel.string>
<layout_stack
- follows="left|right|top"
- height="172"
- left="0"
- name="ui_stack"
- orientation="horizontal"
- top="10"
- width="1024">
+ follows="all"
+ layout="topleft"
+ orientation="horizontal"
+ name="main_stack"
+ border_size="0"
+ animate="false"
+ top="0"
+ left="0"
+ height="768"
+ width="1024">
+ <layout_panel
+ auto_resize="true"
+ user_resize="false"
+ layout="topleft"
+ name="left_spacer"
+ background_visible="false"
+ min_width="0"
+ expanded_min_dim="0"
+ width="1">
+ </layout_panel>
<layout_panel
- height="172"
- auto_resize="true"
- name="ui_elastic_pad_left"
- width="32" />
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ name="center_stage"
+ background_visible="true"
+ bg_opaque_color="DkGrayLogin"
+ background_opaque="true"
+ width="1008"
+ height="768">
+ <layout_stack
+ follows="all"
+ layout="topleft"
+ orientation="horizontal"
+ name="ui_stack"
+ border_size="0"
+ animate="false"
+ top="0"
+ left="0"
+ height="768"
+ width="1008">
+ <layout_panel
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ name="ui_container"
+ width="300"
+ height="768"
+ background_visible="true"
+ bg_opaque_color="PanelDark"
+ background_opaque="true">
+ <icon
+ height="77"
+ width="160"
+ image_name="login_sl_logo_horizontal"
+ layout="topleft"
+ follows="left|top"
+ left="70"
+ top="39"
+ name="sl_logo_small" />
+ <icon
+ left="40"
+ top_pad="30"
+ width="220"
+ height="28"
+ image_name="TextField_Active"
+ layout="topleft"
+ follows="left|top"
+ name="text_field_bg1" />
+ <combo_box
+ left="40"
+ top_delta="0"
+ allow_text_entry="true"
+ follows="left|top"
+ layout="topleft"
+ height="28"
+ label="Username"
+ combo_editor.font="SansSerifLarge"
+ max_chars="128"
+ combo_editor.commit_on_focus_lost="false"
+ combo_editor.prevalidator="ascii"
+ tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine"
+ name="username_combo"
+ width="220">
+ <combo_box.combo_button
+ image_overlay="ComboButton_Arrow"
+ image_overlay_right_delta="10"
+ image_unselected="ComboButton_Transparent"
+ hover_glow_amount="0"
+ image_selected="ComboButton_Transparent"
+ image_disabled="ComboButton_Transparent" />
+ <combo_box.combo_editor
+ background_image="TextField_Transparent"
+ background_image_disabled="TextField_Transparent"
+ background_image_focused="TextField_Transparent"
+ draw_focus_border="false"
+ text_pad_left="8"
+ bg_image_always_focused="true"/>
+ </combo_box>
+ <check_box
+ follows="left|top"
+ font="SansSerifMedium"
+ label_text.text_color="White"
+ top_pad="3"
+ layout="topleft"
+ height="24"
+ label="Remember username"
+ word_wrap="down"
+ check_button.bottom="3"
+ name="remember_name"
+ tool_tip="Already remembered user can be forgotten from Me &gt; Preferences &gt; Advanced &gt; Remembered Usernames."
+ width="198">
+ <check_box.label_text left="23"/>
+ <check_box.check_button
+ image_selected="Checkbox_Slim_On"
+ image_unselected="Checkbox_Slim_Off"
+ image_pressed="Checkbox_Slim_Off"
+ image_pressed_selected="Checkbox_Slim_Off"/>
+ </check_box>
+ <line_editor
+ follows="left|top"
+ height="28"
+ top_pad="20"
+ max_length_chars="16"
+ text_pad_left="8"
+ name="password_edit"
+ label="Password"
+ bg_image_always_focused="true"
+ font="SansSerifLarge"
+ is_password="true"
+ select_on_focus="true"
+ draw_focus_border="false"
+ commit_on_focus_lost="false"
+ width="220" />
+ <check_box
+ control_name="RememberPassword"
+ follows="left|top"
+ font="SansSerifMedium"
+ label_text.text_color="White"
+ height="24"
+ top_pad="3"
+ label="Remember password"
+ word_wrap="down"
+ check_button.bottom="3"
+ name="remember_password"
+ width="165">
+ <check_box.label_text left="23"/>
+ <check_box.check_button
+ image_selected="Checkbox_Slim_On"
+ image_unselected="Checkbox_Slim_Off"
+ image_pressed="Checkbox_Slim_Off"
+ image_pressed_selected="Checkbox_Slim_Off"/>
+ </check_box>
+ <text
+ follows="left|top"
+ font="SansSerif"
+ text_color="White"
+ height="12"
+ name="location_text"
+ top_pad="18"
+ width="120"
+ valign="center">
+ Start here
+ </text>
+ <icon
+ top_pad="6"
+ width="220"
+ height="28"
+ image_name="TextField_Active"
+ layout="topleft"
+ follows="left|top"
+ name="text_field_bg2" />
+ <combo_box
+ allow_text_entry="true"
+ control_name="NextLoginLocation"
+ follows="left|top"
+ label="My favorite places"
+ height="28"
+ max_chars="128"
+ combo_editor.font="SansSerifLarge"
+ top_delta="0"
+ name="start_location_combo"
+ width="220"
+ combo_button.scale_image="true">
+ <combo_box.combo_button
+ image_overlay="ComboButton_Arrow"
+ hover_glow_amount="0"
+ image_overlay_right_delta="10"
+ image_unselected="ComboButton_Transparent"
+ image_selected="ComboButton_Transparent"
+ image_disabled="ComboButton_Transparent" />
+ <combo_box.combo_editor
+ background_image="TextField_Transparent"
+ background_image_disabled="TextField_Transparent"
+ background_image_focused="TextField_Transparent"
+ draw_focus_border="false"
+ text_pad_left="8"
+ bg_image_always_focused="true"/>
+ <combo_box.item
+ label="My last location"
+ name="MyLastLocation"
+ value="last" />
+ <combo_box.item
+ label="My home"
+ name="MyHome"
+ value="home" />
+ </combo_box>
+ <layout_stack
+ follows="left|top"
+ layout="topleft"
+ orientation="vertical"
+ name="login_stack"
+ border_size="0"
+ animate="false"
+ top_pad="0"
+ left="0"
+ height="218"
+ width="300">
+ <layout_panel
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ name="grid_panel"
+ background_visible="false"
+ height="64"
+ width="300">
+ <text
+ follows="left|top"
+ font="SansSerif"
+ text_color="white"
+ height="12"
+ name="grid_text"
+ top="18"
+ left="40"
+ width="120"
+ valign="center">
+ Grid
+ </text>
+ <combo_box
+ allow_text_entry="false"
+ font="SansSerifTiny"
+ follows="left|top"
+ height="28"
+ top_pad="6"
+ left="40"
+ max_chars="128"
+ label="Select grid"
+ layout="topleft"
+ name="server_combo"
+ width="220">
+ <combo_box.drop_down_button
+ pad_bottom="1"
+ pad_left="10"
+ font="SansSerifLarge"
+ label_color="Black"
+ label_color_selected="Black"
+ draw_focus_border="false"
+ image_overlay="ComboButton_Arrow"
+ image_overlay_right_delta="10"
+ image_unselected="TextField_Active"
+ image_selected="TextField_Active"
+ image_pressed="TextField_Active"
+ image_pressed_selected="TextField_Active"/>
+ </combo_box>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ name="login_panel"
+ background_visible="false"
+ height="172"
+ width="300">
+ <button
+ follows="left|top"
+ image_unselected="PushButton_Login"
+ image_pressed="PushButton_Login_Pressed"
+ image_hover_unselected="PushButton_Login_Over"
+ label="Log in"
+ label_color="Black"
+ label_color_disabled="Black"
+ font="SansSerifLarge"
+ font.style="BOLD"
+ name="connect_btn"
+ draw_focus_border="false"
+ hover_hand_cursor="true"
+ enabled="true"
+ width="220"
+ height="30"
+ left="40"
+ top="25"
+ pad_bottom="1" />
+ <text
+ follows="left|top"
+ font="SansSerifMedium"
+ text_color="EmphasisColor"
+ height="15"
+ name="forgot_password_text"
+ left="60"
+ top_pad="9"
+ width="180"
+ halign="center">
+ Need help logging in?
+ </text>
+ <button
+ follows="left|top"
+ image_unselected="PushButton_Sign"
+ image_pressed="PushButton_Sign_Pressed"
+ image_hover_unselected="PushButton_Sign_Over"
+ label="Create account"
+ label_color="White"
+ label_color_disabled="Black"
+ font="SansSerifMedium"
+ font.style="BOLD"
+ name="sign_btn"
+ draw_focus_border="false"
+ hover_hand_cursor="true"
+ width="220"
+ height="35"
+ left="40"
+ top_pad="25"
+ pad_bottom="1" />
+ </layout_panel>
+ </layout_stack>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ name="middle_gutter"
+ min_width="18"
+ max_width="18"
+ expanded_min_dim="18"
+ width="18"
+ height="768"
+ background_visible="true"
+ bg_opaque_color="DkGrayLogin"
+ background_opaque="true">
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ user_resize="false"
+ layout="topleft"
+ name="web_container"
+ width="690"
+ height="768"
+ background_visible="true"
+ bg_opaque_color="DkGrayLogin"
+ background_opaque="true">
+ <web_browser
+ tab_stop="false"
+ trusted_content="true"
+ bg_opaque_color="DkGrayLogin"
+ border_visible="false"
+ follows="all"
+ left="0"
+ top="0"
+ right="-1"
+ bottom="-1"
+ name="login_html"
+ start_url="" />
+ </layout_panel>
+ </layout_stack>
+ </layout_panel>
<layout_panel
- auto_resize="false"
- follows="left|right|top"
- name="ui_container"
- width="1011"
- left="0"
- top="0"
- height="172">
- <icon
- height="73"
- width="165"
- image_name="login_sl_logo"
- left="0"
- top="25"
- name="sl_logo_small" />
- <combo_box
- left_pad="22"
- bottom_delta="-7"
- allow_text_entry="true"
- follows="left|top"
- height="32"
- label="Username"
- combo_editor.font="SansSerifLarge"
- max_chars="128"
- combo_editor.commit_on_focus_lost="false"
- combo_editor.prevalidator="ascii"
- tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine"
- name="username_combo"
- width="206">
- <combo_box.combo_editor
- text_pad_left="8"
- bg_image_always_focused="true"/>
- </combo_box>
- <line_editor
- follows="left|top"
- height="32"
- left_pad="15"
- max_length_chars="16"
- text_pad_left="8"
- name="password_edit"
- label="Password"
- bg_image_always_focused="true"
- font="SansSerifLarge"
- is_password="true"
- select_on_focus="true"
- commit_on_focus_lost="false"
- bottom_delta="0"
- width="165" />
- <combo_box
- allow_text_entry="true"
- control_name="NextLoginLocation"
- follows="left|top"
- label="My favorite places"
- height="32"
- max_chars="128"
- combo_editor.font="SansSerifLarge"
- left_pad="15"
- bottom_delta="0"
- name="start_location_combo"
- width="175"
- combo_button.scale_image="true">
- <combo_box.combo_editor
- bg_image_always_focused="true"
- text_pad_left="8"/>
- <combo_box.item
- label="My last location"
- name="MyLastLocation"
- value="last" />
- <combo_box.item
- label="My home"
- name="MyHome"
- value="home" />
- </combo_box>
- <button
- follows="left|top"
- image_unselected="PushButton_Login"
- image_pressed="PushButton_Login_Pressed"
- image_hover_unselected="PushButton_Login_Over"
- label="Log In"
- label_color="White"
- font="SansSerifMedium"
- name="connect_btn"
- enabled="true"
- width="120"
- height="32"
- left_pad="15"
- bottom_delta="0" />
- <text
- follows="left|top"
- font="SansSerifLarge"
- font.style="BOLD"
- text_color="EmphasisColor"
- height="34"
- name="sign_up_text"
- left_pad="10"
- width="200"
- valign="center">
- Sign up
- </text>
- <check_box
- follows="left|top"
- font="SansSerifMedium"
- left="185"
- bottom_delta="21"
- height="24"
- label="Remember me"
- word_wrap="down"
- check_button.bottom="3"
- name="remember_name"
- tool_tip="Already remembered user can be forgotten from Me &gt; Preferences &gt; Advanced &gt; Remembered Usernames."
- width="198" />
- <check_box
- control_name="RememberPassword"
- follows="left|top"
- font="SansSerifMedium"
- height="24"
- left="408"
- bottom_delta="0"
- label="Remember password"
- word_wrap="down"
- check_button.bottom="3"
- name="remember_password"
- width="165" />
- <combo_box
- allow_text_entry="false"
- font="SansSerifTiny"
- follows="left|top"
- height="26"
- left="588"
- bottom_delta="8"
- max_chars="128"
- label="Select grid"
- layout="topleft"
- name="server_combo"
- width="149" />
- <text
- follows="left|top"
- font="SansSerifMedium"
- text_color="EmphasisColor"
- height="16"
- name="forgot_password_text"
- left="778"
- bottom_delta="-8"
- width="120"
- halign="center">
- Password help
- </text>
- </layout_panel>
- <layout_panel
- height="172"
- auto_resize="true"
- name="ui_elastic_pad_right"
- width="32" />
+ auto_resize="true"
+ user_resize="false"
+ layout="topleft"
+ name="right_spacer"
+ background_visible="false"
+ min_width="0"
+ expanded_min_dim="0"
+ width="1">
+ </layout_panel>
</layout_stack>
- <web_browser
- tab_stop="false"
- trusted_content="true"
- bg_opaque_color="Black"
- border_visible="false"
- follows="all"
- left="0"
- name="login_html"
- start_url=""
- top="154"
- height="600"
- width="1024" />
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_login_first.xml b/indra/newview/skins/default/xui/en/panel_login_first.xml
deleted file mode 100644
index d6ac71db94..0000000000
--- a/indra/newview/skins/default/xui/en/panel_login_first.xml
+++ /dev/null
@@ -1,262 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel
- follows="all"
- height="768"
- layout="topleft"
- name="panel_login"
- focus_root="true"
- background_visible="true"
- bg_opaque_color="0.16 0.16 0.16 1"
- background_opaque="true"
- width="1024">
- <panel.string
- name="forgot_password_url">
- http://secondlife.com/account/request.php
- </panel.string>
- <panel.string
- name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack
- follows="left|right|top|bottom"
- width="1024"
- height="768"
- left="0"
- name="logo_stack"
- orientation="vertical"
- top="0">
- <layout_panel
- height="18"
- auto_resize="false"
- name="page_top"
- width="1024" />
- <!-- start of logo stack -->
- <layout_panel
- height="130"
- min_height="10"
- auto_resize="false"
- name="parent_panel"
- width="1024">
- <layout_stack
- follows="left|right|top|bottom"
- height="100"
- left="0"
- name="logo_stack"
- orientation="horizontal"
- top="0"
- width="1024">
- <layout_panel
- height="110"
- min_height="10"
- auto_resize="true"
- name="logo_left"
- width="300" />
- <layout_panel
- auto_resize="false"
- follows="left|right|top"
- name="logo_container"
- width="225"
- left="0"
- top="0"
- height="105">
- <icon
- height="94"
- image_name="login_sl_logo"
- left="0"
- name="sl_logo"
- top="0" />
- </layout_panel>
- <layout_panel
- height="100"
- name="logo_right"
- auto_resize="true"
- width="300" />
- </layout_stack>
- </layout_panel>
- <!-- end of logo stack -->
- <!-- start of widget stack -->
- <layout_panel
- height="100"
- min_height="10"
- auto_resize="false"
- name="parent_panel2"
- width="1024">
- <layout_stack
- follows="left|right|top|bottom"
- height="80"
- left="0"
- name="widget_stack"
- orientation="horizontal"
- top="0"
- width="1024">
- <layout_panel
- height="80"
- min_height="10"
- auto_resize="true"
- name="widget_left"
- width="200" />
- <layout_panel
- auto_resize="false"
- follows="left|right|top"
- name="widget_container"
- width="730"
- left="0"
- top="0"
- height="80">
- <combo_box
- allow_text_entry="true"
- follows="left|bottom"
- height="32"
- left="42"
- label="Username"
- combo_editor.font="SansSerifLarge"
- max_chars="128"
- top="0"
- combo_editor.prevalidator="ascii"
- tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine"
- name="username_combo"
- width="232">
- <combo_box.combo_editor
- text_pad_left="8" />
- <combo_box.combo_button
- visible ="false"/>
- <combo_box.drop_down_button
- visible ="false"/>
- </combo_box>
- <line_editor
- follows="left|top"
- width="200"
- height="32"
- left="262"
- max_length_chars="16"
- name="password_edit"
- label="Password"
- text_pad_left="8"
- font="SansSerifLarge"
- is_password="true"
- select_on_focus="true"
- commit_on_focus_lost="false"
- top="0" />
- <button
- follows="left|top"
- image_unselected="PushButton_Login"
- image_pressed="PushButton_Login_Pressed"
- image_hover_unselected="PushButton_Login_Over"
- label="Log In"
- label_color="White"
- font="SansSerifLarge"
- name="connect_btn"
- left_pad="15"
- width="120"
- height="32"
- top="0" />
- <text
- follows="left|top"
- font="SansSerifLarge"
- font.style="BOLD"
- text_color="EmphasisColor"
- height="34"
- name="sign_up_text"
- left_pad="10"
- top="0"
- width="200"
- valign="center">
- Sign up
- </text>
- <check_box
- follows="left|top"
- font="SansSerifLarge"
- left="42"
- top="32"
- height="24"
- label="Remember me"
- word_wrap="down"
- check_button.bottom="3"
- name="remember_name"
- tool_tip="Already remembered user can be forgotten from Me &gt; Preferences &gt; Advanced &gt; Remembered Usernames."
- width="198" />
- <check_box
- control_name="RememberPassword"
- follows="left|top"
- font="SansSerifLarge"
- height="24"
- left="262"
- bottom_delta="0"
- label="Remember password"
- word_wrap="down"
- check_button.bottom="3"
- name="remember_password"
- width="198" />
- <text
- follows="left|top"
- font="SansSerifLarge"
- text_color="EmphasisColor"
- height="16"
- name="forgot_password_text"
- left="492"
- top="34"
- width="200">
- Forgotten password
- </text>
- </layout_panel>
- <layout_panel
- height="100"
- name="widget_right"
- auto_resize="true"
- width="200" />
- </layout_stack>
- </layout_panel>
- <!-- end of widget stack -->
- <!-- start of images stack -->
- <layout_panel
- height="500"
- min_height="10"
- auto_resize="false"
- name="parent_panel3"
- width="1024">
- <layout_stack
- follows="left|right|top|bottom"
- height="500"
- left="0"
- name="images_stack"
- orientation="horizontal"
- top="0"
- width="1024">
- <layout_panel
- height="500"
- min_height="10"
- auto_resize="true"
- name="images_left"
- width="96" />
- <layout_panel
- auto_resize="false"
- follows="left|right|top"
- name="images_container"
- width="675"
- left="0"
- top="0"
- height="500">
- <icon
- height="450"
- width="675"
- image_name="first_login_image"
- left="0"
- name="image_left"
- top="0" />
- </layout_panel>
- <layout_panel
- height="100"
- name="images_right"
- auto_resize="true"
- width="96" />
- </layout_stack>
- </layout_panel>
- <!-- end of images stack -->
- <layout_panel
- height="400"
- min_height="10"
- auto_resize="true"
- name="page_bottom"
- width="1024" />
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
index 6e1e6facbe..a302d44e83 100644
--- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
@@ -34,7 +34,6 @@
left="12"
right="-12"
name="ItemcountText"
- font="SansSerifMedium"
text_color="InventoryItemLinkColor"
use_ellipses="true"
top_pad="0">
diff --git a/indra/newview/skins/default/xui/en/panel_marketplace_listings.xml b/indra/newview/skins/default/xui/en/panel_marketplace_listings.xml
index 61cd6a83d4..371147b28a 100644
--- a/indra/newview/skins/default/xui/en/panel_marketplace_listings.xml
+++ b/indra/newview/skins/default/xui/en/panel_marketplace_listings.xml
@@ -108,7 +108,6 @@
left="2"
width="306"
halign="center"
- font="SansSerifMedium"
font_shadow="hard"
valign="top">
Drop folders here to create new listings
diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
index 85cf4419a3..4d924a6c24 100644
--- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
@@ -89,7 +89,7 @@
image_hover_unselected="PushButton_Over"
image_bottom_pad="1"
layout="topleft"
- left="10"
+ left="9"
name="back_btn"
tool_tip="Go back to previous location"
top="2"
@@ -102,7 +102,7 @@
image_hover_unselected="PushButton_Over"
image_bottom_pad="1"
layout="topleft"
- left_pad="0"
+ left_pad="1"
name="forward_btn"
tool_tip="Go forward one location"
top_delta="0"
diff --git a/indra/newview/skins/default/xui/en/panel_notification_list_item.xml b/indra/newview/skins/default/xui/en/panel_notification_list_item.xml
index 80db209b59..c6e2c124d1 100644
--- a/indra/newview/skins/default/xui/en/panel_notification_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_notification_list_item.xml
@@ -63,7 +63,8 @@
use_ellipses="true" word_wrap="false" mouse_opaque="false" name="sender_or_fee_box" visible="false">
Sender: "Resident R e s i d e n t R e s i d e n t"
</text>
- <text allow_scroll="false" font="SansSerifSmall" top="0" right="-5" width="95" height="13" follows="right" halign="right" layout="topleft" left_pad="5"
+ <!-- Old DejaVu font is used to avoid overlapping with sender name -->
+ <text allow_scroll="false" font="DejaVu" font.size="LSmall" top="0" right="-5" width="100" height="13" follows="right" halign="right" layout="topleft" left_pad="5"
name="notification_time" value="2014/12/24 23:30" />
</panel>
</panel>
@@ -105,7 +106,8 @@
use_ellipses="true" word_wrap="false" mouse_opaque="false" name="sender_or_fee_box_exp" visible="false">
Sender: "Resident R e s i d e n t R e s i d e n t"
</text>
- <text allow_scroll="false" font="SansSerifSmall" top="0" right="-1" width="95" height="13" follows="right" halign="right" layout="topleft" left_pad="5"
+ <!-- Old DejaVu font is used to avoid overlapping with sender name -->
+ <text allow_scroll="false" font="DejaVu" font.size="LSmall" top="0" right="-1" width="100" height="13" follows="right" halign="right" layout="topleft" left_pad="5"
name="notification_time_exp" value="2014/12/24 23:30" />
</panel>
<panel border="false" left="0" height="115" width="230" bevel_style="none" follows="all" layout="topleft" name="notification_text_panel_exp" visible="true">
diff --git a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
index a0e3344304..4cd9d27841 100644
--- a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
@@ -216,7 +216,7 @@ It is calculated as border_size + 2*UIResizeBarOverlap
<button
follows="left|bottom"
height="22"
- image_pressed="PushButton_Press"
+ image_pressed="PushButton_Selected"
image_pressed_selected="PushButton_Selected_Press"
image_selected="PushButton_Selected_Press"
is_toggle="true"
@@ -251,7 +251,7 @@ It is calculated as border_size + 2*UIResizeBarOverlap
follows="bottom|right"
height="22"
image_overlay="Search_Icon"
- image_pressed="PushButton_Press"
+ image_pressed="PushButton_Selected"
image_pressed_selected="PushButton_Selected_Press"
image_selected="PushButton_Selected_Press"
is_toggle="true"
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 1be34550fa..d43045ebaa 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -183,6 +183,7 @@ Learn about [https://community.secondlife.com/knowledgebase/joining-and-particip
increment="1"
follows="left|top"
left="5"
+ top_pad="5"
min_val="0"
max_val="4096"
label="Range:"
@@ -199,13 +200,13 @@ Learn about [https://community.secondlife.com/knowledgebase/joining-and-particip
<layout_stack
clip="false"
follows="all"
- height="410"
+ height="406"
layout="topleft"
left="0"
mouse_opaque="false"
orientation="vertical"
right="-1"
- top_pad="0">
+ top_pad="3">
<layout_panel
height="142"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml b/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml
index 9f930d1557..1bea605d91 100644
--- a/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml
+++ b/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml
@@ -144,7 +144,7 @@
<button
follows="top|left"
height="22"
- image_pressed="PushButton_Press"
+ image_pressed="PushButton_Selected"
image_pressed_selected="PushButton_Selected_Press"
image_selected="PushButton_Selected_Press"
label="Auto-adjust now"
@@ -157,7 +157,7 @@
<button
follows="top|left"
height="22"
- image_pressed="PushButton_Press"
+ image_pressed="PushButton_Selected"
image_pressed_selected="PushButton_Selected_Press"
image_selected="PushButton_Selected_Press"
label="Cancel"
@@ -183,7 +183,7 @@
follows="top|left"
height="20"
initial_value="true"
- image_pressed="PushButton_Press"
+ image_pressed="PushButton_Selected"
image_pressed_selected="PushButton_Selected_Press"
image_selected="PushButton_Selected_Press"
is_toggle="true"
diff --git a/indra/newview/skins/default/xui/en/panel_performance_preferences.xml b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml
index 5031784644..df14a66515 100644
--- a/indra/newview/skins/default/xui/en/panel_performance_preferences.xml
+++ b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml
@@ -91,7 +91,7 @@
layout="topleft"
left_pad="40"
name="fastest_lbl"
- width="40">
+ width="42">
Fastest
</text>
<radio_group
@@ -240,7 +240,7 @@
left_pad="10"
top_delta="1"
name="farther_lbl"
- width="40">
+ width="45">
Farther
</text>
<text
@@ -284,7 +284,7 @@
top_delta="0"
left="160"
name="enhancements_desc"
- width="350">
+ width="375">
Shadows significantly improve visual quality but can reduce speed.
</text>
<text
@@ -307,7 +307,8 @@
left_delta="150"
top_delta="0"
name="ShadowDetail"
- width="150">
+ width="153">
+ <combo_box.drop_down_button pad_right="20" />
<combo_box.item
label="None"
name="0"
@@ -417,7 +418,7 @@
top_delta="3"
left_pad="10"
name="photo_dist_det_desc"
- width="180">
+ width="192">
(Enter value between 0.0 and 4.0)
</text>
<text
@@ -426,7 +427,7 @@
height="18"
layout="topleft"
top="80"
- left="213"
+ left="215"
name="0_lbl"
width="7">
0
@@ -446,7 +447,7 @@
font="SansSerifSmall"
height="18"
layout="topleft"
- left_pad="30"
+ left_pad="29"
name="2_lbl"
width="7">
2
@@ -468,7 +469,7 @@
layout="topleft"
left_pad="30"
name="4_lbl"
- width="7">
+ width="8">
4
</text>
<text
@@ -476,7 +477,7 @@
font="SansSerifSmall"
height="18"
layout="topleft"
- left_pad="30"
+ left_pad="29"
name="5_lbl"
width="7">
5
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
index 86999b1afb..d9d362bbd4 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
@@ -13,18 +13,6 @@
name="aspect_ratio_text">
[NUM]:[DEN]
</panel.string>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="12"
- layout="topleft"
- left="33"
- name="Cache:"
- top_pad="10"
- width="100">
- Cache:
- </text>
<spinner
control_name="CacheSize"
decimal_digits="0"
@@ -33,14 +21,14 @@
increment="64"
initial_value="1024"
label="Cache size (896 - 32768MB)"
- label_width="150"
+ label_width="170"
layout="topleft"
- left="80"
+ left="33"
max_val="32768"
min_val="896"
top_pad="10"
name="cachesizespinner"
- width="210" />
+ width="230" />
<text
type="string"
length="1"
@@ -59,7 +47,7 @@
label="Clear Cache"
label_selected="Clear Cache"
layout="topleft"
- left_pad="20"
+ left_pad="25"
name="clear_cache"
top_delta="0"
width="100">
@@ -72,7 +60,7 @@
follows="left|top"
height="10"
layout="topleft"
- left="80"
+ left="33"
name="Cache location"
top_pad="5"
width="300">
@@ -86,7 +74,7 @@
font="SansSerif"
height="23"
layout="topleft"
- left="80"
+ left="33"
max_length_bytes="4096"
name="cache_location"
top_pad="5"
@@ -113,7 +101,7 @@
left_pad="3"
name="default_cache_location"
top_delta="0"
- width="100">
+ width="104">
<button.commit_callback
function="Pref.ResetCache" />
</button>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_general.xml b/indra/newview/skins/default/xui/en/panel_preferences_general.xml
index 08b3ef69b6..6d1b952639 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_general.xml
@@ -110,7 +110,8 @@
left="255"
max_chars="135"
name="time_format_combobox"
- width="70">
+ width="71">
+ <combo_box.drop_down_button pad_right="22" />
<combo_box.item
enabled="true"
label="1:00 PM"
@@ -244,7 +245,7 @@
height="20"
layout="topleft"
left="35"
- top_pad="0"
+ top_pad="5"
name="Name_Tag_Preference">
<radio_item
label="Off"
@@ -304,7 +305,7 @@
name="display_names_check"
width="100"
tool_tip="Check to use display names in chat, IM, name tags, etc."
- top_pad="3"/>
+ top_pad="5"/>
<check_box
control_name="NameTagShowFriends"
enabled_control="AvatarNameTagMode"
@@ -319,7 +320,7 @@
layout="topleft"
control_name="GroupTitlesTagMode"
enabled_control="AvatarNameTagMode"
- left="39"
+ left="38"
top_pad="3"
name="group_title"
width="130">
@@ -344,7 +345,7 @@
layout="topleft"
left="30"
name="inworld_typing_rg_label"
- top_pad="4"
+ top_pad="5"
width="400">
Pressing letter keys:
</text>
@@ -353,7 +354,7 @@
height="34"
layout="topleft"
left="35"
- top_pad="0"
+ top_pad="5"
name="inworld_typing_preference">
<radio_item
label="Starts local chat"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
index bf07ae4d68..0f44366947 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
@@ -104,7 +104,7 @@
layout="topleft"
left="65"
name="FasterText"
- top_pad="4"
+ top_pad="10"
width="80">
Faster
</text>
@@ -114,14 +114,14 @@
follows="left|top"
height="12"
layout="topleft"
- left_delta="360"
+ left_delta="363"
name="BetterText"
top_delta="0"
width="100">
Better
</text>
<icon
- color="DkGray"
+ color="DkGray0"
height="14"
image_name="Rounded_Square"
layout="topleft"
@@ -130,7 +130,7 @@
top_delta="-2"
width="2" />
<icon
- color="DkGray"
+ color="DkGray0"
height="14"
image_name="Rounded_Square"
layout="topleft"
@@ -138,7 +138,7 @@
name="LowMidGraphicsDivet"
width="2" />
<icon
- color="DkGray"
+ color="DkGray0"
height="14"
image_name="Rounded_Square"
layout="topleft"
@@ -147,7 +147,7 @@
top_delta="0"
width="2" />
<icon
- color="DkGray"
+ color="DkGray0"
height="14"
image_name="Rounded_Square"
layout="topleft"
@@ -156,7 +156,7 @@
top_delta="0"
width="2" />
<icon
- color="DkGray"
+ color="DkGray0"
height="14"
image_name="Rounded_Square"
layout="topleft"
@@ -165,7 +165,7 @@
top_delta="0"
width="2" />
<icon
- color="DkGray"
+ color="DkGray0"
height="14"
image_name="Rounded_Square"
layout="topleft"
@@ -174,7 +174,7 @@
top_delta="0"
width="2" />
<icon
- color="DkGray"
+ color="DkGray0"
height="14"
image_name="Rounded_Square"
layout="topleft"
@@ -216,15 +216,15 @@
min_val="64"
max_val="512"
name="DrawDistance"
- top_delta="40"
- width="427" />
+ top_delta="34"
+ width="428" />
<text
type="string"
length="1"
follows="left|top"
height="12"
layout="topleft"
- left_delta="427"
+ left_delta="425"
name="DrawDistanceMeterText2"
top_delta="0"
width="128">
@@ -286,7 +286,7 @@
initial_value="101"
increment="1"
label="Avatar maximum complexity:"
- label_width="165"
+ label_width="187"
layout="topleft"
left="30"
min_val="1"
@@ -294,7 +294,7 @@
name="IndirectMaxComplexity"
show_text="false"
top_delta="28"
- width="300">
+ width="394">
<slider.commit_callback
function="Pref.UpdateIndirectMaxComplexity"
parameter="IndirectMaxComlexityText" />
@@ -306,7 +306,7 @@
height="16"
layout="topleft"
top_delta="0"
- left_delta="304"
+ left_delta="398"
text_readonly_color="LabelDisabledColor"
name="IndirectMaxComplexityText"
width="65">
@@ -329,7 +329,7 @@
label_width="240"
left="30"
top_delta="20"
- width="393">
+ width="394">
<slider.commit_callback
function="Pref.UpdateIndirectMaxNonImpostors"
parameter="IndirectNonImpostorsText" />
@@ -341,7 +341,7 @@
height="16"
layout="topleft"
top_delta="0"
- left_delta="397"
+ left_delta="398"
text_readonly_color="LabelDisabledColor"
name="IndirectMaxNonImpostorsText"
width="65">
@@ -369,7 +369,7 @@
increment="0.1"
initial_value="160"
label="Brightness (exposure)"
- label_width="145"
+ label_width="187"
layout="topleft"
left="30"
min_val="0.5"
@@ -377,7 +377,7 @@
name="RenderExposure"
show_text="true"
top_pad="14"
- width="260">
+ width="424">
</slider>
<!-- End of Basic Settings block -->
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
index 1c00837073..8b60be30f9 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
@@ -10,6 +10,7 @@
top="1"
width="517">
+ <!-- remove "hide_tabs" param when Discord tab is actually used -->
<tab_container
top_pad="0"
enabled="true"
@@ -18,6 +19,7 @@
width="517"
left_delta="0"
name="privacy_tab_container"
+ hide_tabs="true"
tab_position="top"
tab_stop="false">
<panel
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
index 258c49785e..2036ed75ca 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
@@ -170,7 +170,7 @@
left="30"
name="Software updates:"
mouse_opaque="false"
- top_pad="5"
+ top_pad="8"
width="300">
Software updates:
</text>
@@ -180,7 +180,7 @@
height="23"
layout="topleft"
left_delta="50"
- top_pad="5"
+ top_pad="10"
name="updater_service_combobox"
width="300">
<combo_box.item
@@ -197,29 +197,29 @@
value="0" />
</combo_box>
<check_box
- top_delta="4"
+ top_pad="10"
enabled="true"
follows="left|top"
+ layout="topleft"
height="14"
control_name="UpdaterWillingToTest"
label="Willing to update to Beta"
left_delta="0"
mouse_opaque="true"
name="update_willing_to_test"
- width="400"
- top_pad="5"/>
+ width="400"/>
<check_box
- top_delta="4"
+ top_pad="8"
enabled="true"
follows="left|top"
+ layout="topleft"
height="14"
control_name="UpdaterShowReleaseNotes"
label="Show Release Notes after update"
left_delta="0"
mouse_opaque="true"
name="update_show_release_notes"
- width="400"
- top_pad="5"/>
+ width="400"/>
<text
type="string"
length="1"
@@ -229,7 +229,7 @@
left="30"
name="Proxy Settings:"
mouse_opaque="false"
- top_pad="5"
+ top_pad="8"
width="300">
Proxy Settings:
</text>
@@ -242,8 +242,7 @@
layout="topleft"
left_delta="50"
name="set_proxy"
- top_pad="5"
- >
+ top_pad="10" >
<button.commit_callback
function="Pref.Proxy" />
</button>
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 52413abe74..1dcbf4e666 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
@@ -319,7 +319,7 @@
top_delta="25"
name="Listen media from"
height="15"
- width="165"
+ width="180"
halign="right">
Hear media and sounds from
</text>
@@ -327,7 +327,7 @@
control_name="MediaSoundsEarLocation"
follows="left|top"
layout="topleft"
- left_pad="5"
+ left_pad="10"
width="130"
height="23"
top_delta="-4"
@@ -346,7 +346,7 @@
layout="topleft"
height="15"
left="23"
- width="165"
+ width="180"
name="media_autoplay_label"
halign="right">
Auto-play media
@@ -357,7 +357,7 @@
follows="left|top"
layout="topleft"
height="23"
- left_delta="170"
+ left_delta="190"
top_delta="-4"
name="media_auto_play_combo"
width="130">
@@ -379,7 +379,7 @@
layout="topleft"
height="15"
left="23"
- width="165"
+ width="180"
name="media_firstinteract_label"
halign="right">
Media first-interact
@@ -390,11 +390,12 @@
follows="left|top"
layout="topleft"
height="23"
- left_delta="170"
+ left_delta="190"
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.">
+ <combo_box.drop_down_button pad_right="19" />
<item
label="Disabled"
name="media_first_click_none"
@@ -457,7 +458,7 @@
layout="topleft"
follows="left"
height="15"
- width="165"
+ width="187"
name="noise_suppression_label"
left="23"
top_delta="22"
@@ -469,7 +470,7 @@
enabled_control="EnableVoiceChat"
follows="left|top"
layout="topleft"
- left_delta="170"
+ left_delta="190"
top_delta="-6"
width="130"
height="23"
@@ -503,7 +504,7 @@
left="23"
top_delta="30"
name="Listen from"
- width="165"
+ width="180"
height="15"
halign="right">
Hear voice from
@@ -513,7 +514,7 @@
control_name="VoiceEarLocation"
follows="left|top"
layout="topleft"
- left_delta="170"
+ left_delta="190"
top_delta="-6"
width="130"
height="23"
@@ -545,7 +546,7 @@
tool_tip="Check to enable voice echo cancellation"
label="Echo Cancellation"
layout="topleft"
- left="260"
+ left="275"
name="enable_echo_cancellation"
top_pad="-15"
width="200"/>
@@ -558,7 +559,7 @@
layout="topleft"
left="20"
name="push_to_talk_toggle_check"
- width="237"
+ width="245"
tool_tip="When in toggle mode, press and release the trigger key ONCE to switch your microphone on or off. When not in toggle mode, the microphone broadcasts your voice only while the trigger is being held down."
top_pad="5"/>
<check_box
@@ -569,7 +570,7 @@
label="Automatic Gain Control"
layout="topleft"
name="voice_automatic_gain_control"
- left="260"
+ left="275"
top_pad="-15"
width="200"/>
<check_box
@@ -591,7 +592,7 @@
label="Show voice dot above avatars"
layout="topleft"
name="voice_dot_visualizer"
- left="260"
+ left="275"
top_pad="-15"
width="200"/>
<button
@@ -603,7 +604,7 @@
label="Voice Input/Output devices"
layout="topleft"
left="20"
- top_pad="0"
+ top_pad="1"
name="device_settings_btn"
width="200">
</button>
diff --git a/indra/newview/skins/default/xui/en/panel_region_experiences.xml b/indra/newview/skins/default/xui/en/panel_region_experiences.xml
index 199dca4853..5e9ebabba7 100644
--- a/indra/newview/skins/default/xui/en/panel_region_experiences.xml
+++ b/indra/newview/skins/default/xui/en/panel_region_experiences.xml
@@ -13,7 +13,6 @@
<panel.string
name="trusted_estate_text">
Any Experience may be Key.
-
Key Experiences have permission to run on this estate.
Additionally, if the estate does not allow public access, Residents participating in any Key Experience may enter the estate and can remain as long as they are in a Key Experience.
diff --git a/indra/newview/skins/default/xui/en/panel_region_general.xml b/indra/newview/skins/default/xui/en/panel_region_general.xml
index 47e1e669d1..4e624276cc 100644
--- a/indra/newview/skins/default/xui/en/panel_region_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_region_general.xml
@@ -67,12 +67,12 @@
</text>
<text
follows="left|top"
- font="SansSerif"
+ font="SansSerifSmall"
height="20"
layout="topleft"
- left_delta="50"
+ left_delta="53"
name="version_channel_text"
- top_delta="0"
+ top_delta="1"
width="400">
unknown
</text>
@@ -81,7 +81,7 @@
font="SansSerif"
height="20"
layout="topleft"
- top_delta="0"
+ top_delta="-1"
right="-100"
name="grid_position_lbl"
width="80">
diff --git a/indra/newview/skins/default/xui/en/panel_region_terrain.xml b/indra/newview/skins/default/xui/en/panel_region_terrain.xml
index 73e0a1000f..dd9907dc1f 100644
--- a/indra/newview/skins/default/xui/en/panel_region_terrain.xml
+++ b/indra/newview/skins/default/xui/en/panel_region_terrain.xml
@@ -42,7 +42,7 @@
max_val="100"
name="water_height_spin"
top="40"
- width="180" />
+ width="190" />
<spinner
follows="left|top"
height="20"
@@ -54,7 +54,7 @@
max_val="100"
name="terrain_raise_spin"
top="40"
- width="180" />
+ width="190" />
<spinner
follows="left|top"
height="20"
@@ -67,7 +67,7 @@
min_val="-100"
name="terrain_lower_spin"
top="60"
- width="180" />
+ width="190" />
<view_border
bevel_style="none"
follows="top|left"
@@ -330,7 +330,7 @@
follows="left|top"
height="20"
layout="topleft"
- left_pad="10"
+ left_pad="15"
name="height_text_lbl7"
top_delta="0"
width="100">
@@ -349,7 +349,7 @@
min_val="-500"
name="height_start_spin_1"
top_delta="15"
- width="100" />
+ width="105" />
<!-- northeast low-->
<spinner
follows="left|top"
@@ -363,7 +363,7 @@
min_val="-500"
name="height_start_spin_3"
top_delta="0"
- width="100" />
+ width="105" />
<!-- northwest high-->
<spinner
follows="left|top"
@@ -377,7 +377,7 @@
min_val="-500"
name="height_range_spin_1"
top_delta="20"
- width="100" />
+ width="105" />
<!-- northeast high-->
<spinner
follows="left|top"
@@ -391,7 +391,7 @@
min_val="-500"
name="height_range_spin_3"
top_delta="0"
- width="100" />
+ width="105" />
<text
follows="left|top"
height="20"
@@ -406,7 +406,7 @@
follows="left|top"
height="20"
layout="topleft"
- left_pad="10"
+ left_pad="15"
name="height_text_lbl9"
top_delta="0"
width="100">
@@ -425,7 +425,7 @@
min_val="-500"
name="height_start_spin_0"
top_delta="15"
- width="100" />
+ width="105" />
<!-- southeast low-->
<spinner
follows="left|top"
@@ -439,7 +439,7 @@
min_val="-500"
name="height_start_spin_2"
top_delta="0"
- width="100" />
+ width="105" />
<!--southwest high-->
<spinner
follows="left|top"
@@ -453,7 +453,7 @@
min_val="-500"
name="height_range_spin_0"
top_delta="20"
- width="100" />
+ width="105" />
<!-- southeast high-->
<spinner
follows="left|top"
@@ -467,7 +467,7 @@
min_val="-500"
name="height_range_spin_2"
top_delta="0"
- width="100" />
+ width="105" />
<!-- Terrain Download/Upload/Bake buttons -->
<button
follows="left|top"
diff --git a/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml
index a29cdb5b41..c03d6a9745 100644
--- a/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml
+++ b/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml
@@ -35,7 +35,7 @@
layout="topleft"
left_delta="15"
top_pad="15"
- width="80">
+ width="86">
Ambient Color:
</text>
<color_swatch
@@ -53,9 +53,9 @@
follows="left"
height="10"
layout="topleft"
- left_delta="90"
+ left_delta="110"
top_delta="-15"
- width="80">
+ width="86">
Blue Horizon:
</text>
<color_swatch
@@ -73,9 +73,9 @@
follows="left"
height="10"
layout="topleft"
- left_delta="90"
+ left_delta="110"
top_delta="-15"
- width="80">
+ width="86">
Blue Density:
</text>
<color_swatch
@@ -166,7 +166,7 @@
layout="topleft"
left_delta="-5"
top_delta="25"
- width="80">
+ width="90">
Moisture Level:
</text>
<slider
@@ -190,7 +190,7 @@
layout="topleft"
left_delta="-5"
top_delta="25"
- width="80">
+ width="90">
Droplet Radius:
</text>
<slider
diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml
index 16111758cc..2d3a8618ed 100644
--- a/indra/newview/skins/default/xui/en/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml
@@ -91,7 +91,7 @@
left="0"
name="balance"
tool_tip="L$ [AMT]&#10;Click to refresh your L$ balance.&#10;Double-click to display or hide your L$ balance."
- v_pad="4"
+ v_pad="2"
top="0"
wrap="false"
value="L$??"
@@ -102,7 +102,7 @@
follows="right|top|bottom"
image_hover_unselected="PushButton_Over"
image_unselected="PushButton_Off"
- image_pressed="PushButton_Press"
+ image_pressed="PushButton_Selected"
height="18"
label="Buy L$"
label_color="White"
@@ -122,7 +122,7 @@
image_overlay_alignment="left"
image_hover_unselected="PushButton_Over"
image_unselected="PushButton_Off"
- image_pressed="PushButton_Press"
+ image_pressed="PushButton_Selected"
height="18"
label="Shop"
label_color="White"
@@ -140,7 +140,7 @@
follows="right|top"
halign="right"
height="16"
- top="5"
+ top="3"
layout="topleft"
left_pad="0"
name="TimeText"
diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
index 1c70383bf9..5ff02de6f6 100644
--- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml
+++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
@@ -51,7 +51,9 @@
name="color label"
text_readonly_color="LabelDisabledColor"
top="6"
- width="64">
+ width="64"
+ font="DejaVu"
+ font.size="LSmall" >
Color
</text>
<!-- label is blank because control places it below the box -->
@@ -77,7 +79,9 @@
name="color trans"
text_readonly_color="LabelDisabledColor"
top="6"
- width="110">
+ width="110"
+ font="DejaVu"
+ font.size="LSmall" >
Transparency %
</text>
<spinner
@@ -91,7 +95,9 @@
max_val="100"
name="ColorTrans"
top_pad="4"
- width="80" />
+ width="80"
+ font="DejaVu"
+ font.size="LSmall" />
<text
type="string"
length="1"
@@ -102,7 +108,9 @@
name="glow label"
text_readonly_color="LabelDisabledColor"
top="6"
- width="80">
+ width="80"
+ font="DejaVu"
+ font.size="LSmall" >
Glow
</text>
<spinner
@@ -114,7 +122,9 @@
left_delta="0"
name="glow"
top_pad="4"
- width="77" />
+ width="77"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
height="19"
label="Full Bright"
@@ -122,7 +132,9 @@
left="7"
name="checkbox fullbright"
top_pad="4"
- width="81" />
+ width="81"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
height="19"
label="Hide water"
@@ -130,7 +142,9 @@
left="172"
top_delta="0"
name="checkbox_hide_water"
- width="81" />
+ width="81"
+ font="DejaVu"
+ font.size="LSmall" />
<view_border
bevel_style="none"
follows="top|left"
@@ -139,7 +153,9 @@
left="8"
name="object_horizontal"
top_pad="4"
- width="278" />
+ width="278"
+ font="DejaVu"
+ font.size="LSmall" />
<text
type="string"
length="1"
@@ -149,7 +165,9 @@
left="12"
top_pad="12"
name="label_matmedia"
- width="90">
+ width="90"
+ font="DejaVu"
+ font.size="LSmall" >
Material
</text>
<combo_box
@@ -158,7 +176,9 @@
left="10"
name="combobox matmedia"
top_pad="5"
- width="90">
+ width="90"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall" >
<combo_box.item
label="Textures"
name="Materials"
@@ -179,7 +199,9 @@
top_delta="-20"
width="150"
visible = "false"
- name="radio_material_type">
+ name="radio_material_type"
+ font="DejaVu"
+ font.size="LSmall" >
<radio_item
label="Texture (diffuse)"
name="Texture (diffuse)"
@@ -209,7 +231,9 @@
top_delta="0"
width="150"
visible = "false"
- name="radio_pbr_type">
+ name="radio_pbr_type"
+ font="DejaVu"
+ font.size="LSmall" >
<radio_item
label="Complete material"
name="Complete material"
@@ -270,7 +294,9 @@
name="checkbox_sync_settings"
tool_tip="Adjust all maps repeats simultaneously"
top_pad="19"
- width="160" />
+ width="160"
+ font="DejaVu"
+ font.size="LSmall" />
<texture_picker
can_apply_immediately="true"
allow_no_texture="true"
@@ -282,7 +308,9 @@
name="pbr_control"
tool_tip="Click to choose a pbr material"
top_pad="5"
- width="64" />
+ width="64"
+ caption_text.font="DejaVu"
+ caption_text.font.size="LSmall" />
<button
follows="left|top"
height="23"
@@ -291,7 +319,9 @@
top_delta="0"
name="pbr_from_inventory"
label="Choose from inventory"
- width="140"/>
+ width="140"
+ font="DejaVu"
+ font.size="LSmall" />
<text
visible="false"
type="string"
@@ -303,7 +333,9 @@
left_delta="0"
name="material_permissions_loading_label"
text_readonly_color="LabelDisabledColor"
- width="160">
+ width="160"
+ font="DejaVu"
+ font.size="LSmall" >
Loading contents...
</text>
<button
@@ -314,7 +346,9 @@
top_delta="0"
name="edit_selected_pbr"
label="Edit Selected"
- width="140"/>
+ width="140"
+ font="DejaVu"
+ font.size="LSmall" />
<button
follows="left|top"
height="23"
@@ -323,7 +357,9 @@
top_pad="4"
name="save_selected_pbr"
label="Save to inventory"
- width="140"/>
+ width="140"
+ font="DejaVu"
+ font.size="LSmall" />
<texture_picker
can_apply_immediately="true"
default_image_name="Default"
@@ -336,7 +372,9 @@
name="texture control"
tool_tip="Click to choose a picture"
top_delta="-54"
- width="64" />
+ width="64"
+ caption_text.font="DejaVu"
+ caption_text.font.size="LSmall" />
<text
type="string"
length="1"
@@ -347,7 +385,9 @@
name="label alphamode"
text_readonly_color="LabelDisabledColor"
top_delta="0"
- width="90">
+ width="90"
+ font="DejaVu"
+ font.size="LSmall" >
Alpha mode
</text>
<combo_box
@@ -356,7 +396,9 @@
left_delta="0"
name="combobox alphamode"
top_pad="4"
- width="120">
+ width="120"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall">
<combo_box.item
label="None"
name="None"
@@ -384,7 +426,9 @@
name="label maskcutoff"
text_readonly_color="LabelDisabledColor"
top_pad="4"
- width="90">
+ width="90"
+ font="DejaVu"
+ font.size="LSmall" >
Mask cutoff
</text>
<spinner
@@ -399,7 +443,9 @@
left_delta="0"
increment="1"
name="maskcutoff"
- width="80" />
+ width="80"
+ font="DejaVu"
+ font.size="LSmall" />
<texture_picker
allow_no_texture="true"
can_apply_immediately="true"
@@ -413,7 +459,9 @@
name="bumpytexture control"
tool_tip="Click to choose a picture"
top_delta="-55"
- width="64" />
+ width="64"
+ caption_text.font="DejaVu"
+ caption_text.font.size="LSmall" />
<text
type="string"
length="1"
@@ -424,7 +472,9 @@
name="label bumpiness"
text_readonly_color="LabelDisabledColor"
top_delta="0"
- width="90">
+ width="90"
+ font="DejaVu"
+ font.size="LSmall" >
Bumpiness
</text>
<combo_box
@@ -433,7 +483,9 @@
left_delta="0"
name="combobox bumpiness"
top_pad="4"
- width="90">
+ width="90"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall" >
<combo_box.item
label="None"
name="None"
@@ -527,7 +579,9 @@
name="shinytexture control"
tool_tip="Click to choose a picture"
top_delta="-14"
- width="64" />
+ width="64"
+ caption_text.font="DejaVu"
+ caption_text.font.size="LSmall" />
<text
type="string"
length="1"
@@ -538,7 +592,9 @@
left_pad="10"
text_readonly_color="LabelDisabledColor"
top_delta="4"
- width="90">
+ width="90"
+ font="DejaVu"
+ font.size="LSmall" >
Shininess
</text>
<combo_box
@@ -547,7 +603,9 @@
left_pad="10"
name="combobox shininess"
top_delta="-6"
- width="90">
+ width="90"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall" >
<combo_box.item
label="None"
name="None"
@@ -582,7 +640,9 @@
name="label glossiness"
text_readonly_color="LabelDisabledColor"
top_pad="7"
- width="116">
+ width="116"
+ font="DejaVu"
+ font.size="LSmall" >
Glossiness
</text>
<spinner
@@ -597,7 +657,9 @@
top_delta="-4"
left_pad="10"
name="glossiness"
- width="64" />
+ width="64"
+ font="DejaVu"
+ font.size="LSmall" />
<text
type="string"
length="1"
@@ -608,7 +670,9 @@
name="label environment"
text_readonly_color="LabelDisabledColor"
top_pad="8"
- width="116">
+ width="116"
+ font="DejaVu"
+ font.size="LSmall" >
Environment
</text>
<spinner
@@ -623,7 +687,9 @@
top_delta="-4"
left_pad="10"
name="environment"
- width="64" />
+ width="64"
+ font="DejaVu"
+ font.size="LSmall" />
<text
type="string"
length="1"
@@ -634,7 +700,9 @@
name="label shinycolor"
text_readonly_color="LabelDisabledColor"
top_pad="8"
- width="116">
+ width="116"
+ font="DejaVu"
+ font.size="LSmall" >
Color
</text>
<!-- label is blank because control places it below the box -->
@@ -658,7 +726,9 @@
use_ellipses="true"
read_only="true"
name="media_info"
- width="280">
+ width="280"
+ font="DejaVu"
+ font.size="LSmall" >
URL of chosen media, if any, goes here
</text>
<button
@@ -670,7 +740,9 @@
top_pad="4"
tool_tip="Add Media"
label="Choose..."
- width="85"/>
+ width="85"
+ font="DejaVu"
+ font.size="LSmall" />
<button
follows="top|left"
height="18"
@@ -680,7 +752,9 @@
tool_tip="Delete this media texture"
top_delta="0"
label="Remove"
- width="85"/>
+ width="85"
+ font="DejaVu"
+ font.size="LSmall" />
<button
follows="left|top"
height="18"
@@ -691,7 +765,9 @@
name="button align"
top_delta="0"
tool_tip="Align media texture (must load first)"
- width="85" />
+ width="85"
+ font="DejaVu"
+ font.size="LSmall" />
<text
type="string"
length="1"
@@ -702,7 +778,9 @@
name="tex gen"
text_readonly_color="LabelDisabledColor"
top_pad="46"
- width="140">
+ width="140"
+ font="DejaVu"
+ font.size="LSmall" >
Mapping
</text>
<combo_box
@@ -711,7 +789,9 @@
left_pad="0"
name="combobox texgen"
top_pad="-13"
- width="125">
+ width="125"
+ drop_down_button.font="DejaVu"
+ drop_down_button.font.size="LSmall" >
<combo_box.item
label="Default"
name="Default"
@@ -733,7 +813,9 @@
max_val="10000"
name="TexScaleU"
top_pad="5"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -745,7 +827,9 @@
min_val="-10000"
max_val="10000"
name="TexScaleV"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
decimal_digits="1"
follows="left|top"
@@ -758,7 +842,9 @@
max_val="100"
min_val="-100"
name="rptctrl"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
decimal_digits="2"
follows="left|top"
@@ -772,7 +858,9 @@
max_val="360"
min_val="-360"
name="TexRot"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -784,7 +872,9 @@
min_val="-1"
max_val="1"
name="TexOffsetU"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -796,7 +886,9 @@
min_val="-1"
max_val="1"
name="TexOffsetV"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -809,7 +901,9 @@
max_val="10000"
name="bumpyScaleU"
top_delta="-115"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -821,7 +915,9 @@
min_val="-10000"
max_val="10000"
name="bumpyScaleV"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
decimal_digits="2"
follows="left|top"
@@ -836,7 +932,9 @@
max_val="360"
min_val="-360"
name="bumpyRot"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -848,7 +946,9 @@
min_val="-1"
max_val="1"
name="bumpyOffsetU"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -860,7 +960,9 @@
min_val="-1"
max_val="1"
name="bumpyOffsetV"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -873,7 +975,9 @@
max_val="10000"
name="shinyScaleU"
top_delta="-115"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -885,7 +989,9 @@
min_val="-10000"
max_val="10000"
name="shinyScaleV"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
decimal_digits="2"
follows="left|top"
@@ -900,7 +1006,9 @@
max_val="360"
min_val="-360"
name="shinyRot"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -912,7 +1020,9 @@
min_val="-1"
max_val="1"
name="shinyOffsetU"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -924,7 +1034,9 @@
min_val="-1"
max_val="1"
name="shinyOffsetV"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<check_box
follows="top|left"
height="16"
@@ -935,7 +1047,9 @@
name="checkbox planar align"
tool_tip="Align textures on all selected faces with the last selected face. Requires Planar texture mapping."
top_delta="20"
- width="260" />
+ width="260"
+ font="DejaVu"
+ font.size="LSmall" />
<button
follows="left|top"
layout="topleft"
@@ -946,7 +1060,9 @@
label_selected="Align current texture layers"
name="button align textures"
tool_tip="Align current texture layers"
- width="66" />
+ width="66"
+ font="DejaVu"
+ font.size="LSmall" />
<web_browser
visible="false"
enabled="false"
@@ -972,7 +1088,9 @@
max_val="10000"
name="gltfTextureScaleU"
top_delta="34"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -984,7 +1102,9 @@
min_val="-10000"
max_val="10000"
name="gltfTextureScaleV"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
decimal_digits="1"
follows="left|top"
@@ -997,7 +1117,9 @@
max_val="100"
min_val="-100"
name="gltfRptctrl"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -1009,7 +1131,9 @@
min_val="-360"
max_val="360"
name="gltfTextureRotation"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -1021,7 +1145,9 @@
min_val="-999"
max_val="999"
name="gltfTextureOffsetU"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<spinner
follows="left|top"
height="19"
@@ -1033,6 +1159,8 @@
min_val="-999"
max_val="999"
name="gltfTextureOffsetV"
- width="265" />
+ width="265"
+ font="DejaVu"
+ font.size="LSmall" />
<!-- END PBR Material texture transform parameters -->
</panel>
diff --git a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml
index a16b0b58da..bc0350c446 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml
@@ -29,7 +29,7 @@ width="333">
background_visible="true"
bg_opaque_color="DkGray2"
left="10"
- top="5"
+ top="0"
follows="left|top|right"
layout="topleft"
width="307"
@@ -50,25 +50,15 @@ width="333">
layout="topleft"
name="openoutfit_btn"
visible="false" />
- <icon
- follows="top|left"
- height="31"
- image_name="Shirt_Large"
- name="outfit_icon"
- mouse_opaque="false"
- visible="true"
- left="1"
- top="0"
- width="31" />
<text
- font="SansSerifSmall"
+ font="SansSerifSmallBold"
text_color="EmphasisColor"
width="300"
height="13"
follows="top|left|right"
layout="topleft"
- left="35"
- top="3"
+ left="5"
+ top="0"
mouse_opaque="false"
name="currentlook_status" >
(Status)
@@ -76,7 +66,7 @@ width="333">
<text
font="SansSerifLargeBold"
height="20"
- left="35"
+ left="5"
parse_urls="false"
text_color="White"
top="15"
diff --git a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml
index de47e05291..3fc22d69ca 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml
@@ -69,7 +69,6 @@
<button
control_name="InventoryInboxToggleState"
label="Received items"
- font="SansSerifMedium"
name="inbox_btn"
height="35"
image_unselected="MarketplaceBtn_Off"
@@ -92,7 +91,6 @@
top="10"
right="-20"
name="inbox_fresh_new_count"
- font="SansSerifMedium"
halign="right"
top_pad="0">
[NUM] new
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 43a4ba2e23..a6fb6db63d 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -116,6 +116,8 @@ Voice Server Version: [VOICE_VERSION]
<string name="AgniGridLabel">Second Life Main Grid (Agni)</string>
<string name="AditiGridLabel">Second Life Beta Test Grid (Aditi)</string>
+ <string name="AgniGridLabelShort">Agni (production)</string>
+ <string name="AditiGridLabelShort">Aditi (beta)</string>
<string name="ViewerDownloadURL">http://secondlife.com/download</string>
<string name="LoginFailedViewerNotPermitted">
diff --git a/indra/newview/skins/default/xui/en/widgets/button.xml b/indra/newview/skins/default/xui/en/widgets/button.xml
index 090447a6a2..c7669e81af 100644
--- a/indra/newview/skins/default/xui/en/widgets/button.xml
+++ b/indra/newview/skins/default/xui/en/widgets/button.xml
@@ -11,7 +11,7 @@
image_top_pad="0"
image_bottom_pad="0"
imgoverlay_label_space="1"
- label_color="ButtonLabelColor"
+ label_color="White"
label_color_selected="ButtonLabelSelectedColor"
label_color_disabled="ButtonLabelDisabledColor"
label_color_disabled_selected="ButtonLabelSelectedDisabledColor"
@@ -21,9 +21,10 @@
font="SansSerifSmall"
hover_glow_amount="0.15"
halign="center"
- pad_bottom="1"
+ pad_bottom="2"
height="23"
scale_image="true"
+ label_shadow="false"
handle_right_mouse="true"
use_draw_context_alpha="true"
held_down_delay.seconds="0.5"
diff --git a/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml b/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml
index cf995e5833..ebe2fa07e2 100644
--- a/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml
+++ b/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml
@@ -9,7 +9,7 @@
left_pad="0"
icon_pad="10"
icon_width="20"
- text_pad="7"
+ text_pad="5"
text_pad_right="4"
arrow_size="12"
max_folder_item_overlap="2"
diff --git a/indra/newview/skins/default/xui/en/widgets/filter_editor.xml b/indra/newview/skins/default/xui/en/widgets/filter_editor.xml
index 604f62b099..3a0f43de3d 100644
--- a/indra/newview/skins/default/xui/en/widgets/filter_editor.xml
+++ b/indra/newview/skins/default/xui/en/widgets/filter_editor.xml
@@ -7,10 +7,10 @@
select_on_focus="true"
text_tentative_color="TextFgTentativeColor"
highlight_text_field="true"
- background_image="TextField_Search_Off"
- background_image_disabled="TextField_Search_Disabled"
- background_image_focused="TextField_Search_Active"
- background_image_highlight="TextField_Search_Highlight">
+ background_image="TextField_Off"
+ background_image_disabled="TextField_Disabled"
+ background_image_focused="TextField_Active"
+ background_image_highlight="TextField_Highlight">
<search_button label=""
top_pad="4"
left_pad="4"
diff --git a/indra/newview/skins/default/xui/en/widgets/floater.xml b/indra/newview/skins/default/xui/en/widgets/floater.xml
index 11758556d6..73c6dc5d7a 100644
--- a/indra/newview/skins/default/xui/en/widgets/floater.xml
+++ b/indra/newview/skins/default/xui/en/widgets/floater.xml
@@ -9,7 +9,9 @@
bg_alpha_image="Window_Background"
background_visible="true"
background_opaque="false"
+ header_font="SansSerif"
header_height="25"
+ header_vpad="5"
close_image="Icon_Close_Foreground"
restore_image="Icon_Restore_Foreground"
minimize_image="Icon_Minimize_Foreground"
diff --git a/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml b/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml
index 50c5285e04..671cb37ca3 100644
--- a/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml
+++ b/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml
@@ -3,16 +3,21 @@
folder_arrow_image="Folder_Arrow"
favorite_image="Inv_Favorite_Star_Full"
favorite_content_image="Inv_Favorite_Star_Content"
- folder_indentation="8"
- item_height="20"
+ folder_indentation="10"
+ item_height="21"
item_top_pad="4"
selection_image="Rounded_Square"
mouse_opaque="true"
follows="left|top|right"
left_pad="5"
- icon_pad="2"
+ icon_pad="4"
icon_width="16"
- text_pad="1"
+ text_pad="5"
text_pad_right="4"
+ text_pad_top="0"
arrow_size="12"
max_folder_item_overlap="2"/>
+
+<!-- Potential properties not included above:
+ arrow_pad_top
+-->
diff --git a/indra/newview/skins/default/xui/en/widgets/gesture_combo_list.xml b/indra/newview/skins/default/xui/en/widgets/gesture_combo_list.xml
index 14cd3e159c..499152f060 100644
--- a/indra/newview/skins/default/xui/en/widgets/gesture_combo_list.xml
+++ b/indra/newview/skins/default/xui/en/widgets/gesture_combo_list.xml
@@ -10,7 +10,7 @@
mouse_opaque="false"
scale_image="true"
image_selected="PushButton_Selected_Press"
- image_pressed="PushButton_Press"
+ image_pressed="PushButton_Selected"
image_pressed_selected="PushButton_Selected_Press"
image_unselected="PushButton_Off"
image_disabled="PushButton_Disabled"
diff --git a/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml b/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml
index 865c145022..41ef9d2b8a 100644
--- a/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml
+++ b/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml
@@ -6,7 +6,7 @@
folder_indentation="8"
item_height="20"
item_top_pad="4"
- selection_image="Rounded_Square"
+ selection_image="Square_Selection"
left_pad="5"
icon_pad="2"
icon_width="16"
diff --git a/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_item.xml b/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_item.xml
index 09cbb1d3ab..ad4249da4e 100644
--- a/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_item.xml
+++ b/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_item.xml
@@ -2,7 +2,7 @@
<inbox_folder_view_item
item_height="20"
item_top_pad="4"
- selection_image="Rounded_Square"
+ selection_image="Square_Selection"
>
<new_badge
label="New"
diff --git a/indra/newview/skins/default/xui/en/widgets/inventory_list_item.xml b/indra/newview/skins/default/xui/en/widgets/inventory_list_item.xml
index ce36a39a21..b00b8a241b 100644
--- a/indra/newview/skins/default/xui/en/widgets/inventory_list_item.xml
+++ b/indra/newview/skins/default/xui/en/widgets/inventory_list_item.xml
@@ -17,7 +17,7 @@
<worn_style
font="SansSerifSmall"
font.style="BOLD"
- color="EmphasisColor" />
+ color="WornOutfitTextColor" />
<item_icon
height="16"
follows="top|left"
diff --git a/indra/newview/skins/default/xui/en/widgets/line_editor.xml b/indra/newview/skins/default/xui/en/widgets/line_editor.xml
index ae642e1da5..cf6dc0a8c0 100644
--- a/indra/newview/skins/default/xui/en/widgets/line_editor.xml
+++ b/indra/newview/skins/default/xui/en/widgets/line_editor.xml
@@ -11,7 +11,7 @@
text_pad_left="2"
text_readonly_color="TextFgReadOnlyColor"
text_tentative_color="TextFgTentativeColor"
- highlight_color="EmphasisColor"
+ highlight_color="SelectionColor"
preedit_bg_color="White"
mouse_opaque="true"
name="line_editor"
diff --git a/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml b/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml
index ea49b750d1..6824080b49 100644
--- a/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml
+++ b/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml
@@ -55,7 +55,6 @@
width="30" />
<panel_camera_item.text
follows="top|left|right"
- font="SansSerifMedium"
height="15"
layout="topleft"
left ="38"
diff --git a/indra/newview/skins/default/xui/en/widgets/search_editor.xml b/indra/newview/skins/default/xui/en/widgets/search_editor.xml
index 51144c92b6..8294b96799 100644
--- a/indra/newview/skins/default/xui/en/widgets/search_editor.xml
+++ b/indra/newview/skins/default/xui/en/widgets/search_editor.xml
@@ -8,10 +8,10 @@
select_on_focus="true"
text_tentative_color="TextFgTentativeColor"
highlight_text_field="true"
- background_image="TextField_Search_Off"
- background_image_disabled="TextField_Search_Disabled"
- background_image_focused="TextField_Search_Active"
- background_image_highlight="TextField_Search_Highlight">
+ background_image="TextField_Off"
+ background_image_disabled="TextField_Disabled"
+ background_image_focused="TextField_Active"
+ background_image_highlight="TextField_Highlight">
<search_button
top_pad="4"
left_pad="4"
diff --git a/indra/newview/skins/default/xui/en/widgets/simple_text_editor.xml b/indra/newview/skins/default/xui/en/widgets/simple_text_editor.xml
index b99010e17a..041470d0d2 100644
--- a/indra/newview/skins/default/xui/en/widgets/simple_text_editor.xml
+++ b/indra/newview/skins/default/xui/en/widgets/simple_text_editor.xml
@@ -15,12 +15,12 @@
default_color="TextDefaultColor"
text_color="TextFgColor"
text_readonly_color="TextFgReadOnlyColor"
- text_selected_color="White"
+ text_selected_color="Black"
h_pad="6"
v_pad="4"
bg_visible="true"
bg_readonly_color="TextBgReadOnlyColor"
bg_writeable_color="TextBgWriteableColor"
- bg_selected_color="EmphasisColor"
+ bg_selected_color="SelectionColor"
bg_focus_color="TextBgFocusColor">
</simple_text_editor>
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 22955fe73d..63613d34cb 100644
--- a/indra/newview/skins/default/xui/en/widgets/tab_container.xml
+++ b/indra/newview/skins/default/xui/en/widgets/tab_container.xml
@@ -6,10 +6,11 @@ label_pad_left - padding to the left of tab button labels
<tab_container name="tab_container"
mouse_opaque="false"
tab_min_width="60"
- tab_max_width="150"
+ tab_max_width="160"
use_custom_icon_ctrl="false"
halign="center"
- font="SansSerifSmall"
+ font="SansSerif"
+ font.size="Small"
tab_height="21"
label_pad_bottom="1"
label_pad_left="4">
@@ -19,22 +20,22 @@ label_pad_left - padding to the left of tab button labels
tab_left_image_flash
tab_top_image_flash
-->
- <first_tab tab_top_image_unselected="TabTop_Left_Off"
- tab_top_image_selected="TabTop_Left_Selected"
+ <first_tab tab_top_image_unselected="TabTop_First_Flat_Off"
+ tab_top_image_selected="TabTop_First_Flat_Selected"
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_Selected_Over"/>
- <middle_tab tab_top_image_unselected="TabTop_Middle_Off"
- tab_top_image_selected="TabTop_Middle_Selected"
+ tab_left_image_unselected="TabLeft_Flat_Off"
+ tab_left_image_selected="TabLeft_Flat_Selected"/>
+ <middle_tab tab_top_image_unselected="TabTop_Middle_Flat_Off"
+ tab_top_image_selected="TabTop_Middle_Flat_Selected"
tab_bottom_image_unselected="Toolbar_Middle_Off"
tab_bottom_image_selected="Toolbar_Middle_Selected"
- tab_left_image_unselected="SegmentedBtn_Left_Disabled"
- tab_left_image_selected="SegmentedBtn_Left_Selected_Over"/>
- <last_tab tab_top_image_unselected="TabTop_Right_Off"
- tab_top_image_selected="TabTop_Right_Selected"
+ tab_left_image_unselected="TabLeft_Flat_Off"
+ tab_left_image_selected="TabLeft_Flat_Selected"/>
+ <last_tab tab_top_image_unselected="TabTop_Last_Flat_Off"
+ tab_top_image_selected="TabTop_Last_Flat_Selected"
tab_bottom_image_unselected="Toolbar_Right_Off"
tab_bottom_image_selected="Toolbar_Right_Selected"
- tab_left_image_unselected="SegmentedBtn_Left_Disabled"
- tab_left_image_selected="SegmentedBtn_Left_Selected_Over"/>
+ tab_left_image_unselected="TabLeft_Flat_Off"
+ tab_left_image_selected="TabLeft_Flat_Selected"/>
</tab_container>
diff --git a/indra/newview/skins/default/xui/en/widgets/toolbar.xml b/indra/newview/skins/default/xui/en/widgets/toolbar.xml
index 8345911525..a038fe5181 100644
--- a/indra/newview/skins/default/xui/en/widgets/toolbar.xml
+++ b/indra/newview/skins/default/xui/en/widgets/toolbar.xml
@@ -15,16 +15,17 @@
<button_icon_and_text imgoverlay_label_space="7"
label_color_selected="White"
halign="left"
- image_pressed="PushButton_Press"
+ image_pressed="PushButton_Selected"
image_pressed_selected="PushButton_Selected_Press"
image_selected="PushButton_Selected_Press"
image_disabled_selected="PushButton_Selected_Disabled"
image_disabled="PushButton_Disabled"
button_width.min="70"
- button_width.max="140"
+ button_width.max="172"
desired_height="24"
pad_left="10"
pad_right="10"
+ pad_bottom="1"
follows="left|top"
chrome="true"
image_overlay_alignment="left"
@@ -37,7 +38,7 @@
pad_right="10"
image_bottom_pad="10"
image_top_pad="10"
- image_pressed="PushButton_Press"
+ image_pressed="PushButton_Selected"
image_pressed_selected="PushButton_Selected_Press"
image_selected="PushButton_Selected_Press"
image_disabled_selected="PushButton_Selected_Disabled"
diff --git a/indra/newview/skins/default/xui/en/widgets/wearable_outfit_list_item.xml b/indra/newview/skins/default/xui/en/widgets/wearable_outfit_list_item.xml
index aa235e103b..a0b119ed72 100644
--- a/indra/newview/skins/default/xui/en/widgets/wearable_outfit_list_item.xml
+++ b/indra/newview/skins/default/xui/en/widgets/wearable_outfit_list_item.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<inventory_list_item
follows="top|right|left"
- height="20"
+ height="21"
name="inventory_item"
tab_stop="false"
hover_image="ListItem_Over"
@@ -17,7 +17,7 @@
<worn_style
font="SansSerifSmall"
font.style="BOLD"
- color="EmphasisColor" />
+ color="WornOutfitTextColor" />
<item_icon
height="16"
follows="top|left"
@@ -25,18 +25,18 @@
layout="topleft"
left="0"
name="item_icon"
- top="0"
+ top="1"
width="16" />
<item_name
follows="left|right"
- height="20"
+ height="21"
layout="topleft"
left="21"
parse_urls="false"
use_ellipses="true"
name="item_name"
text_color="white"
- top="4"
+ top="2"
value="..."
width="359" />
<add_btn
diff --git a/indra/newview/skins/default/xui/es/panel_login_first.xml b/indra/newview/skins/default/xui/es/panel_login_first.xml
deleted file mode 100644
index ccb6858351..0000000000
--- a/indra/newview/skins/default/xui/es/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php?lang=es
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Nombre de usuario" name="username_combo" tool_tip="El nombre de usuario que elegiste al registrarte, como bobsmith12 o Steller Sunshine"/>
- <line_editor label="Contraseña" name="password_edit"/>
- <button label="Iniciar sesión" name="connect_btn"/>
- <check_box label="Recordarme" name="remember_check"/>
- <text name="forgot_password_text">
- Contraseña olvidada
- </text>
- <text name="sign_up_text">
- Regístrate
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Tu primer destino es la Isla de aprendizaje. ¡Encuentra el portal de salida!
- </text>
- <text name="image_caption_right">
- A continuación, puedes explorar la Isla social y hablar con otros residentes nuevos.
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_login_first.xml b/indra/newview/skins/default/xui/fr/panel_login_first.xml
deleted file mode 100644
index 8f40d0230c..0000000000
--- a/indra/newview/skins/default/xui/fr/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php?lang=fr
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Nom d&apos;utilisateur" name="username_combo" tool_tip="Nom d&apos;utilisateur que vous avez choisi lors de votre inscription (par exemple, bobsmith12 ou Steller Sunshine)."/>
- <line_editor label="Mot de passe" name="password_edit"/>
- <button label="Connexion" name="connect_btn"/>
- <check_box font="SansSerifSmall" label="Mémoriser mes informations" name="remember_check"/>
- <text name="forgot_password_text">
- Mot de passe oublié
- </text>
- <text name="sign_up_text">
- S&apos;inscrire
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Votre première étape est Learning Island. Trouvez le portail de sortie.
- </text>
- <text name="image_caption_right">
- Puis explorez Social Island et faites la connaissance d&apos;autres résidents.
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_login_first.xml b/indra/newview/skins/default/xui/it/panel_login_first.xml
deleted file mode 100644
index 5b04fd411a..0000000000
--- a/indra/newview/skins/default/xui/it/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php?lang=it
- </panel.string>
- <panel.string name="sign_up_url">
- http://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Nome utente" name="username_combo" tool_tip="Il nome utente che hai scelto durante la registrazione, come roby12 o Stella Solare"/>
- <line_editor label="Password" name="password_edit"/>
- <button label="Accedi" name="connect_btn"/>
- <check_box label="Ricordami" name="remember_check"/>
- <text name="forgot_password_text">
- Password dimenticata
- </text>
- <text name="sign_up_text">
- Registrati
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Il primo passo è a Learning Island. Trova il portale di uscita!
- </text>
- <text name="image_caption_right">
- Quindi esplora Social Island e incontra altri nuovi residenti.
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/ja/fonts.xml b/indra/newview/skins/default/xui/ja/fonts.xml
index 2085e916c8..7abb3593b6 100644
--- a/indra/newview/skins/default/xui/ja/fonts.xml
+++ b/indra/newview/skins/default/xui/ja/fonts.xml
@@ -2,11 +2,9 @@
<fonts>
<font name="default" comment="default font files (global fallbacks)">
<file>
- NotoSansCJKjp-Medium.otf
- </file>
- <file>
- DejaVuSans.ttf
+ NotoSansCJKjp-SemiBold.otf
</file>
+ <file load_collection="true" font_weight="400">InterVariableFont.ttf</file>
<os name="Windows">
<file load_collection="true">
YuGothM.ttc
@@ -41,7 +39,7 @@
</os>
<os name="Mac">
<file>
- YuGothic-Medium.otf
+ YuGothic-SemiBold.otf
</file>
<file>
ヒラギノ角ゴシック W3.ttc
@@ -82,9 +80,7 @@
<file>
NotoSansCJKjp-Bold.otf
</file>
- <file>
- DejaVuSans-Bold.ttf
- </file>
+ <file load_collection="true" font_weight="700" flags="bold">InterVariableFont.ttf</file>
<os name="Windows">
<file load_collection="true">
YuGothB.ttc
@@ -104,11 +100,9 @@
</font>
<font name="SansSerif" comment="Name of san-serif font (Truetype file name)">
<file>
- NotoSansCJKjp-Bold.otf
- </file>
- <file>
- DejaVuSans.ttf
+ NotoSansCJKjp-SemiBold.otf
</file>
+ <file load_collection="true" font_weight="400">InterVariableFont.ttf</file>
<os name="Windows">
<file>
arial.ttf
@@ -121,19 +115,13 @@
</os>
</font>
<font name="SansSerif" comment="Name of bold sans-serif font" font_style="BOLD">
- <file>
- DejaVuSans-Bold.ttf
- </file>
+ <file load_collection="true" font_weight="700" flags="bold">InterVariableFont.ttf</file>
</font>
<font name="SansSerif" comment="Name of italic sans-serif font" font_style="ITALIC">
- <file>
- DejaVuSans-Oblique.ttf
- </file>
+ <file load_collection="true" font_weight="400">InterItalicVariableFont.ttf</file>
</font>
<font name="SansSerif" comment="Name of bold italic sans-serif font" font_style="BOLD|ITALIC">
- <file>
- DejaVuSans-BoldOblique.ttf
- </file>
+ <file load_collection="true" flags="bold" font_weight="700">InterItalicVariableFont.ttf</file>
</font>
<font name="Monospace" comment="Name of monospace font">
<file>
@@ -144,29 +132,25 @@
</file>
</font>
<font name="DejaVu" comment="Name of DejaVu font">
- <file>
- DejaVuSans.ttf
- </file>
+ <file>DejaVuSans.ttf</file>
</font>
<font name="DejaVu" comment="Name of DejaVu font (bold)" font_style="BOLD">
- <file>
- DejaVuSans-Bold.ttf
- </file>
+ <file>
+ DejaVuSans-Bold.ttf
+ </file>
</font>
<font name="DejaVu" comment="Name of DejaVu font (italic)" font_style="ITALIC">
- <file>
- DejaVuSans-Oblique.ttf
- </file>
+ <file>
+ DejaVuSans-Oblique.ttf
+ </file>
</font>
<font name="DejaVu" comment="Name of DejaVu font (bold italic)" font_style="BOLD|ITALIC">
- <file>
- DejaVuSans-BoldOblique.ttf
- </file>
+ <file>
+ DejaVuSans-BoldOblique.ttf
+ </file>
</font>
<font name="Helvetica" comment="Name of Helvetica font">
- <file>
- DejaVuSans.ttf
- </file>
+ <file load_collection="true" font_weight="400">InterVariableFont.ttf</file>
<os name="Windows">
<file>
arial.ttf
@@ -179,9 +163,7 @@
</os>
</font>
<font name="Helvetica" comment="Name of Helvetica font (bold)" font_style="BOLD">
- <file>
- DejaVuSans-Bold.ttf
- </file>
+ <file load_collection="true" font_weight="700" flags="bold">InterVariableFont.ttf</file>
<os name="Windows">
<file>
arialbd.ttf
@@ -194,9 +176,7 @@
</os>
</font>
<font name="Helvetica" comment="Name of Helvetica font (italic)" font_style="ITALIC">
- <file>
- DejaVuSans-Oblique.ttf
- </file>
+ <file load_collection="true" font_weight="400">InterItalicVariableFont.ttf</file>
<os name="Windows">
<file>
ariali.ttf
@@ -209,9 +189,7 @@
</os>
</font>
<font name="Helvetica" comment="Name of Helvetica font (bold italic)" font_style="BOLD|ITALIC">
- <file>
- DejaVuSans-BoldOblique.ttf
- </file>
+ <file load_collection="true" flags="bold" font_weight="700">InterItalicVariableFont.ttf</file>
<os name="Windows">
<file>
arialbi.ttf
@@ -227,13 +205,11 @@
<file>
times.ttf
</file>
- <file>
- DejaVuSans.ttf
- </file>
+ <file font_weight="400">InterVariableFont.ttf</file>
</font>
<font_size name="Monospace" comment="Size for monospaced font (points, or 1/72 of an inch)" size="8.0"/>
<font_size name="Huge" comment="Size of huge font (points, or 1/72 of an inch)" size="16.0"/>
- <font_size name="Large" comment="Size of large font (points, or 1/72 of an inch)" size="10.6"/>
- <font_size name="Medium" comment="Size of medium font (points, or 1/72 of an inch)" size="8.6"/>
- <font_size name="Small" comment="Size of small font (points, or 1/72 of an inch)" size="7.6"/>
+ <font_size name="Large" comment="Size of large font (points, or 1/72 of an inch)" size="11"/>
+ <font_size name="Medium" comment="Size of medium font (points, or 1/72 of an inch)" size="9"/>
+ <font_size name="Small" comment="Size of small font (points, or 1/72 of an inch)" size="8"/>
</fonts>
diff --git a/indra/newview/skins/default/xui/ja/panel_login_first.xml b/indra/newview/skins/default/xui/ja/panel_login_first.xml
deleted file mode 100644
index 0f987fc816..0000000000
--- a/indra/newview/skins/default/xui/ja/panel_login_first.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- https://secondlife.com/my/account/request.php?lang=ja-JP
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/?lang=ja
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="page_top"/>
- <layout_panel name="parent_panel">
- <layout_stack name="logo_stack">
- <layout_panel name="logo_left"/>
- <layout_panel name="logo_container">
- <icon name="sl_logo"/>
- </layout_panel>
- <layout_panel auto_resize="true"/>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_left"/>
- <layout_panel name="widget_container">
- <combo_box label="ユーザ名" tool_tip="登録時に自分で選んだユーザー名(例:bobsmith12、Steller Sunshineなど)" name="username_combo">
- <combo_box.combo_editor/>
- <combo_box.combo_button/>
- <combo_box.drop_down_button/>
- </combo_box>
- <line_editor name="password_edit" label="パスワード"/>
- <button label="ログイン" name="connect_btn"/>
- <text name="sign_up_text" valign="center">
- サインアップ
- </text>
- <check_box label="ユーザ名を記憶" name="remember_name" tool_tip="すでに記憶されているユーザーは、「私」>「初期設定」>「詳細設定」>「記憶されたユーザー名」から削除できます。"/>
- <check_box label="パスワード記憶" name="remember_password"/>
- <text name="forgot_password_text">
- パスワードを忘れましたか?
- </text>
- </layout_panel>
- <layout_panel name="widget_right"/>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_left"/>
- <layout_panel name="images_container">
- <icon name="image_left"/>
- </layout_panel>
- <layout_panel name="images_right"/>
- </layout_stack>
- </layout_panel>
- <layout_panel name="page_bottom"/>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_login_first.xml b/indra/newview/skins/default/xui/pl/panel_login_first.xml
deleted file mode 100644
index 0604ecbcff..0000000000
--- a/indra/newview/skins/default/xui/pl/panel_login_first.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<panel name="panel_login">
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Użytkownik" tool_tip="Nazwa użytkownika wybrana przy rejestracji, np. bobsmith12 lub Steller Sunshine" name="username_combo" />
- <line_editor name="password_edit" label="Hasło" />
- <button label="Zaloguj" name="connect_btn" />
- <check_box label="Zapamiętaj mnie" name="remember_check" />
- <text name="forgot_password_text">
- Zapomniałem/am hasła
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Wyspa Nauki to Twój pierwszy krok. Znajdź portal z wyjściem!
- </text>
- <text name="image_caption_right">
- Potem zwiedź Wyspę Towarzyską i poznaj innych nowych rezydentów!
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_login_first.xml b/indra/newview/skins/default/xui/pt/panel_login_first.xml
deleted file mode 100644
index 86c61163bc..0000000000
--- a/indra/newview/skins/default/xui/pt/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php?lang=pt
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Nome de usuário" name="username_combo" tool_tip="O nome de usuário que você escolheu ao fazer seu cadastro, como zecazc12 ou Magia Solar"/>
- <line_editor label="Senha" name="password_edit"/>
- <button label="Login" name="connect_btn"/>
- <check_box label="Lembrar-me" name="remember_check"/>
- <text name="forgot_password_text">
- Senha esquecida
- </text>
- <text name="sign_up_text">
- Cadastre-se
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Sua primeira parada é a Ilha da Educação. Encontre o portal de saída!
- </text>
- <text name="image_caption_right">
- Em seguida, explore a Ilha Social e encontre novos residentes!
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_login_first.xml b/indra/newview/skins/default/xui/ru/panel_login_first.xml
deleted file mode 100644
index 5db81ea7ca..0000000000
--- a/indra/newview/skins/default/xui/ru/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Имя пользователя" name="username_combo" tool_tip="Имя пользователя, которое вы выбрали при регистрации, например, «bobsmith12» или «Steller Sunshine»"/>
- <line_editor label="Пароль" name="password_edit"/>
- <button label="Войти" name="connect_btn"/>
- <check_box label="Запомнить меня" name="remember_check"/>
- <text name="forgot_password_text">
- Забытый пароль
- </text>
- <text name="sign_up_text">
- Регистрация
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Ваш первый шаг – Учебный остров. Найдите портал выхода!
- </text>
- <text name="image_caption_right">
- Затем исследуйте Социальный остров и познакомьтесь с другими новичками!
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_login_first.xml b/indra/newview/skins/default/xui/tr/panel_login_first.xml
deleted file mode 100644
index 1fc80c2b97..0000000000
--- a/indra/newview/skins/default/xui/tr/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Kullanıcı Adı" name="username_combo" tool_tip="Kaydolduğunuzda seçtiğiniz kullanıcı adı, örn. mustafayalcin12 veya Faruk Gungoren"/>
- <line_editor label="Parola" name="password_edit"/>
- <button label="Oturum Aç" name="connect_btn"/>
- <check_box label="Beni hatırla" name="remember_check"/>
- <text name="forgot_password_text">
- Parolamı unuttum
- </text>
- <text name="sign_up_text">
- Kaydol
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Başlangıç yeriniz Eğitim Adası. Haydi çıkış portalını bulun!
- </text>
- <text name="image_caption_right">
- Sonra da Sosyal Ada&apos;yı keşfe çıkın ve diğer LS sakinleriyle tanışın!
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/zh/panel_login_first.xml b/indra/newview/skins/default/xui/zh/panel_login_first.xml
deleted file mode 100644
index 4d72fcdd03..0000000000
--- a/indra/newview/skins/default/xui/zh/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php
- </panel.string>
- <panel.string name="sign_up_url">
- http://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="使用者名稱" name="username_combo" tool_tip="使用者名稱是你註冊時所挑選的,例如 bobsmith12 或 Steller Sunshine"/>
- <line_editor label="密碼" name="password_edit"/>
- <button label="登入" name="connect_btn"/>
- <check_box label="記得我" name="remember_check"/>
- <text name="forgot_password_text">
- 忘記密碼
- </text>
- <text name="sign_up_text">
- 註冊
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- 你在「學習島」的第一步。 找到離開的傳送門!
- </text>
- <text name="image_caption_right">
- 接著,到「社交島」探索,認識新的居民朋友!
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/tests/llviewernetwork_test.cpp b/indra/newview/tests/llviewernetwork_test.cpp
index 94cf0fcf10..1cbb8b50eb 100644
--- a/indra/newview/tests/llviewernetwork_test.cpp
+++ b/indra/newview/tests/llviewernetwork_test.cpp
@@ -236,7 +236,7 @@ namespace tut
std::string("https://secondlife.com/helpers/"));
ensure_equals("Agni login page",
LLGridManager::getInstance()->getLoginPage("util.agni.lindenlab.com"),
- std::string("https://viewer-splash.secondlife.com/"));
+ std::string("https://viewer-splash-v2.secondlife.com/"));
ensure("Agni is a system grid",
LLGridManager::getInstance()->isSystemGrid("util.agni.lindenlab.com"));
@@ -261,7 +261,7 @@ namespace tut
std::string("https://secondlife.aditi.lindenlab.com/helpers/"));
ensure_equals("Aditi login page",
LLGridManager::getInstance()->getLoginPage("util.aditi.lindenlab.com"),
- std::string("https://viewer-splash.secondlife.com/"));
+ std::string("https://viewer-splash-v2.secondlife.com/"));
ensure("Aditi is a system grid",
LLGridManager::getInstance()->isSystemGrid("util.aditi.lindenlab.com"));
}
@@ -309,7 +309,7 @@ namespace tut
std::string("https://secondlife.com/helpers/"));
ensure_equals("Agni login page",
LLGridManager::getInstance()->getLoginPage("util.agni.lindenlab.com"),
- std::string("https://viewer-splash.secondlife.com/"));
+ std::string("https://viewer-splash-v2.secondlife.com/"));
ensure("Agni is a system grid",
LLGridManager::getInstance()->isSystemGrid("util.agni.lindenlab.com"));
@@ -333,7 +333,7 @@ namespace tut
std::string("https://secondlife.aditi.lindenlab.com/helpers/"));
ensure_equals("Aditi login page",
LLGridManager::getInstance()->getLoginPage("util.aditi.lindenlab.com"),
- std::string("https://viewer-splash.secondlife.com/"));
+ std::string("https://viewer-splash-v2.secondlife.com/"));
ensure("Aditi is a system grid",
LLGridManager::getInstance()->isSystemGrid("util.aditi.lindenlab.com"));
@@ -422,7 +422,7 @@ namespace tut
std::string("https://secondlife.com/helpers/"));
ensure_equals("getLoginPage",
LLGridManager::getInstance()->getLoginPage(),
- std::string("https://viewer-splash.secondlife.com/"));
+ std::string("https://viewer-splash-v2.secondlife.com/"));
ensure_equals("update url base for Agni", // relies on agni being the default
std::string("https://update.secondlife.com/update"),
LLGridManager::getInstance()->getUpdateServiceURL());
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index c33f4f140a..8e59c26316 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -576,14 +576,6 @@ class Windows_x86_64_Manifest(ViewerManifest):
self.path_optional("vcruntime140_1.dll")
self.path_optional("vcruntime140_threads.dll")
- # SLVoice executable
- with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')):
- self.path("SLVoice.exe")
-
- # Vivox libraries
- self.path("vivoxsdk_x64.dll")
- self.path("ortp_x64.dll")
-
# BugSplat
if self.args.get('bugsplat'):
self.path("BsSndRpt64.exe")
@@ -1139,16 +1131,6 @@ class Darwin_x86_64_Manifest(ViewerManifest):
# Need to get the llcommon dll from any of the build directories as well.
libfile_parent = self.get_dst_prefix()
dylibs=[]
- # SLVoice executable
- with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')):
- self.path("SLVoice")
-
- # Vivox libraries
- for libfile in (
- 'libortp.dylib',
- 'libvivoxsdk.dylib',
- ):
- self.path2basename(relpkgdir, libfile)
# Discord social SDK
if self.args['discord'] == 'ON':
@@ -1475,7 +1457,6 @@ class Linux_i686_Manifest(LinuxManifest):
self.path("libdirect-1.4.so.5*")
self.path("libalut.so*")
self.path("libopenal.so*")
- self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname
# KLUDGE: As of 2012-04-11, the 'fontconfig' package installs
# libfontconfig.so.1.4.4, along with symlinks libfontconfig.so.1
# and libfontconfig.so. Before we added support for library-file
@@ -1505,15 +1486,6 @@ class Linux_i686_Manifest(LinuxManifest):
print("tcmalloc files not found, skipping")
pass
- # Vivox runtimes
- with self.prefix(src=relpkgdir, dst="bin"):
- self.path("SLVoice")
- with self.prefix(src=relpkgdir, dst="lib"):
- self.path("libortp.so")
- self.path("libsndfile.so.1")
- #self.path("libvivoxoal.so.1") # no - we'll re-use the viewer's own OpenAL lib
- self.path("libvivoxsdk.so")
-
self.strip_binaries()