summaryrefslogtreecommitdiff
path: root/indra/newview/llwindowlistener.cpp
diff options
context:
space:
mode:
authorAndrey Lihatskiy <alihatskiy@productengine.com>2024-05-15 16:35:49 +0300
committerGitHub <noreply@github.com>2024-05-15 16:35:49 +0300
commite49dcb8d0c9f539997effb640e350d9d0689aae6 (patch)
tree1bf99eaccce6de17c62f13c6595f7f497548dc5c /indra/newview/llwindowlistener.cpp
parent531cd34f670170ade57f8813fe48012b61a1d3c2 (diff)
parent5f8a7374b9f18e0112d6749a9c845bd077a81acb (diff)
Merge pull request #1476 from secondlife/marchcat/x-b-merge
Maint X -> Maint B merge
Diffstat (limited to 'indra/newview/llwindowlistener.cpp')
-rw-r--r--indra/newview/llwindowlistener.cpp746
1 files changed, 373 insertions, 373 deletions
diff --git a/indra/newview/llwindowlistener.cpp b/indra/newview/llwindowlistener.cpp
index 0edabf358f..87d18cfc00 100644
--- a/indra/newview/llwindowlistener.cpp
+++ b/indra/newview/llwindowlistener.cpp
@@ -1,25 +1,25 @@
-/**
+/**
* @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$
*/
@@ -47,96 +47,96 @@
#include <boost/bind.hpp>
LLWindowListener::LLWindowListener(LLViewerWindow *window, const KeyboardGetter& kbgetter)
- : LLEventAPI("LLWindow", "Inject input events into the LLWindow instance"),
- mWindow(window),
- mKbGetter(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 string from any addKeyName() call in\n"
- "http://bitbucket.org/lindenlab/viewer-release/src/tip/indra/llwindow/llkeyboard.cpp )\n";
- std::string mask =
- "Specify optional [\"mask\"] as an array containing any of \"CTL\", \"ALT\",\n"
- "\"SHIFT\" or \"MAC_CONTROL\"; the corresponding modifier bits will be combined\n"
- "to form the mask used with the event.";
-
- std::string given = "Given ";
- std::string mouseParams =
- "optional [\"path\"], optional [\"x\"] and [\"y\"], inject the requested mouse ";
- std::string buttonParams =
- std::string("[\"button\"], ") + mouseParams;
- std::string buttonExplain =
- "(button values \"LEFT\", \"MIDDLE\", \"RIGHT\")\n";
- std::string paramsExplain =
- "[\"path\"] is as for LLUI::getInstance()->resolvePath(), described in\n"
- "http://bitbucket.org/lindenlab/viewer-release/src/tip/indra/llui/llui.h\n"
- "If you omit [\"path\"], you must specify both [\"x\"] and [\"y\"].\n"
- "If you specify [\"path\"] without both [\"x\"] and [\"y\"], will synthesize (x, y)\n"
- "in the center of the LLView selected by [\"path\"].\n"
- "You may specify [\"path\"] with both [\"x\"] and [\"y\"], will use your (x, y).\n"
- "This may cause the LLView selected by [\"path\"] to reject the event.\n"
- "Optional [\"reply\"] requests a reply event on the named LLEventPump.\n"
- "reply[\"error\"] isUndefined (None) on success, else an explanatory message.\n";
-
- add("getInfo",
- "Get information about the ui element specified by [\"path\"]",
- &LLWindowListener::getInfo,
- LLSDMap("reply", LLSD()));
- add("getPaths",
- "Send on [\"reply\"] an event in which [\"paths\"] is an array of valid LLView\n"
- "pathnames. Optional [\"under\"] pathname specifies the base node under which\n"
- "to list; all nodes from root if no [\"under\"].",
- &LLWindowListener::getPaths,
- LLSDMap("reply", LLSD()));
- add("keyDown",
- keySomething + "keypress event.\n" + keyExplain + mask,
- &LLWindowListener::keyDown);
- add("keyUp",
- keySomething + "key release event.\n" + keyExplain + mask,
- &LLWindowListener::keyUp);
- add("mouseDown",
- given + buttonParams + "click event.\n" + buttonExplain + paramsExplain + mask,
- &LLWindowListener::mouseDown);
- add("mouseUp",
- given + buttonParams + "release event.\n" + buttonExplain + paramsExplain + mask,
- &LLWindowListener::mouseUp);
- add("mouseMove",
- given + mouseParams + "movement event.\n" + paramsExplain + mask,
- &LLWindowListener::mouseMove);
- add("mouseScroll",
- "Given an integer number of [\"clicks\"], inject the requested mouse scroll event.\n"
- "(positive clicks moves downward through typical content)",
- &LLWindowListener::mouseScroll);
+ std::string keySomething =
+ "Given [\"keysym\"], [\"keycode\"] or [\"char\"], inject the specified ";
+ std::string keyExplain =
+ "(integer keycode values, or keysym string from any addKeyName() call in\n"
+ "http://bitbucket.org/lindenlab/viewer-release/src/tip/indra/llwindow/llkeyboard.cpp )\n";
+ std::string mask =
+ "Specify optional [\"mask\"] as an array containing any of \"CTL\", \"ALT\",\n"
+ "\"SHIFT\" or \"MAC_CONTROL\"; the corresponding modifier bits will be combined\n"
+ "to form the mask used with the event.";
+
+ std::string given = "Given ";
+ std::string mouseParams =
+ "optional [\"path\"], optional [\"x\"] and [\"y\"], inject the requested mouse ";
+ std::string buttonParams =
+ std::string("[\"button\"], ") + mouseParams;
+ std::string buttonExplain =
+ "(button values \"LEFT\", \"MIDDLE\", \"RIGHT\")\n";
+ std::string paramsExplain =
+ "[\"path\"] is as for LLUI::getInstance()->resolvePath(), described in\n"
+ "http://bitbucket.org/lindenlab/viewer-release/src/tip/indra/llui/llui.h\n"
+ "If you omit [\"path\"], you must specify both [\"x\"] and [\"y\"].\n"
+ "If you specify [\"path\"] without both [\"x\"] and [\"y\"], will synthesize (x, y)\n"
+ "in the center of the LLView selected by [\"path\"].\n"
+ "You may specify [\"path\"] with both [\"x\"] and [\"y\"], will use your (x, y).\n"
+ "This may cause the LLView selected by [\"path\"] to reject the event.\n"
+ "Optional [\"reply\"] requests a reply event on the named LLEventPump.\n"
+ "reply[\"error\"] isUndefined (None) on success, else an explanatory message.\n";
+
+ add("getInfo",
+ "Get information about the ui element specified by [\"path\"]",
+ &LLWindowListener::getInfo,
+ LLSDMap("reply", LLSD()));
+ add("getPaths",
+ "Send on [\"reply\"] an event in which [\"paths\"] is an array of valid LLView\n"
+ "pathnames. Optional [\"under\"] pathname specifies the base node under which\n"
+ "to list; all nodes from root if no [\"under\"].",
+ &LLWindowListener::getPaths,
+ LLSDMap("reply", LLSD()));
+ add("keyDown",
+ keySomething + "keypress event.\n" + keyExplain + mask,
+ &LLWindowListener::keyDown);
+ add("keyUp",
+ keySomething + "key release event.\n" + keyExplain + mask,
+ &LLWindowListener::keyUp);
+ add("mouseDown",
+ given + buttonParams + "click event.\n" + buttonExplain + paramsExplain + mask,
+ &LLWindowListener::mouseDown);
+ add("mouseUp",
+ given + buttonParams + "release event.\n" + buttonExplain + paramsExplain + mask,
+ &LLWindowListener::mouseUp);
+ add("mouseMove",
+ given + mouseParams + "movement event.\n" + paramsExplain + mask,
+ &LLWindowListener::mouseMove);
+ add("mouseScroll",
+ "Given an integer number of [\"clicks\"], inject the requested 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;
+ 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;
- }
+ 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));
- }
+ void add(const typename Map::key_type& key, const typename Map::mapped_type& value)
+ {
+ mMap.insert(typename Map::value_type(key, value));
+ }
};
namespace {
@@ -144,212 +144,212 @@ namespace {
// helper for getMask()
MASK lookupMask_(const std::string& maskname)
{
- // It's unclear to me whether MASK_MAC_CONTROL is important, but it's not
- // supported by maskFromString(). Handle that specially.
- if (maskname == "MAC_CONTROL")
- {
- return MASK_MAC_CONTROL;
- }
- else
- {
- // In case of lookup failure, return MASK_NONE, which won't affect our
- // caller's OR.
- MASK mask(MASK_NONE);
- LLKeyboard::maskFromString(maskname, &mask);
- return mask;
- }
+ // It's unclear to me whether MASK_MAC_CONTROL is important, but it's not
+ // supported by maskFromString(). Handle that specially.
+ if (maskname == "MAC_CONTROL")
+ {
+ return MASK_MAC_CONTROL;
+ }
+ else
+ {
+ // In case of lookup failure, return MASK_NONE, which won't affect our
+ // caller's OR.
+ MASK mask(MASK_NONE);
+ LLKeyboard::maskFromString(maskname, &mask);
+ return mask;
+ }
}
MASK getMask(const LLSD& event)
{
- LLSD masknames(event["mask"]);
- if (! masknames.isArray())
- {
- // If event["mask"] is a single string, perform normal lookup on it.
- return lookupMask_(masknames);
- }
-
- // Here event["mask"] is an array of mask-name strings. OR together their
- // corresponding bits.
- MASK mask(MASK_NONE);
- for (LLSD::array_const_iterator ai(masknames.beginArray()), aend(masknames.endArray());
- ai != aend; ++ai)
- {
- mask |= lookupMask_(*ai);
- }
- return mask;
+ LLSD masknames(event["mask"]);
+ if (! masknames.isArray())
+ {
+ // If event["mask"] is a single string, perform normal lookup on it.
+ return lookupMask_(masknames);
+ }
+
+ // Here event["mask"] is an array of mask-name strings. OR together their
+ // corresponding bits.
+ MASK mask(MASK_NONE);
+ for (LLSD::array_const_iterator ai(masknames.beginArray()), aend(masknames.endArray());
+ ai != aend; ++ai)
+ {
+ mask |= lookupMask_(*ai);
+ }
+ return mask;
}
KEY getKEY(const LLSD& event)
{
if (event.has("keysym"))
- {
- // Initialize to KEY_NONE; that way we can ignore the bool return from
- // keyFromString() and, in the lookup-fail case, simply return KEY_NONE.
- KEY key(KEY_NONE);
- LLKeyboard::keyFromString(event["keysym"], &key);
- return key;
- }
- else if (event.has("keycode"))
- {
- return KEY(event["keycode"].asInteger());
- }
- else
- {
- return KEY(event["char"].asString()[0]);
- }
+ {
+ // Initialize to KEY_NONE; that way we can ignore the bool return from
+ // keyFromString() and, in the lookup-fail case, simply return KEY_NONE.
+ KEY key(KEY_NONE);
+ LLKeyboard::keyFromString(event["keysym"], &key);
+ return key;
+ }
+ else if (event.has("keycode"))
+ {
+ return KEY(event["keycode"].asInteger());
+ }
+ else
+ {
+ return KEY(event["char"].asString()[0]);
+ }
}
} // namespace
void LLWindowListener::getInfo(LLSD const & evt)
{
- Response response(LLSD(), evt);
-
- if (evt.has("path"))
- {
- std::string path(evt["path"]);
- LLView * target_view = LLUI::getInstance()->resolvePath(LLUI::getInstance()->getRootView(), path);
- if (target_view != 0)
- {
- response.setResponse(target_view->getInfo());
- }
- else
- {
- response.error(STRINGIZE(evt["op"].asString() << " request "
- "specified invalid \"path\": '" << path << "'"));
- }
- }
- else
- {
- response.error(
- STRINGIZE(evt["op"].asString() << "request did not provide a path" ));
- }
+ Response response(LLSD(), evt);
+
+ if (evt.has("path"))
+ {
+ std::string path(evt["path"]);
+ LLView * target_view = LLUI::getInstance()->resolvePath(LLUI::getInstance()->getRootView(), path);
+ if (target_view != 0)
+ {
+ response.setResponse(target_view->getInfo());
+ }
+ else
+ {
+ response.error(STRINGIZE(evt["op"].asString() << " request "
+ "specified invalid \"path\": '" << path << "'"));
+ }
+ }
+ else
+ {
+ response.error(
+ STRINGIZE(evt["op"].asString() << "request did not provide a path" ));
+ }
}
void LLWindowListener::getPaths(LLSD const & request)
{
- Response response(LLSD(), request);
- LLView *root(LLUI::getInstance()->getRootView()), *base(NULL);
- // Capturing request["under"] as string means we conflate the case in
- // which there is no ["under"] key with the case in which its value is the
- // empty string. That seems to make sense to me.
- std::string under(request["under"]);
-
- // Deal with optional "under" parameter
- if (under.empty())
- {
- base = root;
- }
- else
- {
- base = LLUI::getInstance()->resolvePath(root, under);
- if (! base)
- {
- return response.error(STRINGIZE(request["op"].asString() << " request "
- "specified invalid \"under\" path: '" << under << "'"));
- }
- }
-
- // Traverse the entire subtree under 'base', collecting pathnames
- for (LLView::tree_iterator_t ti(base->beginTreeDFS()), tend(base->endTreeDFS());
- ti != tend; ++ti)
- {
- response["paths"].append((*ti)->getPathname());
- }
+ Response response(LLSD(), request);
+ LLView *root(LLUI::getInstance()->getRootView()), *base(NULL);
+ // Capturing request["under"] as string means we conflate the case in
+ // which there is no ["under"] key with the case in which its value is the
+ // empty string. That seems to make sense to me.
+ std::string under(request["under"]);
+
+ // Deal with optional "under" parameter
+ if (under.empty())
+ {
+ base = root;
+ }
+ else
+ {
+ base = LLUI::getInstance()->resolvePath(root, under);
+ if (! base)
+ {
+ return response.error(STRINGIZE(request["op"].asString() << " request "
+ "specified invalid \"under\" path: '" << under << "'"));
+ }
+ }
+
+ // Traverse the entire subtree under 'base', collecting pathnames
+ for (LLView::tree_iterator_t ti(base->beginTreeDFS()), tend(base->endTreeDFS());
+ ti != tend; ++ti)
+ {
+ response["paths"].append((*ti)->getPathname());
+ }
}
void LLWindowListener::keyDown(LLSD const & evt)
{
- Response response(LLSD(), evt);
- KEY key = getKEY(evt);
- MASK mask = getMask(evt);
-
- if (evt.has("path"))
- {
- std::string path(evt["path"]);
- LLView * target_view = LLUI::getInstance()->resolvePath(LLUI::getInstance()->getRootView(), path);
- if (target_view == 0)
- {
- response.error(STRINGIZE(evt["op"].asString() << " request "
- "specified invalid \"path\": '" << path << "'"));
- }
- else if(target_view->isAvailable())
- {
- response.setResponse(target_view->getInfo());
-
- gFocusMgr.setKeyboardFocus(target_view);
- gViewerInput.handleKey(key, mask, false);
- if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
- }
- else
- {
- response.error(STRINGIZE(evt["op"].asString() << " request "
- "element specified by \"path\": '" << path << "'"
- << " is not visible"));
- }
- }
- else
- {
- gViewerInput.handleKey(key, mask, false);
- if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
- }
+ Response response(LLSD(), evt);
+ KEY key = getKEY(evt);
+ MASK mask = getMask(evt);
+
+ if (evt.has("path"))
+ {
+ std::string path(evt["path"]);
+ LLView * target_view = LLUI::getInstance()->resolvePath(LLUI::getInstance()->getRootView(), path);
+ if (target_view == 0)
+ {
+ response.error(STRINGIZE(evt["op"].asString() << " request "
+ "specified invalid \"path\": '" << path << "'"));
+ }
+ else if(target_view->isAvailable())
+ {
+ response.setResponse(target_view->getInfo());
+
+ gFocusMgr.setKeyboardFocus(target_view);
+ gViewerInput.handleKey(key, mask, false);
+ if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
+ }
+ else
+ {
+ response.error(STRINGIZE(evt["op"].asString() << " request "
+ "element specified by \"path\": '" << path << "'"
+ << " is not visible"));
+ }
+ }
+ else
+ {
+ gViewerInput.handleKey(key, mask, false);
+ if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
+ }
}
void LLWindowListener::keyUp(LLSD const & evt)
{
- Response response(LLSD(), evt);
-
- if (evt.has("path"))
- {
- std::string path(evt["path"]);
- LLView * target_view = LLUI::getInstance()->resolvePath(LLUI::getInstance()->getRootView(), path);
- if (target_view == 0 )
- {
- response.error(STRINGIZE(evt["op"].asString() << " request "
- "specified invalid \"path\": '" << path << "'"));
- }
- else if (target_view->isAvailable())
- {
- response.setResponse(target_view->getInfo());
-
- gFocusMgr.setKeyboardFocus(target_view);
- mKbGetter()->handleTranslatedKeyUp(getKEY(evt), getMask(evt));
- }
- else
- {
- response.error(STRINGIZE(evt["op"].asString() << " request "
- "element specified byt \"path\": '" << path << "'"
- << " is not visible"));
- }
- }
- else
- {
- mKbGetter()->handleTranslatedKeyUp(getKEY(evt), getMask(evt));
- }
+ Response response(LLSD(), evt);
+
+ if (evt.has("path"))
+ {
+ std::string path(evt["path"]);
+ LLView * target_view = LLUI::getInstance()->resolvePath(LLUI::getInstance()->getRootView(), path);
+ if (target_view == 0 )
+ {
+ response.error(STRINGIZE(evt["op"].asString() << " request "
+ "specified invalid \"path\": '" << path << "'"));
+ }
+ else if (target_view->isAvailable())
+ {
+ response.setResponse(target_view->getInfo());
+
+ gFocusMgr.setKeyboardFocus(target_view);
+ mKbGetter()->handleTranslatedKeyUp(getKEY(evt), getMask(evt));
+ }
+ else
+ {
+ response.error(STRINGIZE(evt["op"].asString() << " request "
+ "element specified byt \"path\": '" << path << "'"
+ << " is not visible"));
+ }
+ }
+ else
+ {
+ mKbGetter()->handleTranslatedKeyUp(getKEY(evt), getMask(evt));
+ }
}
// for WhichButton
typedef BOOL (LLWindowCallbacks::*MouseMethod)(LLWindow *, LLCoordGL, MASK);
struct Actions
{
- Actions(const MouseMethod& d, const MouseMethod& u): down(d), up(u), valid(true) {}
- Actions(): valid(false) {}
- MouseMethod down, up;
- bool valid;
+ Actions(const MouseMethod& d, const MouseMethod& u): down(d), up(u), valid(true) {}
+ Actions(): valid(false) {}
+ MouseMethod 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));
- }
+ 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;
@@ -381,145 +381,145 @@ public:
static void mouseEvent(const MouseFunc& func, const LLSD& request)
{
- // Ensure we send response
- LLEventAPI::Response response(LLSD(), request);
- // We haven't yet established whether the incoming request has "x" and "y",
- // but capture this anyway, with 0 for omitted values.
- LLCoordGL pos(request["x"].asInteger(), request["y"].asInteger());
- bool has_pos(request.has("x") && request.has("y"));
-
- std::unique_ptr<LLView::TemporaryDrilldownFunc> tempfunc;
-
- // Documentation for mouseDown(), mouseUp() and mouseMove() claims you
- // must either specify ["path"], or both of ["x"] and ["y"]. You MAY
- // specify all. Let's say that passing "path" as an empty string is
- // equivalent to not passing it at all.
- std::string path(request["path"]);
- if (path.empty())
- {
- // Without "path", you must specify both "x" and "y".
- if (! has_pos)
- {
- return response.error(STRINGIZE(request["op"].asString() << " request "
- "without \"path\" must specify both \"x\" and \"y\": "
- << request));
- }
- }
- else // ! path.empty()
- {
- LLView* root = LLUI::getInstance()->getRootView();
- LLView* target = LLUI::getInstance()->resolvePath(root, path);
- if (! target)
- {
- return response.error(STRINGIZE(request["op"].asString() << " request "
- "specified invalid \"path\": '" << path << "'"));
- }
-
- response.setResponse(target->getInfo());
-
- // The intent of this test is to prevent trying to drill down to a
- // widget in a hidden floater, or on a tab that's not current, etc.
- if (! target->isInVisibleChain())
- {
- return response.error(STRINGIZE(request["op"].asString() << " request "
- "specified \"path\" not currently visible: '"
- << path << "'"));
- }
-
- // This test isn't folded in with the above error case since you can
- // (e.g.) pop up a tooltip even for a disabled widget.
- if (! target->isInEnabledChain())
- {
- response.warn(STRINGIZE(request["op"].asString() << " request "
- "specified \"path\" not currently enabled: '"
- << path << "'"));
- }
-
- if (! has_pos)
- {
- LLRect rect(target->calcScreenRect());
- pos.set(rect.getCenterX(), rect.getCenterY());
- // nonstandard warning tactic: probably usual case; we want event
- // sender to know synthesized (x, y), but maybe don't need to log?
- response["warnings"].append(STRINGIZE("using center point ("
- << pos.mX << ", " << pos.mY << ")"));
- }
+ // Ensure we send response
+ LLEventAPI::Response response(LLSD(), request);
+ // We haven't yet established whether the incoming request has "x" and "y",
+ // but capture this anyway, with 0 for omitted values.
+ LLCoordGL pos(request["x"].asInteger(), request["y"].asInteger());
+ bool has_pos(request.has("x") && request.has("y"));
+
+ std::unique_ptr<LLView::TemporaryDrilldownFunc> tempfunc;
+
+ // Documentation for mouseDown(), mouseUp() and mouseMove() claims you
+ // must either specify ["path"], or both of ["x"] and ["y"]. You MAY
+ // specify all. Let's say that passing "path" as an empty string is
+ // equivalent to not passing it at all.
+ std::string path(request["path"]);
+ if (path.empty())
+ {
+ // Without "path", you must specify both "x" and "y".
+ if (! has_pos)
+ {
+ return response.error(STRINGIZE(request["op"].asString() << " request "
+ "without \"path\" must specify both \"x\" and \"y\": "
+ << request));
+ }
+ }
+ else // ! path.empty()
+ {
+ LLView* root = LLUI::getInstance()->getRootView();
+ LLView* target = LLUI::getInstance()->resolvePath(root, path);
+ if (! target)
+ {
+ return response.error(STRINGIZE(request["op"].asString() << " request "
+ "specified invalid \"path\": '" << path << "'"));
+ }
+
+ response.setResponse(target->getInfo());
+
+ // The intent of this test is to prevent trying to drill down to a
+ // widget in a hidden floater, or on a tab that's not current, etc.
+ if (! target->isInVisibleChain())
+ {
+ return response.error(STRINGIZE(request["op"].asString() << " request "
+ "specified \"path\" not currently visible: '"
+ << path << "'"));
+ }
+
+ // This test isn't folded in with the above error case since you can
+ // (e.g.) pop up a tooltip even for a disabled widget.
+ if (! target->isInEnabledChain())
+ {
+ response.warn(STRINGIZE(request["op"].asString() << " request "
+ "specified \"path\" not currently enabled: '"
+ << path << "'"));
+ }
+
+ if (! has_pos)
+ {
+ LLRect rect(target->calcScreenRect());
+ pos.set(rect.getCenterX(), rect.getCenterY());
+ // nonstandard warning tactic: probably usual case; we want event
+ // sender to know synthesized (x, y), but maybe don't need to log?
+ response["warnings"].append(STRINGIZE("using center point ("
+ << pos.mX << ", " << pos.mY << ")"));
+ }
/*==========================================================================*|
- // NEVER MIND: the LLView tree defines priority handler layers in
- // front of the normal widget set, so this has never yet produced
- // anything but spam warnings. (sigh)
-
- // recursive childFromPoint() should give us the frontmost, leafmost
- // widget at the specified (x, y).
- LLView* frontmost = root->childFromPoint(pos.mX, pos.mY, true);
- if (frontmost != target)
- {
- response.warn(STRINGIZE(request["op"].asString() << " request "
- "specified \"path\" = '" << path
- << "', but frontmost LLView at (" << pos.mX << ", " << pos.mY
- << ") is '" << LLView::getPathname(frontmost) << "'"));
- }
+ // NEVER MIND: the LLView tree defines priority handler layers in
+ // front of the normal widget set, so this has never yet produced
+ // anything but spam warnings. (sigh)
+
+ // recursive childFromPoint() should give us the frontmost, leafmost
+ // widget at the specified (x, y).
+ LLView* frontmost = root->childFromPoint(pos.mX, pos.mY, true);
+ if (frontmost != target)
+ {
+ response.warn(STRINGIZE(request["op"].asString() << " request "
+ "specified \"path\" = '" << path
+ << "', but frontmost LLView at (" << pos.mX << ", " << pos.mY
+ << ") is '" << LLView::getPathname(frontmost) << "'"));
+ }
|*==========================================================================*/
- // Instantiate a TemporaryDrilldownFunc to route incoming mouse events
- // to the target LLView*. But put it on the heap since "path" is
- // optional. Nonetheless, manage it with a boost::scoped_ptr so it
- // will be destroyed when we leave.
- tempfunc.reset(new LLView::TemporaryDrilldownFunc(llview::TargetEvent(target)));
- }
-
- // The question of whether the requested LLView actually handled the
- // specified event is important enough, and its handling unclear enough,
- // to warrant a separate response attribute. Instead of deciding here to
- // make it a warning, or an error, let caller decide.
- response["handled"] = func(pos, getMask(request));
-
- // On exiting this scope, response will send, tempfunc will restore the
- // normal pointInView(x, y) containment logic, etc.
+ // Instantiate a TemporaryDrilldownFunc to route incoming mouse events
+ // to the target LLView*. But put it on the heap since "path" is
+ // optional. Nonetheless, manage it with a boost::scoped_ptr so it
+ // will be destroyed when we leave.
+ tempfunc.reset(new LLView::TemporaryDrilldownFunc(llview::TargetEvent(target)));
+ }
+
+ // The question of whether the requested LLView actually handled the
+ // specified event is important enough, and its handling unclear enough,
+ // to warrant a separate response attribute. Instead of deciding here to
+ // make it a warning, or an error, let caller decide.
+ response["handled"] = func(pos, getMask(request));
+
+ // On exiting this scope, response will send, tempfunc will restore the
+ // normal pointInView(x, y) containment logic, etc.
}
void LLWindowListener::mouseDown(LLSD const & request)
{
- Actions actions(buttons.lookup(request["button"]));
- if (actions.valid)
- {
- // Normally you can pass NULL to an LLWindow* without compiler
- // complaint, but going through boost::bind() evidently
- // bypasses that special case: it only knows you're trying to pass an
- // int to a pointer. Explicitly cast NULL to the desired pointer type.
- mouseEvent(boost::bind(actions.down, mWindow,
- static_cast<LLWindow*>(NULL), _1, _2),
- request);
- }
+ Actions actions(buttons.lookup(request["button"]));
+ if (actions.valid)
+ {
+ // Normally you can pass NULL to an LLWindow* without compiler
+ // complaint, but going through boost::bind() evidently
+ // bypasses that special case: it only knows you're trying to pass an
+ // int to a pointer. Explicitly cast NULL to the desired pointer type.
+ mouseEvent(boost::bind(actions.down, mWindow,
+ static_cast<LLWindow*>(NULL), _1, _2),
+ request);
+ }
}
void LLWindowListener::mouseUp(LLSD const & request)
{
- Actions actions(buttons.lookup(request["button"]));
- if (actions.valid)
- {
- mouseEvent(boost::bind(actions.up, mWindow,
- static_cast<LLWindow*>(NULL), _1, _2),
- request);
- }
+ Actions actions(buttons.lookup(request["button"]));
+ if (actions.valid)
+ {
+ mouseEvent(boost::bind(actions.up, mWindow,
+ static_cast<LLWindow*>(NULL), _1, _2),
+ request);
+ }
}
void LLWindowListener::mouseMove(LLSD const & request)
{
- // We want to call the same central mouseEvent() routine for
- // handleMouseMove() as for button clicks. But handleMouseMove() returns
- // void, whereas mouseEvent() accepts a function returning bool -- and
- // uses that bool return. Use MouseFuncTrue to construct a callable that
- // returns bool anyway.
- mouseEvent(MouseFuncTrue(boost::bind(&LLWindowCallbacks::handleMouseMove, mWindow,
- static_cast<LLWindow*>(NULL), _1, _2)),
- request);
+ // We want to call the same central mouseEvent() routine for
+ // handleMouseMove() as for button clicks. But handleMouseMove() returns
+ // void, whereas mouseEvent() accepts a function returning bool -- and
+ // uses that bool return. Use MouseFuncTrue to construct a callable that
+ // returns bool anyway.
+ mouseEvent(MouseFuncTrue(boost::bind(&LLWindowCallbacks::handleMouseMove, mWindow,
+ static_cast<LLWindow*>(NULL), _1, _2)),
+ request);
}
void LLWindowListener::mouseScroll(LLSD const & request)
{
- S32 clicks = request["clicks"].asInteger();
+ S32 clicks = request["clicks"].asInteger();
- mWindow->handleScrollWheel(NULL, clicks);
+ mWindow->handleScrollWheel(NULL, clicks);
}