Anonymous avatar Anonymous committed c930049 Merge

Comments (0)

Files changed (55)

 0496d2f74043cf4e6058e76ac3db03d44cff42ce 3.0.3-release
 92a3aa04775438226399b19deee12ac3b5a62838 3.0.5-start
 c7282e59f374ee904bd793c3c444455e3399b0c5 3.1.0-start
+2657fa785bbfac115852c41bd0adaff74c2ad5da DRTVWR-93_3.1.0-beta1
+2657fa785bbfac115852c41bd0adaff74c2ad5da 3.1.0-beta1
 snowstorm_viewer-development.build_viewer_update_version_manager = false
 snowstorm_viewer-development.email = viewer-development-builds@lists.secondlife.com
 snowstorm_viewer-development.build_enforce_coding_policy = true
+snowstorm_viewer-development.codeticket_add_context = true
 
 Snowstorm_viewer-project-review.build_debug_release_separately = true
 Snowstorm_viewer-project-review.codeticket_add_context = true
 Snowstorm_viewer-project-review.viewer_channel = "Project Viewer - Snowstorm Team"
 Snowstorm_viewer-project-review.login_channel = "Project Viewer - Snowstorm Team"
+Snowstorm_viewer-project-review.codeticket_add_context = true
 
 # ========================================
 # Viewer Beta

doc/contributions.txt

 	VWR-1184
 Aleric Inglewood
 	SNOW-84
+	OPEN-38
 	SNOW-240
 	SNOW-477
 	SNOW-522
 	STORM-1567
 	STORM-1572
 	STORM-1574
+	STORM-1579
+	STORM-1639
 Kadah Coba
     STORM-1060
 Jondan Lundquist
 	VWR-5370
 leliel Mirihi
 	STORM-1100
+	STORM-1602
 len Starship
 Lisa Lowe
 	CT-218
 Takeda Terrawyng
 TankMaster Finesmith
 	STORM-1100
+	STORM-1602
+	STORM-1258
+    VWR-26622
 Talamasca
 Tali Rosca
 Tayra Dagostino

indra/cmake/FindGLH.cmake

+# -*- cmake -*-
+
+# - Find GLH
+# Find the Graphic Library Helper includes.
+# This module defines
+#  GLH_INCLUDE_DIR, where to find glh/glh_linear.h.
+#  GLH_FOUND, If false, do not try to use GLH.
+
+find_path(GLH_INCLUDE_DIR glh/glh_linear.h
+    NO_SYSTEM_ENVIRONMENT_PATH
+    )
+
+if (GLH_INCLUDE_DIR)
+  set(GLH_FOUND "YES")
+else (GLH_INCLUDE_DIR)
+  set(GLH_FOUND "NO")
+endif (GLH_INCLUDE_DIR)
+
+if (GLH_FOUND)
+  if (NOT GLH_FIND_QUIETLY)
+    message(STATUS "Found GLH: ${GLH_INCLUDE_DIR}")
+    set(GLH_FIND_QUIETLY TRUE) # Only alert us the first time
+  endif (NOT GLH_FIND_QUIETLY)
+else (GLH_FOUND)
+  if (GLH_FIND_REQUIRED)
+    message(FATAL_ERROR "Could not find GLH")
+  endif (GLH_FIND_REQUIRED)
+endif (GLH_FOUND)
+
+mark_as_advanced(GLH_INCLUDE_DIR)

indra/cmake/GLH.cmake

+# -*- cmake -*-
+include(Prebuilt)
+
+set(GLH_FIND_REQUIRED TRUE)
+set(GLH_FIND_QUIETLY TRUE)
+
+if (STANDALONE)
+  include(FindGLH)
+else (STANDALONE)
+  use_prebuilt_binary(glh_linear)
+endif (STANDALONE)

indra/cmake/LLRender.cmake

 # -*- cmake -*-
 
 include(FreeType)
+include(GLH)
 
 set(LLRENDER_INCLUDE_DIRS
     ${LIBS_OPEN_DIR}/llrender
+    ${GLH_INCLUDE_DIR}
     )
 
 if (SERVER AND LINUX)

indra/cmake/LLSharedLibs.cmake

 # ll_stage_sharedlib
 # Performs config and adds a copy command for a sharedlib target.
 macro(ll_stage_sharedlib DSO_TARGET)
-  if(SHARED_LIB_STAGING_DIR)
-    # target gets written to the DLL staging directory.
-    # Also this directory is shared with RunBuildTest.cmake, y'know, for the tests.
-    set_target_properties(${DSO_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${SHARED_LIB_STAGING_DIR})
-    if(NOT WINDOWS)
-      get_target_property(DSO_PATH ${DSO_TARGET} LOCATION)
-      get_filename_component(DSO_FILE ${DSO_PATH} NAME)
-      if(DARWIN)
-        set(SHARED_LIB_STAGING_DIR_CONFIG ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/Resources)
-      else(DARWIN)
-        set(SHARED_LIB_STAGING_DIR_CONFIG ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR})
-      endif(DARWIN)
+  # target gets written to the DLL staging directory.
+  # Also this directory is shared with RunBuildTest.cmake, y'know, for the tests.
+  set_target_properties(${DSO_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${SHARED_LIB_STAGING_DIR})
+  if(NOT WINDOWS)
+    get_target_property(DSO_PATH ${DSO_TARGET} LOCATION)
+    get_filename_component(DSO_FILE ${DSO_PATH} NAME)
+    if(DARWIN)
+      set(SHARED_LIB_STAGING_DIR_CONFIG ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/Resources)
+    else(DARWIN)
+      set(SHARED_LIB_STAGING_DIR_CONFIG ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR})
+    endif(DARWIN)
 
       # *TODO - maybe make this a symbolic link? -brad
       add_custom_command(
           COMMENT "Copying llcommon to the staging folder."
         )
     endif(NOT WINDOWS)
-  endif(SHARED_LIB_STAGING_DIR)
 
   if (DARWIN)
     set_target_properties(${DSO_TARGET} PROPERTIES

indra/cmake/Linking.cmake

 
 include(Variables)
 
-
-if (NOT STANDALONE)
-  set(ARCH_PREBUILT_DIRS ${AUTOBUILD_INSTALL_DIR}/lib)
-  set(ARCH_PREBUILT_DIRS_RELEASE ${AUTOBUILD_INSTALL_DIR}/lib/release)
-  set(ARCH_PREBUILT_DIRS_DEBUG ${AUTOBUILD_INSTALL_DIR}/lib/debug)
-  if (WINDOWS)
-    set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs)
-    set(EXE_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs)
-  elseif (LINUX)
-    set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/lib)
-    set(EXE_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/bin)
-  elseif (DARWIN)
-    set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs)
-    set(EXE_STAGING_DIR "${CMAKE_BINARY_DIR}/sharedlibs/\$(CONFIGURATION)")
-  endif (WINDOWS)
-endif (NOT STANDALONE)
+set(ARCH_PREBUILT_DIRS ${AUTOBUILD_INSTALL_DIR}/lib)
+set(ARCH_PREBUILT_DIRS_RELEASE ${AUTOBUILD_INSTALL_DIR}/lib/release)
+set(ARCH_PREBUILT_DIRS_DEBUG ${AUTOBUILD_INSTALL_DIR}/lib/debug)
+if (WINDOWS)
+  set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs)
+  set(EXE_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs)
+elseif (LINUX)
+  set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/lib)
+  set(EXE_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/bin)
+elseif (DARWIN)
+  set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs)
+  set(EXE_STAGING_DIR "${CMAKE_BINARY_DIR}/sharedlibs/\$(CONFIGURATION)")
+endif (WINDOWS)
 
 # Autobuild packages must provide 'release' versions of libraries, but may provide versions for
 # specific build types.  AUTOBUILD_LIBS_INSTALL_DIRS lists first the build type directory and then

indra/linux_crash_logger/CMakeLists.txt

 project(linux_crash_logger)
 
 include(00-Common)
+include(GLH)
 include(LLCommon)
 include(LLCrashLogger)
 include(LLMath)

indra/llcommon/lleventapi.cpp

 // std headers
 // external library headers
 // other Linden headers
+#include "llerror.h"
 
 LLEventAPI::LLEventAPI(const std::string& name, const std::string& desc, const std::string& field):
     lbase(name, field),
 LLEventAPI::~LLEventAPI()
 {
 }
+
+LLEventAPI::Response::Response(const LLSD& seed, const LLSD& request, const LLSD::String& replyKey):
+    mResp(seed),
+    mReq(request),
+    mKey(replyKey)
+{}
+
+LLEventAPI::Response::~Response()
+{
+    // When you instantiate a stack Response object, if the original
+    // request requested a reply, send it when we leave this block, no
+    // matter how.
+    sendReply(mResp, mReq, mKey);
+}
+
+void LLEventAPI::Response::warn(const std::string& warning)
+{
+    LL_WARNS("LLEventAPI::Response") << warning << LL_ENDL;
+    mResp["warnings"].append(warning);
+}
+
+void LLEventAPI::Response::error(const std::string& error)
+{
+    // Use LL_WARNS rather than LL_ERROR: we don't want the viewer to shut
+    // down altogether.
+    LL_WARNS("LLEventAPI::Response") << error << LL_ENDL;
+
+    mResp["error"] = error;
+}

indra/llcommon/lleventapi.h

         LLEventDispatcher::add(name, desc, callable, required);
     }
 
+    /**
+     * Instantiate a Response object in any LLEventAPI subclass method that
+     * wants to guarantee a reply (if requested) will be sent on exit from the
+     * method. The reply will be sent if request.has(@a replyKey), default
+     * "reply". If specified, the value of request[replyKey] is the name of
+     * the LLEventPump on which to send the reply. Conventionally you might
+     * code something like:
+     *
+     * @code
+     * void MyEventAPI::someMethod(const LLSD& request)
+     * {
+     *     // Send a reply event as long as request.has("reply")
+     *     Response response(LLSD(), request);
+     *     // ...
+     *     // will be sent in reply event
+     *     response["somekey"] = some_data;
+     * }
+     * @endcode
+     */
+    class LL_COMMON_API Response
+    {
+    public:
+        /**
+         * Instantiating a Response object in an LLEventAPI subclass method
+         * ensures that, if desired, a reply event will be sent.
+         *
+         * @a seed is the initial reply LLSD that will be further decorated before
+         * being sent as the reply
+         *
+         * @a request is the incoming request LLSD; we particularly care about
+         * [replyKey] and ["reqid"]
+         *
+         * @a replyKey [default "reply"] is the string name of the LLEventPump
+         * on which the caller wants a reply. If <tt>(!
+         * request.has(replyKey))</tt>, no reply will be sent.
+         */
+        Response(const LLSD& seed, const LLSD& request, const LLSD::String& replyKey="reply");
+        ~Response();
+
+        /**
+         * @code
+         * if (some condition)
+         * {
+         *     response.warn("warnings are logged and collected in [\"warnings\"]");
+         * }
+         * @endcode
+         */
+        void warn(const std::string& warning);
+        /**
+         * @code
+         * if (some condition isn't met)
+         * {
+         *     // In a function returning void, you can validly 'return
+         *     // expression' if the expression is itself of type void. But
+         *     // returning is up to you; response.error() has no effect on
+         *     // flow of control.
+         *     return response.error("error message, logged and also sent as [\"error\"]");
+         * }
+         * @endcode
+         */
+        void error(const std::string& error);
+
+        /**
+         * set other keys...
+         *
+         * @code
+         * // set any attributes you want to be sent in the reply
+         * response["info"] = some_value;
+         * // ...
+         * response["ok"] = went_well;
+         * @endcode
+         */
+        LLSD& operator[](const LLSD::String& key) { return mResp[key]; }
+		
+		 /**
+		 * set the response to the given data
+		 */
+		void setResponse(LLSD const & response){ mResp = response; }
+
+        LLSD mResp, mReq;
+        LLSD::String mKey;
+    };
+
 private:
     std::string mDesc;
 };

indra/llcommon/llevents.cpp

 
 bool sendReply(const LLSD& reply, const LLSD& request, const std::string& replyKey)
 {
+    // If the original request has no value for replyKey, it's pointless to
+    // construct or send a reply event: on which LLEventPump should we send
+    // it? Allow that to be optional: if the caller wants to require replyKey,
+    // it can so specify when registering the operation method.
+    if (! request.has(replyKey))
+    {
+        return false;
+    }
+
+    // Here the request definitely contains replyKey; reasonable to proceed.
+
     // Copy 'reply' to modify it.
     LLSD newreply(reply);
     // Get the ["reqid"] element from request

indra/llcommon/llqueuedthread.cpp

 //============================================================================
 
 // MAIN THREAD
-LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
+LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool should_pause) :
 	LLThread(name),
 	mThreaded(threaded),
 	mIdleThread(TRUE),
 {
 	if (mThreaded)
 	{
+		if(should_pause)
+		{
+			pause() ; //call this before start the thread.
+		}
+
 		start();
 	}
 }

indra/llcommon/llqueuedthread.h

 	static handle_t nullHandle() { return handle_t(0); }
 	
 public:
-	LLQueuedThread(const std::string& name, bool threaded = true);
+	LLQueuedThread(const std::string& name, bool threaded = true, bool should_pause = false);
 	virtual ~LLQueuedThread();	
 	virtual void shutdown();
 	

indra/llcommon/llworkerthread.cpp

 //============================================================================
 // Run on MAIN thread
 
-LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) :
-	LLQueuedThread(name, threaded)
+LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) :
+	LLQueuedThread(name, threaded, should_pause)
 {
 	mDeleteMutex = new LLMutex;
 }

indra/llcommon/llworkerthread.h

 	LLMutex* mDeleteMutex;
 	
 public:
-	LLWorkerThread(const std::string& name, bool threaded = true);
+	LLWorkerThread(const std::string& name, bool threaded = true, bool should_pause = false);
 	~LLWorkerThread();
 
 	/*virtual*/ S32 update(U32 max_time_ms);

indra/llui/CMakeLists.txt

     llurlmatch.cpp
     llurlregistry.cpp
     llviewborder.cpp
+    llviewinject.cpp
     llviewmodel.cpp
     llview.cpp
     llviewquery.cpp
     llurlmatch.h
     llurlregistry.h
     llviewborder.h
+    llviewinject.h
     llviewmodel.h
     llview.h
     llviewquery.h

indra/llui/lluictrl.cpp

 	if (!mDoubleClickSignal) mDoubleClickSignal = new mouse_signal_t();
 	return mDoubleClickSignal->connect(cb); 
 }
+
+void LLUICtrl::addInfo(LLSD & info)
+{
+	LLView::addInfo(info);
+	info["value"] = getValue();
+}

indra/llui/lluictrl.h

 
 	static F32 sActiveControlTransparency;
 	static F32 sInactiveControlTransparency;
-
+	
+	virtual void addInfo(LLSD & info);
+	
 private:
 
 	BOOL			mIsChrome;

indra/llui/llview.cpp

 #include "llview.h"
 
 #include <cassert>
+#include <sstream>
 #include <boost/tokenizer.hpp>
+#include <boost/foreach.hpp>
+#include <boost/bind.hpp>
 
 #include "llrender.h"
 #include "llevent.h"
 #include "v3color.h"
 #include "lluictrlfactory.h"
 #include "lltooltip.h"
+#include "llsdutil.h"
 
 // for ui edit hack
 #include "llbutton.h"
 S32		LLView::sLastBottomXML = S32_MIN;
 std::vector<LLViewDrawContext*> LLViewDrawContext::sDrawContextStack;
 
+LLView::DrilldownFunc LLView::sDrilldown =
+	boost::bind(&LLView::pointInView, _1, _2, _3, HIT_TEST_USE_BOUNDING_RECT);
 
 //#if LL_DEBUG
 BOOL LLView::sIsDrawing = FALSE;
 LLView::ctrl_list_t LLView::getCtrlList() const
 {
 	ctrl_list_t controls;
-	for(child_list_const_iter_t iter = mChildList.begin();
-		iter != mChildList.end();
-		iter++)
+	BOOST_FOREACH(LLView* viewp, mChildList)
 	{
-		if((*iter)->isCtrl())
+		if(viewp->isCtrl())
 		{
-			controls.push_back(static_cast<LLUICtrl*>(*iter));
+			controls.push_back(static_cast<LLUICtrl*>(viewp));
 		}
 	}
 	return controls;
 	return enabled;
 }
 
+static void buildPathname(std::ostream& out, const LLView* view)
+{
+	if (! (view && view->getParent()))
+	{
+		return; // Don't include root in the path.
+	}
+
+	buildPathname(out, view->getParent());
+
+	// Build pathname into ostream on the way back from recursion.
+	out << '/' << view->getName();
+}
+
+std::string LLView::getPathname() const
+{
+	std::ostringstream out;
+	buildPathname(out, this);
+	return out.str();
+}
+
+//static
+std::string LLView::getPathname(const LLView* view)
+{
+    if (! view)
+    {
+        return "NULL";
+    }
+    return view->getPathname();
+}
+
 // virtual
 BOOL LLView::canFocusChildren() const
 {
 
 void LLView::setAllChildrenEnabled(BOOL b)
 {
-	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+	BOOST_FOREACH(LLView* viewp, mChildList)
 	{
-		LLView* viewp = *child_it;
 		viewp->setEnabled(b);
 	}
 }
 // virtual
 void LLView::handleVisibilityChange ( BOOL new_visibility )
 {
-	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+	BOOST_FOREACH(LLView* viewp, mChildList)
 	{
-		LLView* viewp = *child_it;
 		// only views that are themselves visible will have their overall visibility affected by their ancestors
 		if (viewp->getVisible())
 		{
 	//llinfos << "Mouse left " << getName() << llendl;
 }
 
+bool LLView::visibleAndContains(S32 local_x, S32 local_y)
+{
+	return sDrilldown(this, local_x, local_y)
+		&& getVisible();
+}
 
-LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask)
+bool LLView::visibleEnabledAndContains(S32 local_x, S32 local_y)
 {
-	LLView* handled_view = NULL;
-	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+	return visibleAndContains(local_x, local_y)
+		&& getEnabled();
+}
+
+void LLView::logMouseEvent()
+{
+	if (sDebugMouseHandling)
 	{
-		LLView* viewp = *child_it;
+		sMouseHandlerMessage = std::string("/") + mName + sMouseHandlerMessage;
+	}
+}
+
+template <typename METHOD, typename CHARTYPE>
+LLView* LLView::childrenHandleCharEvent(const std::string& desc, const METHOD& method,
+										CHARTYPE c, MASK mask)
+{
+	if ( getVisible() && getEnabled() )
+	{
+		BOOST_FOREACH(LLView* viewp, mChildList)
+		{
+			if ((viewp->*method)(c, mask, TRUE))
+			{
+				if (LLView::sDebugKeys)
+				{
+					llinfos << desc << " handled by " << viewp->getName() << llendl;
+				}
+				return viewp;
+			}
+		}
+	}
+    return NULL;
+}
+
+// XDATA might be MASK, or S32 clicks
+template <typename METHOD, typename XDATA>
+LLView* LLView::childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDATA extra)
+{
+	BOOST_FOREACH(LLView* viewp, mChildList)
+	{
 		S32 local_x = x - viewp->getRect().mLeft;
 		S32 local_y = y - viewp->getRect().mBottom;
-		if(!viewp->pointInView(local_x, local_y) 
-			|| !viewp->getVisible())
+
+		if (!viewp->visibleEnabledAndContains(local_x, local_y))
 		{
 			continue;
 		}
 
-		if (viewp->handleToolTip(local_x, local_y, mask) )
+		if ((viewp->*method)( local_x, local_y, extra )
+			|| viewp->blockMouseEvent( local_x, local_y ))
 		{
-			if (sDebugMouseHandling)
-			{
-				sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
-			}
+			viewp->logMouseEvent();
+			return viewp;
+		}
+	}
+	return NULL;
+}
 
-			handled_view = viewp;
-			break;
+LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask)
+{
+	BOOST_FOREACH(LLView* viewp, mChildList)
+	{
+		S32 local_x = x - viewp->getRect().mLeft;
+		S32 local_y = y - viewp->getRect().mBottom;
+		// Differs from childrenHandleMouseEvent() in that we want to offer
+		// tooltips even for disabled widgets.
+		if(!viewp->visibleAndContains(local_x, local_y))
+		{
+			continue;
 		}
 
-		if (viewp->blockMouseEvent(local_x, local_y))
+		if (viewp->handleToolTip(local_x, local_y, mask) 
+			|| viewp->blockMouseEvent(local_x, local_y))
 		{
-			handled_view = viewp;
-			break;
+			viewp->logMouseEvent();
+			return viewp;
 		}
 	}
-	return handled_view;
+	return NULL;
 }
 
+LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
+									   BOOL drop,
+									   EDragAndDropType cargo_type,
+									   void* cargo_data,
+									   EAcceptance* accept,
+									   std::string& tooltip_msg)
+{
+	// default to not accepting drag and drop, will be overridden by handler
+	*accept = ACCEPT_NO;
 
-LLView*	LLView::childFromPoint(S32 x, S32 y)
-{
-	if (!getVisible()  )
-		return false;
-	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+	BOOST_FOREACH(LLView* viewp, mChildList)
 	{
-		LLView* viewp = *child_it;
 		S32 local_x = x - viewp->getRect().mLeft;
 		S32 local_y = y - viewp->getRect().mBottom;
-		if (!viewp->pointInView(local_x, local_y) 
-			|| !viewp->getVisible() )
+		if( !viewp->visibleEnabledAndContains(local_x, local_y))
 		{
 			continue;
 		}
+
+		// Differs from childrenHandleMouseEvent() simply in that this virtual
+		// method call diverges pretty radically from the usual (x, y, int).
+		if (viewp->handleDragAndDrop(local_x, local_y, mask, drop,
+									 cargo_type,
+									 cargo_data,
+									 accept,
+									 tooltip_msg)
+			|| viewp->blockMouseEvent(local_x, local_y))
+		{
+			return viewp;
+		}
+	}
+	return NULL;
+}
+
+LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
+{
+	BOOST_FOREACH(LLView* viewp, mChildList)
+	{
+		S32 local_x = x - viewp->getRect().mLeft;
+		S32 local_y = y - viewp->getRect().mBottom;
+		if(!viewp->visibleEnabledAndContains(local_x, local_y))
+		{
+			continue;
+		}
+
+		// This call differentiates this method from childrenHandleMouseEvent().
+		LLUI::sWindow->setCursor(viewp->getHoverCursor());
+
+		if (viewp->handleHover(local_x, local_y, mask)
+			|| viewp->blockMouseEvent(local_x, local_y))
+		{
+			viewp->logMouseEvent();
+			return viewp;
+		}
+	}
+	return NULL;
+}
+
+LLView*	LLView::childFromPoint(S32 x, S32 y, bool recur)
+{
+	if (!getVisible())
+		return false;
+
+	BOOST_FOREACH(LLView* viewp, mChildList)
+	{
+		S32 local_x = x - viewp->getRect().mLeft;
+		S32 local_y = y - viewp->getRect().mBottom;
+		if (!viewp->visibleAndContains(local_x, local_y))
+		{
+			continue;
+		}
+		// Here we've found the first (frontmost) visible child at this level
+		// containing the specified point. Is the caller asking us to drill
+		// down and return the innermost leaf child at this point, or just the
+		// top-level child?
+		if (recur)
+		{
+			LLView* leaf(viewp->childFromPoint(local_x, local_y, recur));
+			// Maybe viewp is already a leaf LLView, or maybe it has children
+			// but this particular (x, y) point falls between them. If the
+			// recursive call returns non-NULL, great, use that; else just use
+			// viewp.
+			return leaf? leaf : viewp;
+		}
 		return viewp;
 
 	}
 	return childrenHandleDragAndDrop( x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) != NULL;
 }
 
-LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
-									   BOOL drop,
-									   EDragAndDropType cargo_type,
-									   void* cargo_data,
-									   EAcceptance* accept,
-									   std::string& tooltip_msg)
-{
-	LLView* handled_view = NULL;
-	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
-	{
-		LLView* viewp = *child_it;
-		S32 local_x = x - viewp->getRect().mLeft;
-		S32 local_y = y - viewp->getRect().mBottom;
-		if( !viewp->pointInView(local_x, local_y) ||
-			!viewp->getVisible() ||
-			!viewp->getEnabled())
-		{
-			continue;
-		}
-		if (viewp->handleDragAndDrop(local_x, local_y, mask, drop,
-									 cargo_type,
-									 cargo_data,
-									 accept,
-									 tooltip_msg))
-		{
-			handled_view = viewp;
-			break;
-		}
-
-		if (viewp->blockMouseEvent(x, y))
-		{
-			*accept = ACCEPT_NO;
-			handled_view = viewp;
-			break;
-		}
-	}
-	return handled_view;
-}
-
 void LLView::onMouseCaptureLost()
 {
 }
 	return childrenHandleMiddleMouseUp( x, y, mask ) != NULL;
 }
 
-
 LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks)
 {
-	LLView* handled_view = NULL;
-	if (getVisible() && getEnabled() )
-	{
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			S32 local_x = x - viewp->getRect().mLeft;
-			S32 local_y = y - viewp->getRect().mBottom;
-			if (!viewp->pointInView(local_x, local_y) 
-				|| !viewp->getVisible()
-				|| !viewp->getEnabled())
-			{
-				continue;
-			}
-
-			if (viewp->handleScrollWheel( local_x, local_y, clicks ))
-			{
-				if (sDebugMouseHandling)
-				{
-					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
-				}
-
-				handled_view = viewp;
-				break;
-			}
-		}
-	}
-	return handled_view;
-}
-
-LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
-{
-	LLView* handled_view = NULL;
-	if (getVisible() && getEnabled() )
-	{
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			S32 local_x = x - viewp->getRect().mLeft;
-			S32 local_y = y - viewp->getRect().mBottom;
-			if(!viewp->pointInView(local_x, local_y) 
-				|| !viewp->getVisible() 
-				|| !viewp->getEnabled())
-			{
-				continue;
-			}
-
-			if (viewp->handleHover(local_x, local_y, mask) )
-			{
-				if (sDebugMouseHandling)
-				{
-					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
-				}
-
-				handled_view = viewp;
-				break;
-			}
-
-			if (viewp->blockMouseEvent(local_x, local_y))
-			{
-				LLUI::sWindow->setCursor(viewp->getHoverCursor());
-
-				handled_view = viewp;
-				break;
-			}
-		}
-	}
-	return handled_view;
+	return childrenHandleMouseEvent(&LLView::handleScrollWheel, x, y, clicks);
 }
 
 // Called during downward traversal
 LLView* LLView::childrenHandleKey(KEY key, MASK mask)
 {
-	LLView* handled_view = NULL;
-
-	if ( getVisible() && getEnabled() )
-	{
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			if (viewp->handleKey(key, mask, TRUE))
-			{
-				if (LLView::sDebugKeys)
-				{
-					llinfos << "Key handled by " << viewp->getName() << llendl;
-				}
-				handled_view = viewp;
-				break;
-			}
-		}
-	}
-
-	return handled_view;
+	return childrenHandleCharEvent("Key", &LLView::handleKey, key, mask);
 }
 
 // Called during downward traversal
 LLView* LLView::childrenHandleUnicodeChar(llwchar uni_char)
 {
-	LLView* handled_view = NULL;
-
-	if ( getVisible() && getEnabled() )
-	{
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			if (viewp->handleUnicodeChar(uni_char, TRUE))
-			{
-				if (LLView::sDebugKeys)
-				{
-					llinfos << "Unicode character handled by " << viewp->getName() << llendl;
-				}
-				handled_view = viewp;
-				break;
-			}
-		}
-	}
-
-	return handled_view;
+	return childrenHandleCharEvent("Unicode character", &LLView::handleUnicodeCharWithDummyMask,
+								   uni_char, MASK_NONE);
 }
 
 LLView* LLView::childrenHandleMouseDown(S32 x, S32 y, MASK mask)
 {
-	LLView* handled_view = NULL;
-
-	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
-	{
-		LLView* viewp = *child_it;
-		S32 local_x = x - viewp->getRect().mLeft;
-		S32 local_y = y - viewp->getRect().mBottom;
-
-		if (!viewp->pointInView(local_x, local_y) 
-			|| !viewp->getVisible() 
-			|| !viewp->getEnabled())
-		{
-			continue;
-		}
-
-		if(viewp->handleMouseDown( local_x, local_y, mask ))
-		{
-			if (sDebugMouseHandling)
-			{
-				sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
-			}
-			handled_view = viewp;
-			break;
-		}
-
-		if(viewp->blockMouseEvent(local_x, local_y))
-		{
-			handled_view = viewp;
-			break;
-		}
-	}
-	return handled_view;
+	return childrenHandleMouseEvent(&LLView::handleMouseDown, x, y, mask);
 }
 
 LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask)
 {
-	LLView* handled_view = NULL;
-
-	if (getVisible() && getEnabled() )
-	{
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			S32 local_x = x - viewp->getRect().mLeft;
-			S32 local_y = y - viewp->getRect().mBottom;
-
-			if (!viewp->pointInView(local_x, local_y)
-				|| !viewp->getVisible() 
-				|| !viewp->getEnabled())
-			{
-				continue;
-			}
-
-			if (viewp->handleRightMouseDown( local_x, local_y, mask ))
-			{
-				if (sDebugMouseHandling)
-				{
-					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
-				}
-
-				handled_view = viewp;
-				break;
-			}
-
-			if (viewp->blockMouseEvent(local_x, local_y))
-			{
-				handled_view = viewp;
-				break;
-			}
-		}
-	}
-	return handled_view;
+	return childrenHandleMouseEvent(&LLView::handleRightMouseDown, x, y, mask);
 }
 
 LLView* LLView::childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask)
 {
-	LLView* handled_view = NULL;
-
-	if (getVisible() && getEnabled() )
-	{
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			S32 local_x = x - viewp->getRect().mLeft;
-			S32 local_y = y - viewp->getRect().mBottom;
-			if (!viewp->pointInView(local_x, local_y)
-				|| !viewp->getVisible() 
-				|| !viewp->getEnabled())
-			{
-				continue;
-			}
-
-			if(viewp->handleMiddleMouseDown( local_x, local_y, mask ))
-			{
-				if (sDebugMouseHandling)
-				{
-					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
-				}
-				handled_view = viewp;
-				break;
-			}
-
-			if (viewp->blockMouseEvent(local_x, local_y))
-			{
-				handled_view = viewp;
-				break;
-			}
-		}
-	}
-	return handled_view;
+	return childrenHandleMouseEvent(&LLView::handleMiddleMouseDown, x, y, mask);
 }
 
 LLView* LLView::childrenHandleDoubleClick(S32 x, S32 y, MASK mask)
 {
-	LLView* handled_view = NULL;
-
-	if (getVisible() && getEnabled() )
-	{
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			S32 local_x = x - viewp->getRect().mLeft;
-			S32 local_y = y - viewp->getRect().mBottom;
-
-			if (!viewp->pointInView(local_x, local_y) 
-				|| !viewp->getVisible() 
-				|| !viewp->getEnabled())
-			{
-				continue;
-			}
-
-			if (viewp->handleDoubleClick( local_x, local_y, mask ))
-			{
-				if (sDebugMouseHandling)
-				{
-					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
-				}
-				handled_view = viewp;
-				break;
-			}
-
-			if (viewp->blockMouseEvent(local_x, local_y))
-			{
-				handled_view = viewp;
-				break;
-			}
-		}
-	}
-	return handled_view;
+	return childrenHandleMouseEvent(&LLView::handleDoubleClick, x, y, mask);
 }
 
 LLView* LLView::childrenHandleMouseUp(S32 x, S32 y, MASK mask)
 {
-	LLView* handled_view = NULL;
-	if( getVisible() && getEnabled() )
-	{
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			S32 local_x = x - viewp->getRect().mLeft;
-			S32 local_y = y - viewp->getRect().mBottom;
-			if (!viewp->pointInView(local_x, local_y)
-				|| !viewp->getVisible()
-				|| !viewp->getEnabled())
-			{
-				continue;
-			}
-			
-			if (viewp->handleMouseUp( local_x, local_y, mask ))
-			{
-				if (sDebugMouseHandling)
-				{
-					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
-				}
-				handled_view = viewp;
-				break;
-			}
-
-			if (viewp->blockMouseEvent(local_x, local_y))
-			{
-				handled_view = viewp;
-				break;
-			}
-		}
-	}
-	return handled_view;
+	return childrenHandleMouseEvent(&LLView::handleMouseUp, x, y, mask);
 }
 
 LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask)
 {
-	LLView* handled_view = NULL;
-	if( getVisible() && getEnabled() )
-	{
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			S32 local_x = x - viewp->getRect().mLeft;
-			S32 local_y = y - viewp->getRect().mBottom;
-			if (!viewp->pointInView(local_x, local_y) 
-				|| !viewp->getVisible() 
-				|| !viewp->getEnabled() )
-			{
-				continue;
-			}
-
-			if(viewp->handleRightMouseUp( local_x, local_y, mask ))
-			{
-				if (sDebugMouseHandling)
-				{
-					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
-				}
-				handled_view = viewp;
-				break;
-			}
-
-			if(viewp->blockMouseEvent(local_x, local_y))
-			{
-				handled_view = viewp;
-				break;
-			}
-		}
-	}
-	return handled_view;
+	return childrenHandleMouseEvent(&LLView::handleRightMouseUp, x, y, mask);
 }
 
 LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask)
 {
-	LLView* handled_view = NULL;
-	if( getVisible() && getEnabled() )
-	{
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			S32 local_x = x - viewp->getRect().mLeft;
-			S32 local_y = y - viewp->getRect().mBottom;
-			if (!viewp->pointInView(local_x, local_y) 
-				|| !viewp->getVisible() 
-				|| !viewp->getEnabled())
-			{
-				continue;
-			}
-				
-			if(viewp->handleMiddleMouseUp( local_x, local_y, mask ))
-			{
-				if (sDebugMouseHandling)
-				{
-					sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
-				}
-				handled_view = viewp;
-				break;
-			}
-
-			if (viewp->blockMouseEvent(local_x, local_y))
-			{
-				handled_view = viewp;
-				break;
-			}
-		}
-	}
-	return handled_view;
+	return childrenHandleMouseEvent(&LLView::handleMiddleMouseUp, x, y, mask);
 }
 
 void LLView::draw()
 		mRect.mTop = getRect().mBottom + height;
 
 		// move child views according to reshape flags
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+		BOOST_FOREACH(LLView* viewp, mChildList)
 		{
-			LLView* viewp = *child_it;
 			LLRect child_rect( viewp->mRect );
 
 			if (viewp->followsRight() && viewp->followsLeft())
 {
 	LLRect local_bounding_rect = LLRect::null;
 
-	child_list_const_iter_t child_it;
-	for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+	BOOST_FOREACH(LLView* childp, mChildList)
 	{
-		LLView* childp = *child_it;
 		// ignore invisible and "top" children when calculating bounding rect
 		// such as combobox popups
 		if (!childp->getVisible() || childp == gFocusMgr.getTopCtrl()) 
 	//richard: should we allow empty names?
 	//if(name.empty())
 	//	return NULL;
-	child_list_const_iter_t child_it;
 	// Look for direct children *first*
-	for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+	BOOST_FOREACH(LLView* childp, mChildList)
 	{
-		LLView* childp = *child_it;
 		llassert(childp);
 		if (childp->getName() == name)
 		{
 	if (recurse)
 	{
 		// Look inside each child as well.
-		for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+		BOOST_FOREACH(LLView* childp, mChildList)
 		{
-			LLView* childp = *child_it;
 			llassert(childp);
 			LLView* viewp = childp->findChildView(name, recurse);
 			if ( viewp )
 bool	LLView::notifyChildren(const LLSD& info)
 {
 	bool ret = false;
-	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+	BOOST_FOREACH(LLView* childp, mChildList)
 	{
-		ret |= (*child_it)->notifyChildren(info);
+		ret = ret || childp->notifyChildren(info);
 	}
 	return ret;
 }
 		
 	return *sDrawContextStack.back();
 }
+
+LLSD LLView::getInfo(void)
+{
+	LLSD info;
+	addInfo(info);
+	return info;
+}
+
+void LLView::addInfo(LLSD & info)
+{
+	info["path"] = getPathname();
+	info["class"] = typeid(*this).name();
+	info["visible"] = getVisible();
+	info["visible_chain"] = isInVisibleChain();
+	info["enabled"] = getEnabled();
+	info["enabled_chain"] = isInEnabledChain();
+	info["available"] = isAvailable();
+	LLRect rect(calcScreenRect());
+	info["rect"] = LLSDMap("left", rect.mLeft)("top", rect.mTop)
+				("right", rect.mRight)("bottom", rect.mBottom);
+}

indra/llui/llview.h

 #include "llfocusmgr.h"
 
 #include <list>
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
 
 class LLSD;
 
 	/*virtual*/ void	screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const;
 	/*virtual*/ void	localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const;
 
-	virtual		LLView*	childFromPoint(S32 x, S32 y);
+	virtual		LLView*	childFromPoint(S32 x, S32 y, bool recur=false);
 
 	// view-specific handlers 
 	virtual void	onMouseEnter(S32 x, S32 y, MASK mask);
 	virtual void	onMouseLeave(S32 x, S32 y, MASK mask);
 
+	std::string getPathname() const;
+	// static method handles NULL pointer too
+	static std::string getPathname(const LLView*);
 
 	template <class T> T* findChild(const std::string& name, BOOL recurse = TRUE) const
 	{
 	virtual S32	notify(const LLSD& info) { return 0;};
 
 	static const LLViewDrawContext& getDrawContext();
+	
+	// Returns useful information about this ui widget.
+	LLSD getInfo(void);
 
 protected:
 	void			drawDebugRect();
 	void			drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0, BOOL force_draw = FALSE);
 	void			drawChildren();
+	bool			visibleAndContains(S32 local_x, S32 local_Y);
+	bool			visibleEnabledAndContains(S32 local_x, S32 local_y);
+	void			logMouseEvent();
 
 	LLView*	childrenHandleKey(KEY key, MASK mask);
 	LLView* childrenHandleUnicodeChar(llwchar uni_char);
 	LLView* childrenHandleToolTip(S32 x, S32 y, MASK mask);
 
 	ECursorType mHoverCursor;
-	
+
+	virtual void addInfo(LLSD & info);
 private:
 
+	template <typename METHOD, typename XDATA>
+	LLView* childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDATA extra);
+
+	template <typename METHOD, typename CHARTYPE>
+	LLView* childrenHandleCharEvent(const std::string& desc, const METHOD& method,
+									CHARTYPE c, MASK mask);
+
+	// adapter to blur distinction between handleKey() and handleUnicodeChar()
+	// for childrenHandleCharEvent()
+	BOOL	handleUnicodeCharWithDummyMask(llwchar uni_char, MASK /* dummy */, BOOL from_parent)
+	{
+		return handleUnicodeChar(uni_char, from_parent);
+	}
+
 	LLView*		mParentView;
 	child_list_t mChildList;
 
 
 	LLView& getDefaultWidgetContainer() const;
 
+	// This allows special mouse-event targeting logic for testing.
+	typedef boost::function<bool(const LLView*, S32 x, S32 y)> DrilldownFunc;
+	static DrilldownFunc sDrilldown;
+
 public:
+	// This is the only public accessor to alter sDrilldown. This is not
+	// an accident. The intended usage pattern is like:
+	// {
+	//     LLView::TemporaryDrilldownFunc scoped_func(myfunctor);
+	//     // ... test with myfunctor ...
+	// } // exiting block restores original LLView::sDrilldown
+	class TemporaryDrilldownFunc: public boost::noncopyable
+	{
+	public:
+		TemporaryDrilldownFunc(const DrilldownFunc& func):
+			mOldDrilldown(sDrilldown)
+		{
+			sDrilldown = func;
+		}
+
+		~TemporaryDrilldownFunc()
+		{
+			sDrilldown = mOldDrilldown;
+		}
+
+	private:
+		DrilldownFunc mOldDrilldown;
+	};
+
 	// Depth in view hierarchy during rendering
 	static S32	sDepth;
 

indra/llui/llviewinject.cpp

+/**
+ * @file   llviewinject.cpp
+ * @author Nat Goodspeed
+ * @date   2011-08-16
+ * @brief  Implementation for llviewinject.
+ * 
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Copyright (c) 2011, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llviewinject.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+
+llview::TargetEvent::TargetEvent(LLView* view)
+{
+    // Walk up the view tree from target LLView to the root (NULL). If
+    // passed NULL, iterate 0 times.
+    for (; view; view = view->getParent())
+    {
+        // At each level, operator() is going to ask: for a particular parent
+        // LLView*, which of its children should I select? So for this view's
+        // parent, select this view.
+        mChildMap[view->getParent()] = view;
+    }
+}
+
+bool llview::TargetEvent::operator()(const LLView* view, S32 /*x*/, S32 /*y*/) const
+{
+    // We are being called to decide whether to direct an incoming mouse event
+    // to this child view. (Normal LLView processing is to check whether the
+    // incoming (x, y) is within the view.) Look up the parent to decide
+    // whether, for that parent, this is the previously-selected child.
+    ChildMap::const_iterator found(mChildMap.find(view->getParent()));
+    // If we're looking at a child whose parent isn't even in the map, never
+    // mind.
+    if (found == mChildMap.end())
+    {
+        return false;
+    }
+    // So, is this the predestined child for this parent?
+    return (view == found->second);
+}

indra/llui/llviewinject.h

+/**
+ * @file   llviewinject.h
+ * @author Nat Goodspeed
+ * @date   2011-08-16
+ * @brief  Supplemental LLView functionality used for simulating UI events.
+ * 
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Copyright (c) 2011, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLVIEWINJECT_H)
+#define LL_LLVIEWINJECT_H
+
+#include "llview.h"
+#include <map>
+
+namespace llview
+{
+
+    /**
+     * TargetEvent is a callable with state, specifically intended for use as
+     * an LLView::TemporaryDrilldownFunc. Instantiate it with the desired
+     * target LLView*; pass it to a TemporaryDrilldownFunc instance;
+     * TargetEvent::operator() will then attempt to direct subsequent mouse
+     * events to the desired target LLView*. (This is an "attempt" because
+     * LLView will still balk unless the target LLView and every parent are
+     * visible and enabled.)
+     */
+    class TargetEvent
+    {
+    public:
+        /**
+         * Construct TargetEvent with the desired target LLView*. (See
+         * LLUI::resolvePath() to obtain an LLView* given a string pathname.)
+         * This sets up for operator().
+         */
+        TargetEvent(LLView* view);
+
+        /**
+         * This signature must match LLView::DrilldownFunc. When you install
+         * this TargetEvent instance using LLView::TemporaryDrilldownFunc,
+         * LLView will call this method to decide whether to propagate an
+         * incoming mouse event to the passed child LLView*.
+         */
+        bool operator()(const LLView*, S32 x, S32 y) const;
+
+    private:
+        // For a given parent LLView, identify which child to select.
+        typedef std::map<LLView*, LLView*> ChildMap;
+        ChildMap mChildMap;
+    };
+
+} // llview namespace
+
+#endif /* ! defined(LL_LLVIEWINJECT_H) */

indra/llwindow/CMakeLists.txt

     llkeyboardheadless.cpp
     llwindowheadless.cpp
     llwindowcallbacks.cpp
-    llwindowlistener.cpp
     )
 
 set(llwindow_HEADER_FILES
     llkeyboardheadless.h
     llwindowheadless.h
     llwindowcallbacks.h
-    llwindowlistener.h
     )
 
 set(viewer_SOURCE_FILES

indra/llwindow/llwindow.cpp

 #include "llkeyboard.h"
 #include "linked_lists.h"
 #include "llwindowcallbacks.h"
-#include "llwindowlistener.h"
-#include <boost/lambda/core.hpp>
 
 
 //
 	  mFlags(flags),
 	  mHighSurrogate(0)
 {
-	// gKeyboard is still NULL, so it doesn't do LLWindowListener any good to
-	// pass its value right now. Instead, pass it a nullary function that
-	// will, when we later need it, return the value of gKeyboard.
-	// boost::lambda::var() constructs such a functor on the fly.
-	mListener = new LLWindowListener(callbacks, boost::lambda::var(gKeyboard));
 }
 
 LLWindow::~LLWindow()
 {
-	delete mListener;
-	mListener = NULL;
 }
 
 //virtual

indra/llwindow/llwindow.h

 class LLSplashScreen;
 class LLPreeditor;
 class LLWindowCallbacks;
-class LLWindowListener;
 
 // Refer to llwindow_test in test/common/llwindow for usage example
 
 	BOOL		mHideCursorPermanent;
 	U32			mFlags;
 	U16			mHighSurrogate;
-	LLWindowListener* mListener;
 
  	// Handle a UTF-16 encoding unit received from keyboard.
  	// Converting the series of UTF-16 encoding units to UTF-32 data,

indra/llwindow/llwindowlistener.cpp

-/** 
- * @file llwindowlistener.cpp
- * @brief EventAPI interface for injecting input into LLWindow
- *
- * $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 "linden_common.h"
-
-#include "llwindowlistener.h"
-
-#include "llcoord.h"
-#include "llkeyboard.h"
-#include "llwindowcallbacks.h"
-#include <map>
-
-LLWindowListener::LLWindowListener(LLWindowCallbacks *window, const KeyboardGetter& kbgetter)
-	: LLEventAPI("LLWindow", "Inject input events into the LLWindow instance"),
-	  mWindow(window),
-	  mKbGetter(kbgetter)
-{
-	std::string keySomething =
-		"Given [\"keysym\"], [\"keycode\"] or [\"char\"], inject the specified ";
-	std::string keyExplain =
-		"(integer keycode values, or keysym \"XXXX\" from any KEY_XXXX, in\n"
-		"http://hg.secondlife.com/viewer-development/src/tip/indra/llcommon/indra_constants.h )";
-	std::string mask =
-		"Specify optional [\"mask\"] as an array containing any of \"CONTROL\", \"ALT\",\n"
-		"\"SHIFT\" or \"MAC_CONTROL\"; the corresponding modifier bits will be combined\n"
-		"to form the mask used with the event.";
-
-	std::string mouseSomething =
-		"Given [\"button\"], [\"x\"] and [\"y\"], inject the given mouse ";
-	std::string mouseExplain =
-		"(button values \"LEFT\", \"MIDDLE\", \"RIGHT\")";
-
-	add("keyDown",
-		keySomething + "keypress event.\n" + keyExplain + '\n' + mask,
-		&LLWindowListener::keyDown);
-	add("keyUp",
-		keySomething + "key release event.\n" + keyExplain + '\n' + mask,
-		&LLWindowListener::keyUp);
-	add("mouseDown",
-		mouseSomething + "click event.\n" + mouseExplain + '\n' + mask,
-		&LLWindowListener::mouseDown);
-	add("mouseUp",
-		mouseSomething + "release event.\n" + mouseExplain + '\n' + mask,
-		&LLWindowListener::mouseUp);
-	add("mouseMove",
-		std::string("Given [\"x\"] and [\"y\"], inject the given mouse movement event.\n") +
-		mask,
-		&LLWindowListener::mouseMove);
-	add("mouseScroll",
-		"Given an integer number of [\"clicks\"], inject the given mouse scroll event.\n"
-		"(positive clicks moves downward through typical content)",
-		&LLWindowListener::mouseScroll);
-}
-
-template <typename MAPPED>
-class StringLookup
-{
-private:
-	std::string mDesc;
-	typedef std::map<std::string, MAPPED> Map;
-	Map mMap;
-
-public:
-	StringLookup(const std::string& desc): mDesc(desc) {}
-
-	MAPPED lookup(const typename Map::key_type& key) const
-	{
-		typename Map::const_iterator found = mMap.find(key);
-		if (found == mMap.end())
-		{
-			LL_WARNS("LLWindowListener") << "Unknown " << mDesc << " '" << key << "'" << LL_ENDL;
-			return MAPPED();
-		}
-		return found->second;
-	}
-
-protected:
-	void add(const typename Map::key_type& key, const typename Map::mapped_type& value)
-	{
-		mMap.insert(typename Map::value_type(key, value));
-	}
-};
-
-// for WhichKeysym. KeyProxy is like the typedef KEY, except that KeyProxy()
-// (default-constructed) is guaranteed to have the value KEY_NONE.
-class KeyProxy
-{
-public:
-	KeyProxy(KEY k): mKey(k) {}
-	KeyProxy(): mKey(KEY_NONE) {}
-	operator KEY() const { return mKey; }
-
-private:
-	KEY mKey;
-};
-
-struct WhichKeysym: public StringLookup<KeyProxy>
-{
-	WhichKeysym(): StringLookup<KeyProxy>("keysym")
-	{
-		add("RETURN",		KEY_RETURN);
-		add("LEFT",			KEY_LEFT);
-		add("RIGHT",		KEY_RIGHT);
-		add("UP",			KEY_UP);
-		add("DOWN",			KEY_DOWN);
-		add("ESCAPE",		KEY_ESCAPE);
-		add("BACKSPACE",	KEY_BACKSPACE);
-		add("DELETE",		KEY_DELETE);
-		add("SHIFT",		KEY_SHIFT);
-		add("CONTROL",		KEY_CONTROL);
-		add("ALT",			KEY_ALT);
-		add("HOME",			KEY_HOME);
-		add("END",			KEY_END);
-		add("PAGE_UP",		KEY_PAGE_UP);
-		add("PAGE_DOWN",	KEY_PAGE_DOWN);
-		add("HYPHEN",		KEY_HYPHEN);
-		add("EQUALS",		KEY_EQUALS);
-		add("INSERT",		KEY_INSERT);
-		add("CAPSLOCK",		KEY_CAPSLOCK);
-		add("TAB",			KEY_TAB);
-		add("ADD",			KEY_ADD);
-		add("SUBTRACT",		KEY_SUBTRACT);
-		add("MULTIPLY",		KEY_MULTIPLY);
-		add("DIVIDE",		KEY_DIVIDE);
-		add("F1",			KEY_F1);
-		add("F2",			KEY_F2);
-		add("F3",			KEY_F3);
-		add("F4",			KEY_F4);
-		add("F5",			KEY_F5);
-		add("F6",			KEY_F6);
-		add("F7",			KEY_F7);
-		add("F8",			KEY_F8);
-		add("F9",			KEY_F9);
-		add("F10",			KEY_F10);
-		add("F11",			KEY_F11);
-		add("F12",			KEY_F12);
-
-		add("PAD_UP",		KEY_PAD_UP);
-		add("PAD_DOWN",		KEY_PAD_DOWN);
-		add("PAD_LEFT",		KEY_PAD_LEFT);
-		add("PAD_RIGHT",	KEY_PAD_RIGHT);
-		add("PAD_HOME",		KEY_PAD_HOME);
-		add("PAD_END",		KEY_PAD_END);
-		add("PAD_PGUP",		KEY_PAD_PGUP);
-		add("PAD_PGDN",		KEY_PAD_PGDN);
-		add("PAD_CENTER",	KEY_PAD_CENTER); // the 5 in the middle
-		add("PAD_INS",		KEY_PAD_INS);
-		add("PAD_DEL",		KEY_PAD_DEL);
-		add("PAD_RETURN",	KEY_PAD_RETURN);
-		add("PAD_ADD",		KEY_PAD_ADD); // not used
-		add("PAD_SUBTRACT", KEY_PAD_SUBTRACT); // not used
-		add("PAD_MULTIPLY", KEY_PAD_MULTIPLY); // not used
-		add("PAD_DIVIDE",	KEY_PAD_DIVIDE); // not used
-
-		add("BUTTON0",		KEY_BUTTON0);
-		add("BUTTON1",		KEY_BUTTON1);
-		add("BUTTON2",		KEY_BUTTON2);
-		add("BUTTON3",		KEY_BUTTON3);
-		add("BUTTON4",		KEY_BUTTON4);
-		add("BUTTON5",		KEY_BUTTON5);
-		add("BUTTON6",		KEY_BUTTON6);
-		add("BUTTON7",		KEY_BUTTON7);
-		add("BUTTON8",		KEY_BUTTON8);
-		add("BUTTON9",		KEY_BUTTON9);
-		add("BUTTON10",		KEY_BUTTON10);
-		add("BUTTON11",		KEY_BUTTON11);
-		add("BUTTON12",		KEY_BUTTON12);
-		add("BUTTON13",		KEY_BUTTON13);
-		add("BUTTON14",		KEY_BUTTON14);
-		add("BUTTON15",		KEY_BUTTON15);
-	}
-};
-static WhichKeysym keysyms;
-
-struct WhichMask: public StringLookup<MASK>
-{
-	WhichMask(): StringLookup<MASK>("shift mask")
-	{
-		add("NONE",			MASK_NONE);
-		add("CONTROL",		MASK_CONTROL); // Mapped to cmd on Macs
-		add("ALT",			MASK_ALT);
-		add("SHIFT",		MASK_SHIFT);
-		add("MAC_CONTROL",	MASK_MAC_CONTROL); // Un-mapped Ctrl key on Macs, not used on Windows
-	}
-};
-static WhichMask masks;
-
-static MASK getMask(const LLSD& event)
-{
-	MASK mask(MASK_NONE);
-	LLSD masknames(event["mask"]);
-	for (LLSD::array_const_iterator ai(masknames.beginArray()), aend(masknames.endArray());
-		 ai != aend; ++ai)
-	{
-		mask |= masks.lookup(*ai);
-	}
-	return mask;
-}
-
-static KEY getKEY(const LLSD& event)
-{
-    if (event.has("keysym"))
-	{
-		return keysyms.lookup(event["keysym"]);
-	}
-	else if (event.has("keycode"))
-	{
-		return KEY(event["keycode"].asInteger());
-	}
-	else
-	{
-		return KEY(event["char"].asString()[0]);
-	}
-}
-
-void LLWindowListener::keyDown(LLSD const & evt)
-{
-	mKbGetter()->handleTranslatedKeyDown(getKEY(evt), getMask(evt));
-}
-
-void LLWindowListener::keyUp(LLSD const & evt)
-{
-	mKbGetter()->handleTranslatedKeyUp(getKEY(evt), getMask(evt));
-}
-
-// for WhichButton
-typedef BOOL (LLWindowCallbacks::*MouseFunc)(LLWindow *, LLCoordGL, MASK);
-struct Actions
-{
-	Actions(const MouseFunc& d, const MouseFunc& u): down(d), up(u), valid(true) {}
-	Actions(): valid(false) {}
-	MouseFunc down, up;
-	bool valid;
-};
-
-struct WhichButton: public StringLookup<Actions>
-{
-	WhichButton(): StringLookup<Actions>("mouse button")
-	{
-		add("LEFT",		Actions(&LLWindowCallbacks::handleMouseDown,
-								&LLWindowCallbacks::handleMouseUp));
-		add("RIGHT",	Actions(&LLWindowCallbacks::handleRightMouseDown,
-								&LLWindowCallbacks::handleRightMouseUp));
-		add("MIDDLE",	Actions(&LLWindowCallbacks::handleMiddleMouseDown,
-								&LLWindowCallbacks::handleMiddleMouseUp));
-	}
-};
-static WhichButton buttons;
-
-static LLCoordGL getPos(const LLSD& event)
-{
-	return LLCoordGL(event["x"].asInteger(), event["y"].asInteger());
-}
-
-void LLWindowListener::mouseDown(LLSD const & evt)
-{
-	Actions actions(buttons.lookup(evt["button"]));
-	if (actions.valid)
-	{
-		(mWindow->*(actions.down))(NULL, getPos(evt), getMask(evt));
-	}
-}
-
-void LLWindowListener::mouseUp(LLSD const & evt)
-{
-	Actions actions(buttons.lookup(evt["button"]));
-	if (actions.valid)
-	{
-		(mWindow->*(actions.up))(NULL, getPos(evt), getMask(evt));
-	}
-}
-
-void LLWindowListener::mouseMove(LLSD const & evt)
-{
-	mWindow->handleMouseMove(NULL, getPos(evt), getMask(evt));
-}
-
-void LLWindowListener::mouseScroll(LLSD const & evt)
-{
-	S32 clicks = evt["clicks"].asInteger();
-
-	mWindow->handleScrollWheel(NULL, clicks);
-}
-

indra/llwindow/llwindowlistener.h

-/** 
- * @file llwindowlistener.h
- * @brief EventAPI interface for injecting input into LLWindow
- *
- * $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_LLWINDOWLISTENER_H
-#define LL_LLWINDOWLISTENER_H
-
-#include "lleventapi.h"
-#include <boost/function.hpp>
-
-class LLKeyboard;
-class LLWindowCallbacks;
-
-class LLWindowListener : public LLEventAPI
-{
-public:
-	typedef boost::function<LLKeyboard*()> KeyboardGetter;
-	LLWindowListener(LLWindowCallbacks * window, const KeyboardGetter& kbgetter);
-
-	void keyDown(LLSD const & evt);
-	void keyUp(LLSD const & evt);
-	void mouseDown(LLSD const & evt);
-	void mouseUp(LLSD const & evt);
-	void mouseMove(LLSD const & evt);
-	void mouseScroll(LLSD const & evt);
-
-private:
-	LLWindowCallbacks * mWindow;
-	KeyboardGetter mKbGetter;
-};
-
-
-#endif // LL_LLWINDOWLISTENER_H

indra/llxml/llcontrol.h

 	ctrl_name_table_t mNameTable;
 	std::string mTypeString[TYPE_COUNT];
 
+public:
 	eControlType typeStringToEnum(const std::string& typestr);
 	std::string typeEnumToString(eControlType typeenum);	
-public:
+
 	LLControlGroup(const std::string& name);
 	~LLControlGroup();
 	void cleanup();

indra/newview/CMakeLists.txt

     llweb.cpp
     llwebsharing.cpp
     llwind.cpp
+    llwindowlistener.cpp
     llwlanimator.cpp
     llwldaycycle.cpp
     llwlhandlers.cpp
     llweb.h
     llwebsharing.h
     llwind.h
+    llwindowlistener.h
     llwlanimator.h
     llwldaycycle.h
     llwlhandlers.h

indra/newview/gpu_table.txt

 // against driver strings, a class number, and whether we claim
 // to support them or not.
 //
+// Case is not significant in either the regular expressions or the
+// driver strings; the recognizer code lowercases both before using
+// them.
+//
 // If you modify this table, use the (perl) gpu_table_tester
 // to compare the results of recognizing known cards (it is easy
 // to mess this up by putting things in the wrong order):
 // perl ../../scripts/gpu_table_tester -g gpu_table.txt tests/gpus_seen.txt | diff - tests/gpus_results.txt
 //
 // Format:
-//   Fields are separated by one or more tab (not space) characters
-//   <recognizer name>	<regular expression>	<class>		<supported>
+//	 Fields are separated by one or more tab (not space) characters
+//	 <recognizer name>	<regular expression>	<class>		<supported>
 //
 // Class Numbers:
-//		0 - Defaults to low graphics settings.  No shaders on by default
-//		1 - Defaults to mid graphics settings.  Basic shaders on by default
-//		2 - Defaults to high graphics settings.  Atmospherics on by default.
+//		0 - Defaults to low graphics settings.	No shaders on by default
+//		1 - Defaults to mid graphics settings.	Basic shaders on by default
+//		2 - Defaults to high graphics settings.	 Atmospherics on by default.
 //		3 - Same as class 2 for now.
 //
 // Supported Number:
 ATI All-in-Wonder X1800			.*ATI.*All-in-Wonder X18.*					3		1
 ATI All-in-Wonder X1900			.*ATI.*All-in-Wonder X19.*					3		1
 ATI All-in-Wonder PCI-E			.*ATI.*All-in-Wonder.*PCI-E.*				1		1
-ATI All-in-Wonder Radeon 		.*ATI.*All-in-Wonder Radeon.*				0		1
+ATI All-in-Wonder Radeon		.*ATI.*All-in-Wonder Radeon.*				0		1
+ATI ASUS ARES					.*ATI.*ASUS.*ARES.*							3		1
 ATI ASUS A9xxx					.*ATI.*ASUS.*A9.*							1		1
 ATI ASUS AH24xx					.*ATI.*ASUS.*AH24.*							1		1
 ATI ASUS AH26xx					.*ATI.*ASUS.*AH26.*							3		1
 ATI ASUS AX8xx					.*ATI.*ASUS.*AX8.*							2		1
 ATI ASUS EAH24xx				.*ATI.*ASUS.*EAH24.*						2		1
 ATI ASUS EAH26xx				.*ATI.*ASUS.*EAH26.*						3		1
+ATI ASUS EAH29xx				.*ATI.*ASUS.*EAH29.*						3		1
 ATI ASUS EAH34xx				.*ATI.*ASUS.*EAH34.*						1		1
 ATI ASUS EAH36xx				.*ATI.*ASUS.*EAH36.*						3		1
 ATI ASUS EAH38xx				.*ATI.*ASUS.*EAH38.*						3		1
 ATI ASUS EAH48xx				.*ATI.*ASUS.*EAH48.*						3		1
 ATI ASUS EAH57xx				.*ATI.*ASUS.*EAH57.*						3		1
 ATI ASUS EAH58xx				.*ATI.*ASUS.*EAH58.*						3		1
+ATI ASUS EAH6xxx				.*ATI.*ASUS.*EAH6.*							3		1
 ATI ASUS Radeon X1xxx			.*ATI.*ASUS.*X1.*							3		1
 ATI Radeon X7xx					.*ATI.*ASUS.*X7.*							1		1
-ATI Radeon X1xxx				.*ATI.*X1.*									0		1
-ATI Radeon X13xx				.*ATI.*Diamond X13.*						1		1
-ATI Radeon X16xx				.*ATI.*Diamond X16.*						1		1
-ATI Radeon X19xx				.*ATI.*Diamond X19.*						1		1
+ATI Radeon X19xx				.*ATI.*(Radeon|Diamond) X19.* ?.*			3		1
+ATI Radeon X18xx				.*ATI.*(Radeon|Diamond) X18.* ?.*			3		1
+ATI Radeon X17xx				.*ATI.*(Radeon|Diamond) X17.* ?.*			2		1
+ATI Radeon X16xx				.*ATI.*(Radeon|Diamond) X16.* ?.*			2		1
+ATI Radeon X15xx				.*ATI.*(Radeon|Diamond) X15.* ?.*			2		1
+ATI Radeon X13xx				.*ATI.*(Radeon|Diamond) X13.* ?.*			1		1
+ATI Radeon X1xxx				.*ATI.*(Radeon|Diamond) X1.. ?.*			1		1
+ATI Radeon X2xxx				.*ATI.*(Radeon|Diamond) X2.. ?.*			1		1
 ATI Display Adapter				.*ATI.*display adapter.*					0		1
 ATI FireGL 5200					.*ATI.*FireGL V52.*							0		1
 ATI FireGL 5xxx					.*ATI.*FireGL V5.*							1		1
 ATI FirePro M7740				.*ATI.*FirePro.*M77.*						3		1
 ATI FirePro M7820				.*ATI.*FirePro.*M78.*						3		1
 ATI FireMV						.*ATI.*FireMV.*								0		1
-ATI Geforce 9500 GT				.*ATI.*Geforce 9500 *GT						2		1
-ATI Geforce 9800 GT				.*ATI.*Geforce 9800 *GT						2		1
+ATI Geforce 9500 GT				.*ATI.*Geforce 9500 *GT.*					2		1
+ATI Geforce 9600 GT				.*ATI.*Geforce 9600 *GT.*					2		1
+ATI Geforce 9800 GT				.*ATI.*Geforce 9800 *GT.*					2		1
 ATI Generic						.*ATI.*Generic.*							0		0
 ATI Hercules 9800				.*ATI.*Hercules.*9800.*						1		1
 ATI IGP 340M					.*ATI.*IGP.*340M.*							0		0
 ATI M71							.*ATI.*M71.*								1		1
 ATI M72							.*ATI.*M72.*								1		1
 ATI M76							.*ATI.*M76.*								3		1
-ATI Mobility Radeon 4100		.*ATI.*(Mobility|MOBILITY).*41.*			0		1
-ATI Mobility Radeon 7xxx		.*ATI.*(Mobility|MOBILITY).*Radeon 7.*		0		1
-ATI Mobility Radeon 8xxx		.*ATI.*(Mobility|MOBILITY).*Radeon 8.*		0		1
-ATI Mobility Radeon 9800		.*ATI.*(Mobility|MOBILITY).*98.*			1		1
-ATI Mobility Radeon 9700		.*ATI.*(Mobility|MOBILITY).*97.*			1		1
-ATI Mobility Radeon 9600		.*ATI.*(Mobility|MOBILITY).*96.*			0		1
-ATI Mobility Radeon HD 530v		.*ATI.*(Mobility|MOBILITY).*HD *530v.*		1		1
-ATI Mobility Radeon HD 540v		.*ATI.*(Mobility|MOBILITY).*HD *540v.*		2		1
-ATI Mobility Radeon HD 545v		.*ATI.*(Mobility|MOBILITY).*HD *545v.*		2		1
-ATI Mobility Radeon HD 550v		.*ATI.*(Mobility|MOBILITY).*HD *550v.*		2		1
-ATI Mobility Radeon HD 560v		.*ATI.*(Mobility|MOBILITY).*HD *560v.*		2		1
-ATI Mobility Radeon HD 565v		.*ATI.*(Mobility|MOBILITY).*HD *565v.*		2		1
-ATI Mobility Radeon HD 2300		.*ATI.*(Mobility|MOBILITY).*HD *23.*		1		1
-ATI Mobility Radeon HD 2400		.*ATI.*(Mobility|MOBILITY).*HD *24.*		1		1
-ATI Mobility Radeon HD 2600		.*ATI.*(Mobility|MOBILITY).*HD *26.*		3		1
-ATI Mobility Radeon HD 2700		.*ATI.*(Mobility|MOBILITY).*HD *27.*		3		1
-ATI Mobility Radeon HD 3100		.*ATI.*(Mobility|MOBILITY).*HD *31.*		0		1
-ATI Mobility Radeon HD 3200		.*ATI.*(Mobility|MOBILITY).*HD *32.*		0		1
-ATI Mobility Radeon HD 3400		.*ATI.*(Mobility|MOBILITY).*HD *34.*		2		1
-ATI Mobility Radeon HD 3600		.*ATI.*(Mobility|MOBILITY).*HD *36.*		3		1
-ATI Mobility Radeon HD 3800		.*ATI.*(Mobility|MOBILITY).*HD *38.*		3		1
-ATI Mobility Radeon HD 4200		.*ATI.*(Mobility|MOBILITY).*HD *42.*		2		1
-ATI Mobility Radeon HD 4300		.*ATI.*(Mobility|MOBILITY).*HD *43.*		2		1
-ATI Mobility Radeon HD 4500		.*ATI.*(Mobility|MOBILITY).*HD *45.*		3		1
-ATI Mobility Radeon HD 4600		.*ATI.*(Mobility|MOBILITY).*HD *46.*		3		1
-ATI Mobility Radeon HD 4800		.*ATI.*(Mobility|MOBILITY).*HD *48.*		3		1
-ATI Mobility Radeon HD 5100		.*ATI.*(Mobility|MOBILITY).*HD *51.*		2		1
-ATI Mobility Radeon HD 5300		.*ATI.*(Mobility|MOBILITY).*HD *53.*		2		1
-ATI Mobility Radeon HD 5400		.*ATI.*(Mobility|MOBILITY).*HD *54.*		2		1
-ATI Mobility Radeon HD 5500		.*ATI.*(Mobility|MOBILITY).*HD *55.*		2		1
-ATI Mobility Radeon HD 5600		.*ATI.*(Mobility|MOBILITY).*HD *56.*		2		1
-ATI Mobility Radeon HD 5700		.*ATI.*(Mobility|MOBILITY).*HD *57.*		3		1
-ATI Mobility Radeon HD 6200		.*ATI.*(Mobility|MOBILITY).*HD *62.*		2		1
-ATI Mobility Radeon HD 6300		.*ATI.*(Mobility|MOBILITY).*HD *63.*		2		1