summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornat-goodspeed <nat@lindenlab.com>2024-04-03 16:00:03 -0400
committerGitHub <noreply@github.com>2024-04-03 16:00:03 -0400
commitd2ed30f82367ae875d2b894e55118867e40239e9 (patch)
treebff58971c931f71002986dc2d240afb7c8a9daf9
parentf069543328efc441673db9877c97ae2201b86e91 (diff)
parentb351888ed7d395279dfc022363e911d52ebdcc16 (diff)
Merge pull request #1101 from secondlife/lua-scripts-floater
Lua scripts floater
-rw-r--r--indra/llwindow/llwindow.h2
-rw-r--r--indra/llwindow/llwindowmacosx-objc.h2
-rw-r--r--indra/llwindow/llwindowmacosx-objc.mm7
-rw-r--r--indra/llwindow/llwindowmacosx.cpp5
-rw-r--r--indra/llwindow/llwindowmacosx.h2
-rw-r--r--indra/llwindow/llwindowwin32.cpp37
-rw-r--r--indra/llwindow/llwindowwin32.h2
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llfloaterluascripts.cpp120
-rw-r--r--indra/newview/llfloaterluascripts.h55
-rw-r--r--indra/newview/llluamanager.cpp3
-rw-r--r--indra/newview/llluamanager.h21
-rw-r--r--indra/newview/llviewerfloaterreg.cpp2
-rw-r--r--indra/newview/skins/default/xui/en/floater_lua_scripts.xml36
-rw-r--r--indra/newview/skins/default/xui/en/menu_lua_scripts.xml11
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml10
16 files changed, 302 insertions, 15 deletions
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index f435d46584..9e9e424455 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -187,6 +187,8 @@ public:
virtual void interruptLanguageTextInput() {}
virtual void spawnWebBrowser(const std::string& escaped_url, bool async) {};
+ virtual void openFolder(const std::string &path) {};
+
static std::vector<std::string> getDynamicFallbackFontList();
// Provide native key event data
diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h
index 77024d3a9c..ade303c6d4 100644
--- a/indra/llwindow/llwindowmacosx-objc.h
+++ b/indra/llwindow/llwindowmacosx-objc.h
@@ -177,6 +177,8 @@ void setMarkedText(unsigned short *text, unsigned int *selectedRange, unsigned i
void getPreeditLocation(float *location, unsigned int length);
void allowDirectMarkedTextInput(bool allow, GLViewRef glView);
+void openFolderWithFinder(const char *folder_path);
+
NSWindowRef getMainAppWindow();
GLViewRef getGLView();
diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm
index 690fe058db..56d1798dcf 100644
--- a/indra/llwindow/llwindowmacosx-objc.mm
+++ b/indra/llwindow/llwindowmacosx-objc.mm
@@ -462,6 +462,13 @@ long showAlert(std::string text, std::string title, int type)
return ret;
}
+void openFolderWithFinder(const char *folder_path)
+{
+ @autoreleasepool {
+ NSString *folderPathString = [NSString stringWithUTF8String:folder_path];
+ [[NSWorkspace sharedWorkspace] openFile:folderPathString withApplication:@"Finder"];
+ }
+}
/*
GLViewRef getGLView()
{
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 778e5d3898..b774597eb6 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -2076,6 +2076,11 @@ F32 LLWindowMacOSX::getSystemUISize()
return gHiDPISupport ? ::getDeviceUnitSize(mGLView) : LLWindow::getSystemUISize();
}
+void LLWindowMacOSX::openFolder(const std::string &path)
+{
+ openFolderWithFinder(path.c_str());
+}
+
#if LL_OS_DRAGDROP_ENABLED
/*
S16 LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow,
diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h
index 7614167213..5f728fb72e 100644
--- a/indra/llwindow/llwindowmacosx.h
+++ b/indra/llwindow/llwindowmacosx.h
@@ -116,6 +116,8 @@ public:
void spawnWebBrowser(const std::string& escaped_url, bool async) override;
F32 getSystemUISize() override;
+ void openFolder(const std::string &path) override;
+
static std::vector<std::string> getDisplaysResolutionList();
static std::vector<std::string> getDynamicFallbackFontList();
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 057d7a700e..7fbc2c8ea2 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -3755,6 +3755,23 @@ S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 t
return retval;
}
+void shell_open(const std::string &file, bool async)
+{
+ std::wstring url_utf16 = ll_convert(file);
+
+ // let the OS decide what to use to open the URL
+ SHELLEXECUTEINFO sei = {sizeof(sei)};
+ // NOTE: this assumes that SL will stick around long enough to complete the DDE message exchange
+ // necessary for ShellExecuteEx to complete
+ if (async)
+ {
+ sei.fMask = SEE_MASK_ASYNCOK;
+ }
+ sei.nShow = SW_SHOWNORMAL;
+ sei.lpVerb = L"open";
+ sei.lpFile = url_utf16.c_str();
+ ShellExecuteEx(&sei);
+}
void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url, bool async)
{
@@ -3780,22 +3797,12 @@ void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url, bool async)
// replaced ShellExecute code with ShellExecuteEx since ShellExecute doesn't work
// reliablly on Vista.
- // this is madness.. no, this is..
- LLWString url_wstring = utf8str_to_wstring( escaped_url );
- llutf16string url_utf16 = wstring_to_utf16str( url_wstring );
+ shell_open(escaped_url, async);
+}
- // let the OS decide what to use to open the URL
- SHELLEXECUTEINFO sei = { sizeof( sei ) };
- // NOTE: this assumes that SL will stick around long enough to complete the DDE message exchange
- // necessary for ShellExecuteEx to complete
- if (async)
- {
- sei.fMask = SEE_MASK_ASYNCOK;
- }
- sei.nShow = SW_SHOWNORMAL;
- sei.lpVerb = L"open";
- sei.lpFile = url_utf16.c_str();
- ShellExecuteEx( &sei );
+void LLWindowWin32::openFolder(const std::string &path)
+{
+ shell_open(path, false);
}
/*
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index ff287a140e..320c1c8b88 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -122,6 +122,8 @@ public:
/*virtual*/ void interruptLanguageTextInput();
/*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async);
+ void openFolder(const std::string &path) override;
+
/*virtual*/ F32 getSystemUISize();
LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url );
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index b26ce7d06d..f41e481b26 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -243,6 +243,7 @@ set(viewer_SOURCE_FILES
llfloaterlinkreplace.cpp
llfloaterloadprefpreset.cpp
llfloaterluadebug.cpp
+ llfloaterluascripts.cpp
llfloatermarketplacelistings.cpp
llfloatermap.cpp
llfloatermediasettings.cpp
@@ -901,6 +902,7 @@ set(viewer_HEADER_FILES
llfloaterlinkreplace.h
llfloaterloadprefpreset.h
llfloaterluadebug.h
+ llfloaterluascripts.h
llfloatermap.h
llfloatermarketplacelistings.h
llfloatermediasettings.h
diff --git a/indra/newview/llfloaterluascripts.cpp b/indra/newview/llfloaterluascripts.cpp
new file mode 100644
index 0000000000..bd845a97d6
--- /dev/null
+++ b/indra/newview/llfloaterluascripts.cpp
@@ -0,0 +1,120 @@
+/**
+ * @file llfloaterluascriptsinfo.cpp
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterluascripts.h"
+#include "llevents.h"
+#include <filesystem>
+#include "llluamanager.h"
+#include "llscrolllistctrl.h"
+#include "llviewerwindow.h"
+#include "llwindow.h"
+#include "llviewermenu.h"
+
+const F32 REFRESH_INTERVAL = 1.0f;
+
+LLFloaterLUAScripts::LLFloaterLUAScripts(const LLSD &key)
+ : LLFloater(key),
+ mUpdateTimer(new LLTimer()),
+ mContextMenuHandle()
+{
+ mCommitCallbackRegistrar.add("Script.OpenFolder", [this](LLUICtrl*, const LLSD &userdata)
+ {
+ gViewerWindow->getWindow()->openFolder(mTargetFolderPath);
+ });
+}
+
+
+BOOL LLFloaterLUAScripts::postBuild()
+{
+ mScriptList = getChild<LLScrollListCtrl>("scripts_list");
+ mScriptList->setRightMouseDownCallback([this](LLUICtrl *ctrl, S32 x, S32 y, MASK mask) { onScrollListRightClicked(ctrl, x, y);});
+
+ LLContextMenu *menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
+ "menu_lua_scripts.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ if (menu)
+ {
+ mContextMenuHandle = menu->getHandle();
+ }
+
+ return TRUE;
+}
+
+LLFloaterLUAScripts::~LLFloaterLUAScripts()
+{
+ auto menu = mContextMenuHandle.get();
+ if (menu)
+ {
+ menu->die();
+ mContextMenuHandle.markDead();
+ }
+}
+
+void LLFloaterLUAScripts::draw()
+{
+ if (mUpdateTimer->checkExpirationAndReset(REFRESH_INTERVAL))
+ {
+ populateScriptList();
+ }
+ LLFloater::draw();
+}
+
+void LLFloaterLUAScripts::populateScriptList()
+{
+ S32 prev_pos = mScriptList->getScrollPos();
+ LLSD prev_selected = mScriptList->getSelectedValue();
+ mScriptList->clearRows();
+ mScriptList->updateColumns(true);
+ std::map<std::string, std::string> scripts = LLLUAmanager::getScriptNames();
+ for (auto &it : scripts)
+ {
+ LLSD row;
+ row["value"] = it.first;
+ row["columns"][0]["value"] = std::filesystem::path((it.second)).stem().string();
+ row["columns"][0]["column"] = "script_name";
+ row["columns"][1]["value"] = it.second;
+ row["columns"][1]["column"] = "script_path";
+ mScriptList->addElement(row);
+ }
+ mScriptList->setScrollPos(prev_pos);
+ mScriptList->setSelectedByValue(prev_selected, true);
+}
+
+void LLFloaterLUAScripts::onScrollListRightClicked(LLUICtrl *ctrl, S32 x, S32 y)
+{
+ LLScrollListItem *item = mScriptList->hitItem(x, y);
+ if (item)
+ {
+ mScriptList->selectItemAt(x, y, MASK_NONE);
+ auto menu = mContextMenuHandle.get();
+ if (menu)
+ {
+ mTargetFolderPath = std::filesystem::path((item->getColumn(1)->getValue().asString())).parent_path().string();
+ menu->show(x, y);
+ LLMenuGL::showPopup(this, menu, x, y);
+ }
+ }
+}
diff --git a/indra/newview/llfloaterluascripts.h b/indra/newview/llfloaterluascripts.h
new file mode 100644
index 0000000000..548bbd10f6
--- /dev/null
+++ b/indra/newview/llfloaterluascripts.h
@@ -0,0 +1,55 @@
+/**
+ * @file llfloaterluascriptsinfo.h
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, 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_LLFLOATERLUASCRIPTS_H
+#define LL_LLFLOATERLUASCRIPTS_H
+
+#include "llfloater.h"
+
+class LLScrollListCtrl;
+
+class LLFloaterLUAScripts :
+ public LLFloater
+{
+ public:
+ LLFloaterLUAScripts(const LLSD &key);
+ virtual ~LLFloaterLUAScripts();
+
+ BOOL postBuild();
+ void draw();
+
+private:
+ void populateScriptList();
+ void onScrollListRightClicked(LLUICtrl *ctrl, S32 x, S32 y);
+
+ std::unique_ptr<LLTimer> mUpdateTimer;
+ LLScrollListCtrl* mScriptList;
+ std::string mTargetFolderPath;
+
+ LLHandle<LLContextMenu> mContextMenuHandle;
+};
+
+#endif // LL_LLFLOATERLUASCRIPTS_H
+
diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp
index 82be85a153..1d55313813 100644
--- a/indra/newview/llluamanager.cpp
+++ b/indra/newview/llluamanager.cpp
@@ -48,6 +48,8 @@
#include <string_view>
#include <vector>
+std::map<std::string, std::string> LLLUAmanager::sScriptNames;
+
lua_function(sleep, "sleep(seconds): pause the running coroutine")
{
F32 seconds = lua_tonumber(L, -1);
@@ -177,6 +179,7 @@ void LLLUAmanager::runScriptFile(const std::string &filename, script_result_fn r
// A script_result_fn will be called when LuaState::expr() completes.
LLCoros::instance().launch(filename, [filename, result_cb, finished_cb]()
{
+ ScriptObserver observer(LLCoros::getName(), filename);
llifstream in_file;
in_file.open(filename.c_str());
diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h
index 3c00450179..fe4db22fca 100644
--- a/indra/newview/llluamanager.h
+++ b/indra/newview/llluamanager.h
@@ -41,6 +41,8 @@ class LuaState;
class LLLUAmanager
{
+ friend class ScriptObserver;
+
public:
// Pass a callback with this signature to obtain the error message, if
// any, from running a script or source string. Empty msg means success.
@@ -81,6 +83,11 @@ public:
static std::pair<int, LLSD> waitScriptLine(LuaState& L, const std::string& chunk);
static void runScriptOnLogin();
+
+ static const std::map<std::string, std::string> getScriptNames() { return sScriptNames; }
+
+ private:
+ static std::map<std::string, std::string> sScriptNames;
};
class LLRequireResolver
@@ -100,4 +107,18 @@ class LLRequireResolver
bool findModuleImpl(const std::string& absolutePath);
void runModule(const std::string& desc, const std::string& code);
};
+
+// RAII class to guarantee that a script entry is erased even when coro is terminated
+class ScriptObserver
+{
+ public:
+ ScriptObserver(const std::string &coro_name, const std::string &filename) : mCoroName(coro_name)
+ {
+ LLLUAmanager::sScriptNames[mCoroName] = filename;
+ }
+ ~ScriptObserver() { LLLUAmanager::sScriptNames.erase(mCoroName); }
+
+ private:
+ std::string mCoroName;
+};
#endif
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index f72ef71241..de328639f8 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -94,6 +94,7 @@
#include "llfloaterlinkreplace.h"
#include "llfloaterloadprefpreset.h"
#include "llfloaterluadebug.h"
+#include "llfloaterluascripts.h"
#include "llfloatermap.h"
#include "llfloatermarketplacelistings.h"
#include "llfloatermediasettings.h"
@@ -402,6 +403,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("load_pref_preset", "floater_load_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLoadPrefPreset>);
LLFloaterReg::add("lua_debug", "floater_lua_debug.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterLUADebug>);
+ LLFloaterReg::add("lua_scripts", "floater_lua_scripts.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterLUAScripts>);
LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMemLeak>);
diff --git a/indra/newview/skins/default/xui/en/floater_lua_scripts.xml b/indra/newview/skins/default/xui/en/floater_lua_scripts.xml
new file mode 100644
index 0000000000..6859201650
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_lua_scripts.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_minimize="false"
+ can_resize="true"
+ can_close="true"
+ bevel_style="in"
+ height="220"
+ min_height="220"
+ layout="topleft"
+ name="LUA scripts"
+ save_rect="true"
+ title="LUA Scripts"
+ single_instance="true"
+ width="555"
+ min_width="555">
+ <scroll_list
+ column_padding="0"
+ draw_stripes="true"
+ draw_heading="true"
+ height="200"
+ left="10"
+ follows="all"
+ layout="topleft"
+ sort_column="script_name"
+ name="scripts_list"
+ top_pad="10"
+ width="535">
+ <scroll_list.columns
+ label="Name"
+ name="script_name"
+ width="180" />
+ <scroll_list.columns
+ label="Path"
+ name="script_path"/>
+ </scroll_list>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_lua_scripts.xml b/indra/newview/skins/default/xui/en/menu_lua_scripts.xml
new file mode 100644
index 0000000000..8f718abe17
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_lua_scripts.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ name="Scripts">
+ <menu_item_call
+ label="Open Containing Folder"
+ layout="topleft"
+ name="open_folder">
+ <menu_item_call.on_click
+ function="Script.OpenFolder" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index b259b101b4..40f5c40dfe 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2539,6 +2539,16 @@ function="World.EnvPreset"
function="Floater.Toggle"
parameter="lua_debug" />
</menu_item_check>
+ <menu_item_check
+ label="LUA Scripts Info"
+ name="LUA Scripts">
+ <menu_item_check.on_check
+ function="Floater.Visible"
+ parameter="lua_scripts" />
+ <menu_item_check.on_click
+ function="Floater.Toggle"
+ parameter="lua_scripts" />
+ </menu_item_check>
<menu_item_separator/>
<menu_item_call