diff --git a/indra/integration_tests/llui_libtest/llwidgetreg.cpp b/indra/integration_tests/llui_libtest/llwidgetreg.cpp
index c6e2e79a09f4af384d69f641d2cf5f76464e1bfd..57c39243fbe5dc9c49cd8ca30341f293add14cba 100644
--- a/indra/integration_tests/llui_libtest/llwidgetreg.cpp
+++ b/indra/integration_tests/llui_libtest/llwidgetreg.cpp
@@ -37,6 +37,7 @@
 #include "llcombobox.h"
 #include "llcontainerview.h"
 #include "lliconctrl.h"
+#include "llloadingindicator.h"
 #include "llmenubutton.h"
 #include "llmenugl.h"
 #include "llmultislider.h"
@@ -72,6 +73,7 @@ void LLWidgetReg::initClass(bool register_widgets)
 		LLDefaultChildRegistry::Register<LLFlyoutButton> flyout_button("flyout_button");
 		LLDefaultChildRegistry::Register<LLContainerView> container_view("container_view");
 		LLDefaultChildRegistry::Register<LLIconCtrl> icon("icon");
+		LLDefaultChildRegistry::Register<LLLoadingIndicator> loading_indicator("loading_indicator");
 		LLDefaultChildRegistry::Register<LLLineEditor> line_editor("line_editor");
 		LLDefaultChildRegistry::Register<LLMenuItemSeparatorGL> menu_item_separator("menu_item_separator");
 		LLDefaultChildRegistry::Register<LLMenuItemCallGL> menu_item_call_gl("menu_item_call");
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 532b6b6524b805a6620ef3fc9e2de1e169099cd6..3ecab90756417f50610f230d8ebdc9d4bf42dbb4 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -52,6 +52,7 @@ set(llui_SOURCE_FILES
     llkeywords.cpp
     lllayoutstack.cpp
     lllineeditor.cpp
+    llloadingindicator.cpp
     lllocalcliprect.cpp
     llmenubutton.cpp
     llmenugl.cpp
@@ -144,6 +145,7 @@ set(llui_HEADER_FILES
     lllayoutstack.h
     lllazyvalue.h
     lllineeditor.h
+    llloadingindicator.h
     lllocalcliprect.h
     llmenubutton.h
     llmenugl.h
diff --git a/indra/llui/llloadingindicator.cpp b/indra/llui/llloadingindicator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8dec6ea9df008beb69076047f16749a327a40f9b
--- /dev/null
+++ b/indra/llui/llloadingindicator.cpp
@@ -0,0 +1,135 @@
+/** 
+ * @file llloadingindicator.cpp
+ * @brief Perpetual loading indicator
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ * 
+ * Copyright (c) 2010, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llloadingindicator.h"
+
+// Linden library includes
+#include "llsingleton.h"
+
+// Project includes
+#include "lluictrlfactory.h"
+#include "lluiimage.h"
+
+static LLDefaultChildRegistry::Register<LLLoadingIndicator> r("loading_indicator");
+
+///////////////////////////////////////////////////////////////////////////////
+// LLLoadingIndicator::Data class
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Pre-loaded images shared by all instances of the widget
+ */
+class LLLoadingIndicator::Data: public LLSingleton<LLLoadingIndicator::Data>
+{
+public:
+	/*virtual*/ void		initSingleton(); // from LLSingleton
+
+	LLPointer<LLUIImage>	getNextImage(S8& idx) const;
+	U8						getImagesCount() const	{ return NIMAGES; }
+private:
+
+	static const U8			NIMAGES = 12;
+	LLPointer<LLUIImage>	mImages[NIMAGES];
+};
+
+// virtual
+// Called right after the instance gets constructed.
+void LLLoadingIndicator::Data::initSingleton()
+{
+	// Load images.
+	for (U8 i = 0; i < NIMAGES; ++i)
+	{
+		std::string img_name = llformat("Progress_%d", i+1);
+		mImages[i] = LLUI::getUIImage(img_name, 0);
+		llassert(mImages[i]);
+	}
+}
+
+LLPointer<LLUIImage> LLLoadingIndicator::Data::getNextImage(S8& idx) const
+{
+	// Actually selects previous image because
+	// current images seem to be in wrong order;
+	// performs array bounds checking.
+	idx = idx > 0 ? llmin(NIMAGES-1, idx-1) : NIMAGES-1;
+	return mImages[idx];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// LLLoadingIndicator class
+///////////////////////////////////////////////////////////////////////////////
+
+LLLoadingIndicator::LLLoadingIndicator(const Params& p)
+:	LLUICtrl(p)
+	, mRotationsPerSec(p.rotations_per_sec > 0 ? p.rotations_per_sec : 1.0f)
+	, mCurImageIdx(-1)
+{
+	// Select initial image.
+	mCurImagep = Data::instance().getNextImage(mCurImageIdx);
+
+	// Start timer for switching images.
+	start();
+}
+
+void LLLoadingIndicator::draw()
+{
+	// Time to switch to the next image?
+	if (mImageSwitchTimer.getStarted() && mImageSwitchTimer.hasExpired())
+	{
+		// Switch to the next image.
+		mCurImagep = Data::instance().getNextImage(mCurImageIdx);
+
+		// Restart timer.
+		start();
+	}
+
+	// Draw current image.
+	if( mCurImagep.notNull() )
+	{
+		mCurImagep->draw(getLocalRect(), LLColor4::white % getDrawContext().mAlpha);
+	}
+
+	LLUICtrl::draw();
+}
+
+void LLLoadingIndicator::stop()
+{
+	mImageSwitchTimer.stop();
+}
+
+void LLLoadingIndicator::start()
+{
+	mImageSwitchTimer.start();
+	F32 period = 1.0f / (Data::instance().getImagesCount() * mRotationsPerSec);
+	mImageSwitchTimer.setTimerExpirySec(period);
+}
diff --git a/indra/llui/llloadingindicator.h b/indra/llui/llloadingindicator.h
new file mode 100644
index 0000000000000000000000000000000000000000..32dd1fead80f3f560b5e3e0c6db5f484b14dcf1e
--- /dev/null
+++ b/indra/llui/llloadingindicator.h
@@ -0,0 +1,93 @@
+/** 
+ * @file llloadingindicator.h
+ * @brief Perpetual loading indicator
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ * 
+ * Copyright (c) 2010, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLLOADINGINDICATOR_H
+#define LL_LLLOADINGINDICATOR_H
+
+#include "lluictrl.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class LLLoadingIndicator
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Perpetual loading indicator (a la MacOSX or YouTube)
+ * 
+ * Number of rotations per second can be overriden
+ * with the "roations_per_sec" parameter.
+ * 
+ * Can start/stop spinning.
+ * 
+ * @see start()
+ * @see stop()
+ */
+class LLLoadingIndicator
+: public LLUICtrl
+{
+	LOG_CLASS(LLLoadingIndicator);
+public:
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<F32>	rotations_per_sec;
+		Params()
+		:	rotations_per_sec("rotations_per_sec", 1.0f)
+		{}
+	};
+
+	virtual ~LLLoadingIndicator() {}
+
+	// llview overrides
+	virtual void draw();
+
+	/**
+	 * Stop spinning.
+	 */
+	void stop();
+
+	/**
+	 * Start spinning.
+	 */
+	void start();
+
+private:
+	LLLoadingIndicator(const Params&);
+	friend class LLUICtrlFactory;
+
+	class Data;
+
+	F32						mRotationsPerSec;
+	S8						mCurImageIdx;
+	LLPointer<LLUIImage>	mCurImagep;
+	LLFrameTimer			mImageSwitchTimer;
+};
+
+#endif // LL_LLLOADINGINDICATOR_H
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index f9a4ed7285dd65336db550a02862d4578c9f7534..bf12384a2846132ac4e02375812c0a8670006b02 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -56,6 +56,7 @@
 #include "llfloaterreg.h"
 #include "llmenugl.h"
 #include "llmenubutton.h"
+#include "llloadingindicator.h"
 #include "llwindow.h"
 
 // for registration
@@ -94,7 +95,10 @@ std::list<std::string> gUntranslated;
 static LLDefaultChildRegistry::Register<LLFilterEditor> register_filter_editor("filter_editor");
 static LLDefaultChildRegistry::Register<LLFlyoutButton> register_flyout_button("flyout_button");
 static LLDefaultChildRegistry::Register<LLSearchEditor> register_search_editor("search_editor");
+
+// register other widgets which otherwise may not be linked in
 static LLDefaultChildRegistry::Register<LLMenuButton> register_menu_button("menu_button");
+static LLDefaultChildRegistry::Register<LLLoadingIndicator> register_loading_indicator("loading_indicator");
 
 
 //
diff --git a/indra/llui/lluifwd.h b/indra/llui/lluifwd.h
index f99bb39fddecf4193a56520a01ef8f113317ad36..d6047b943cd523c21dc639faceafd6f20cb370b2 100644
--- a/indra/llui/lluifwd.h
+++ b/indra/llui/lluifwd.h
@@ -39,6 +39,7 @@ class LLComboBox;
 class LLDragHandle;
 class LLFloater;
 class LLIconCtrl;
+class LLLoadingIndicator;
 class LLLineEditor;
 class LLMenuGL;
 class LLPanel;
diff --git a/indra/newview/skins/default/textures/icons/Progress_1.png b/indra/newview/skins/default/textures/icons/Progress_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..58b56003c40a1c50fb38a02ad749862278fee619
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Progress_1.png differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_10.png b/indra/newview/skins/default/textures/icons/Progress_10.png
new file mode 100644
index 0000000000000000000000000000000000000000..07fe0be8a3999b4713a0fa26ffaf9263a831b15e
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Progress_10.png differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_11.png b/indra/newview/skins/default/textures/icons/Progress_11.png
new file mode 100644
index 0000000000000000000000000000000000000000..215d68cc465fa2c7597c650b0bb5251b08f46f83
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Progress_11.png differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_12.png b/indra/newview/skins/default/textures/icons/Progress_12.png
new file mode 100644
index 0000000000000000000000000000000000000000..d75558862140ee581dcf463bd903829c987155b1
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Progress_12.png differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_2.png b/indra/newview/skins/default/textures/icons/Progress_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..6640ee227ba754700c2d29014eb47dc06f765d84
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Progress_2.png differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_3.png b/indra/newview/skins/default/textures/icons/Progress_3.png
new file mode 100644
index 0000000000000000000000000000000000000000..5decbe977e25de8cd5ed19dd1cc844df0a04e715
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Progress_3.png differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_4.png b/indra/newview/skins/default/textures/icons/Progress_4.png
new file mode 100644
index 0000000000000000000000000000000000000000..56e81c17aa0258e691da8cd3db02a377b4f044d4
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Progress_4.png differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_5.png b/indra/newview/skins/default/textures/icons/Progress_5.png
new file mode 100644
index 0000000000000000000000000000000000000000..a89bf2ac62d0c3175ccb5cbcd2fbbed8a28e9047
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Progress_5.png differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_6.png b/indra/newview/skins/default/textures/icons/Progress_6.png
new file mode 100644
index 0000000000000000000000000000000000000000..233c4795407ddf79ca93d1895da1baa4ad011f82
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Progress_6.png differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_7.png b/indra/newview/skins/default/textures/icons/Progress_7.png
new file mode 100644
index 0000000000000000000000000000000000000000..631d7a6819ddd0763c90fc1834ce4eb9c51292a5
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Progress_7.png differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_8.png b/indra/newview/skins/default/textures/icons/Progress_8.png
new file mode 100644
index 0000000000000000000000000000000000000000..ac0e3f13f7b214eeb491a33fd3a057cc2f81e368
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Progress_8.png differ
diff --git a/indra/newview/skins/default/textures/icons/Progress_9.png b/indra/newview/skins/default/textures/icons/Progress_9.png
new file mode 100644
index 0000000000000000000000000000000000000000..17fb4a0335da68fb3f50fdc50cbe1cec529cf75e
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Progress_9.png differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 84a99ba92a959dc5e4404f981e2c4d44d744171a..1080ff347ce6f4673b60f8d0d1018d08120bece8 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -580,4 +580,17 @@ with the same filename but different name
   <texture name="default_profile_picture.j2c" />
   <texture name="locked_image.j2c" />
 
+  <texture name="Progress_1" file_name="icons/Progress_1.png" preload="false" />
+  <texture name="Progress_2" file_name="icons/Progress_2.png" preload="false" />
+  <texture name="Progress_3" file_name="icons/Progress_3.png" preload="false" />
+  <texture name="Progress_4" file_name="icons/Progress_4.png" preload="false" />
+  <texture name="Progress_5" file_name="icons/Progress_5.png" preload="false" />
+  <texture name="Progress_6" file_name="icons/Progress_6.png" preload="false" />
+  <texture name="Progress_7" file_name="icons/Progress_7.png" preload="false" />
+  <texture name="Progress_8" file_name="icons/Progress_8.png" preload="false" />
+  <texture name="Progress_9" file_name="icons/Progress_9.png" preload="false" />
+  <texture name="Progress_10" file_name="icons/Progress_10.png" preload="false" />
+  <texture name="Progress_11" file_name="icons/Progress_11.png" preload="false" />
+  <texture name="Progress_12" file_name="icons/Progress_12.png" preload="false" />
+
 </textures>
diff --git a/indra/newview/skins/default/xui/en/widgets/loading_indicator.xml b/indra/newview/skins/default/xui/en/widgets/loading_indicator.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6040d2412851b2ee21fd593dd4fcfc4afa024983
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/loading_indicator.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<loading_indicator
+    follows="left|top"
+    mouse_opaque="false"
+    name="loading_indicator"
+    rotations_per_sec="1.0"
+    tab_stop="false"
+/>