summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/cmake/CMakeLists.txt1
-rw-r--r--indra/cmake/LLWindow.cmake2
-rw-r--r--indra/cmake/NFDE.cmake42
-rw-r--r--indra/cmake/SDL2.cmake7
-rw-r--r--indra/integration_tests/llimage_libtest/CMakeLists.txt2
-rw-r--r--indra/llwindow/llsdl.cpp1
-rw-r--r--indra/llwindow/llwindowsdl.cpp74
-rw-r--r--indra/llwindow/llwindowsdl.h2
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llappviewer.cpp4
-rw-r--r--indra/newview/llappviewerlinux.cpp3
-rw-r--r--indra/newview/lldirpicker.cpp101
-rw-r--r--indra/newview/llfilepicker.cpp918
-rw-r--r--indra/newview/llfilepicker.h12
-rw-r--r--indra/newview/llviewermenufile.cpp6
15 files changed, 627 insertions, 550 deletions
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 9017fc2fb4..9d95a23a59 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -43,6 +43,7 @@ set(cmake_SOURCE_FILES
Lualibs.cmake
Meshoptimizer.cmake
NDOF.cmake
+ NFDE.cmake
OPENAL.cmake
OpenGL.cmake
OpenJPEG.cmake
diff --git a/indra/cmake/LLWindow.cmake b/indra/cmake/LLWindow.cmake
index a5791f1bef..3bdca544ac 100644
--- a/indra/cmake/LLWindow.cmake
+++ b/indra/cmake/LLWindow.cmake
@@ -9,5 +9,5 @@ include_guard()
if (LINUX)
# linux uses SDL2 for window and keyboard
- target_compile_definitions( ll::SDL2 INTERFACE LL_USE_SDL_KEYBOARD=1 )
+ target_compile_definitions( ll::SDL2 INTERFACE LL_USE_SDL_WINDOW=1 LL_USE_SDL_KEYBOARD=1 )
endif (LINUX)
diff --git a/indra/cmake/NFDE.cmake b/indra/cmake/NFDE.cmake
new file mode 100644
index 0000000000..196ba575b2
--- /dev/null
+++ b/indra/cmake/NFDE.cmake
@@ -0,0 +1,42 @@
+# -*- cmake -*-
+if(LINUX)
+ set(USE_NFDE ON CACHE BOOL "Use Native File Dialog wrapper library")
+ set(USE_NFDE_PORTAL ON CACHE BOOL "Use NFDE XDG Portals")
+endif()
+
+include_guard()
+
+add_library(ll::nfde INTERFACE IMPORTED)
+if(USE_NFDE)
+ include(Prebuilt)
+ use_prebuilt_binary(nfde)
+
+ target_compile_definitions( ll::nfde INTERFACE LL_NFD=1)
+
+ if (WINDOWS)
+ target_link_libraries( ll::nfde INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/nfd.lib)
+ elseif (DARWIN)
+ target_link_libraries( ll::nfde INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libnfd.a)
+ elseif (LINUX)
+ if(USE_NFDE_PORTAL)
+ target_link_libraries( ll::nfde INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libnfd_portal.a)
+ else()
+ target_link_libraries( ll::nfde INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libnfd_gtk.a)
+ endif()
+ endif ()
+
+ if (LINUX)
+ find_package(PkgConfig REQUIRED)
+ if(NOT USE_NFDE_PORTAL)
+ pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
+ target_link_libraries(ll::nfde INTERFACE ${GTK3_LINK_LIBRARIES})
+ else()
+ pkg_check_modules(DBUS REQUIRED dbus-1)
+ target_link_libraries(ll::nfde INTERFACE ${DBUS_LINK_LIBRARIES})
+ endif()
+ endif()
+
+ target_include_directories( ll::nfde SYSTEM INTERFACE
+ ${LIBS_PREBUILT_DIR}/include/nfde
+ )
+endif()
diff --git a/indra/cmake/SDL2.cmake b/indra/cmake/SDL2.cmake
index 87195ed108..a464133f3f 100644
--- a/indra/cmake/SDL2.cmake
+++ b/indra/cmake/SDL2.cmake
@@ -12,11 +12,8 @@ use_prebuilt_binary( SDL2 )
find_library( SDL2_LIBRARY
NAMES SDL2
- PATHS "${LIBS_PREBUILT_DIR}/lib/release")
-if ( "${SDL2_LIBRARY}" STREQUAL "SDL2_LIBRARY-NOTFOUND" )
- message( FATAL_ERROR "unable to find SDL2_LIBRARY" )
-endif()
+ PATHS "${LIBS_PREBUILT_DIR}/lib/release" REQUIRED)
target_link_libraries( ll::SDL2 INTERFACE "${SDL2_LIBRARY}" )
-target_include_directories( ll::SDL2 SYSTEM INTERFACE "${LIBS_PREBUILT_DIR}/include" )
+target_include_directories( ll::SDL2 SYSTEM INTERFACE "${LIBS_PREBUILT_DIR}/include/SDL2" )
diff --git a/indra/integration_tests/llimage_libtest/CMakeLists.txt b/indra/integration_tests/llimage_libtest/CMakeLists.txt
index 84d1feb758..e6ff142626 100644
--- a/indra/integration_tests/llimage_libtest/CMakeLists.txt
+++ b/indra/integration_tests/llimage_libtest/CMakeLists.txt
@@ -33,8 +33,6 @@ target_link_libraries(llimage_libtest
llfilesystem
llmath
llimage
- llkdu
- llimagej2coj
)
# Ensure people working on the viewer don't break this library
diff --git a/indra/llwindow/llsdl.cpp b/indra/llwindow/llsdl.cpp
index 3f7992a1d7..6161bd2972 100644
--- a/indra/llwindow/llsdl.cpp
+++ b/indra/llwindow/llsdl.cpp
@@ -56,7 +56,6 @@ void init_sdl()
std::initializer_list<std::tuple< char const*, char const * > > hintList =
{
{SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR,"0"},
- {SDL_HINT_VIDEODRIVER,"wayland,x11"},
{SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH,"1"},
{SDL_HINT_IME_INTERNAL_EDITING,"1"}
};
diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp
index 4793ab4fc7..68704e65bb 100644
--- a/indra/llwindow/llwindowsdl.cpp
+++ b/indra/llwindow/llwindowsdl.cpp
@@ -114,18 +114,6 @@ Display* LLWindowSDL::get_SDL_Display(void)
#include <wayland-client-protocol.h>
#include <dlfcn.h>
-bool LLWindowSDL::isWaylandWindowNotDrawing() const
-{
- if( Wayland != mServerProtocol || mWaylandData.mLastFrameEvent == 0 )
- return false;
-
- auto currentTime = LLTimer::getTotalTime();
- if( (currentTime - mWaylandData.mLastFrameEvent) > 250000 )
- return true;
-
- return false;
-}
-
uint32_t (*ll_wl_proxy_get_version)(struct wl_proxy *proxy);
void (*ll_wl_proxy_destroy)(struct wl_proxy *proxy);
int (*ll_wl_proxy_add_listener)(struct wl_proxy *proxy, void (**implementation)(void), void *data);
@@ -210,8 +198,22 @@ void LLWindowSDL::waylandFrameDoneCB(void *data, struct wl_callback *cb, uint32_
pThis->setupWaylandFrameCallback(); // ask for a new frame
}
+bool LLWindowSDL::isWaylandWindowNotDrawing() const
+{
+ if(!mWaylandLoaded || Wayland != mServerProtocol || mWaylandData.mLastFrameEvent == 0)
+ return false;
+
+ auto currentTime = LLTimer::getTotalTime();
+ if( (currentTime - mWaylandData.mLastFrameEvent) > 250000 )
+ return true;
+
+ return false;
+}
+
void LLWindowSDL::setupWaylandFrameCallback()
{
+ if(!mWaylandLoaded) return;
+
static wl_callback_listener frame_listener { nullptr };
frame_listener.done = &LLWindowSDL::waylandFrameDoneCB;
@@ -403,12 +405,14 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b
if(!mContext)
{
LL_WARNS() << "Cannot create GL context " << SDL_GetError() << LL_ENDL;
+ close();
setupFailure("GL Context creation error", "Error", OSMB_OK);
}
if (SDL_GL_MakeCurrent(mWindow, mContext) != 0)
{
LL_WARNS() << "Failed to make context current. SDL: " << SDL_GetError() << LL_ENDL;
+ close();
setupFailure("GL Context failed to set current failure", "Error", OSMB_OK);
}
@@ -443,14 +447,6 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b
setupFailure( error, "Error", OSMB_OK );
}
}
- else
- {
- if (!mWindow)
- {
- LL_WARNS() << "createContext: window creation failure. SDL: " << SDL_GetError() << LL_ENDL;
- setupFailure("Window creation error", "Error", OSMB_OK);
- }
- }
SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &redBits);
SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &greenBits);
@@ -468,9 +464,6 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b
LL_INFOS() << " Stencil Bits " << S32(stencilBits) << LL_ENDL;
GLint colorBits = redBits + greenBits + blueBits + alphaBits;
- // fixme: actually, it's REALLY important for picking that we get at
- // least 8 bits each of red,green,blue. Alpha we can be a bit more
- // relaxed about if we have to.
if (colorBits < 32)
{
close();
@@ -504,26 +497,26 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b
if ( SDL_GetWindowWMInfo(mWindow, &info) )
{
/* Save the information for later use */
- if ( info.subsystem == SDL_SYSWM_X11 )
+ if (info.subsystem == SDL_SYSWM_X11)
{
- SDL_SetHint(SDL_HINT_VIDEODRIVER, "x11");
mX11Data.mDisplay = info.info.x11.display;
mX11Data.mXWindowID = info.info.x11.window;
mServerProtocol = X11;
LL_INFOS() << "Running under X11" << LL_ENDL;
}
- else if ( info.subsystem == SDL_SYSWM_WAYLAND )
+ else if (info.subsystem == SDL_SYSWM_WAYLAND)
{
#ifdef LL_WAYLAND
- if( !loadWaylandClient() ) {
- SDL_SetHint(SDL_HINT_VIDEODRIVER, "x11");
- LL_ERRS() << "Failed to load wayland-client.so or grab required functions" << LL_ENDL;
- } else {
- SDL_SetHint(SDL_HINT_VIDEODRIVER, "wayland");
+ mWaylandLoaded = loadWaylandClient();
+ if(!mWaylandLoaded)
+ {
+ LL_WARNS() << "Failed to load wayland-client.so or grab required functions" << LL_ENDL;
}
+#endif
mWaylandData.mSurface = info.info.wl.surface;
mServerProtocol = Wayland;
+
setupWaylandFrameCallback();
// If set (XWayland) remove DISPLAY, this will prompt dullahan to also use Wayland
@@ -531,15 +524,11 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b
unsetenv("DISPLAY");
LL_INFOS() << "Running under Wayland" << LL_ENDL;
- LL_WARNS() << "Be aware that with at least SDL2 the window will not receive minimizing events, thus minimized state can only be estimated."
- "also setting the application icon via SDL_SetWindowIcon does not work." << LL_ENDL;
-#else
- setupFailure("Viewer is running under Wayland, but was not compiled with full wayland support!\nYou can compile the viewer with wayland prelimiary support using COMPILE_WAYLAND_SUPPORT", "Error", OSMB_OK);
-#endif
+ LL_WARNS() << "Be aware that with at least SDL2 the window will not receive minimizing events, thus minimized state can only be estimated." << LL_ENDL;
}
else
{
- LL_WARNS() << "We're not running under X11 or Wayland? Wild." << LL_ENDL;
+ LL_WARNS() << "Unsupported windowing system" << LL_ENDL;
}
}
else
@@ -1268,6 +1257,7 @@ U32 LLWindowSDL::SDLCheckGrabbyKeys(U32 keysym, bool gain)
void check_vm_bloat()
{
+#if LL_LINUX
// watch our own VM and RSS sizes, warn if we bloated rapidly
static const std::string STATS_FILE = "/proc/self/stat";
FILE *fp = fopen(STATS_FILE.c_str(), "r");
@@ -1351,6 +1341,7 @@ finally:
free(ptr);
fclose(fp);
}
+#endif
}
@@ -1949,9 +1940,9 @@ void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async)
LL_INFOS() << "spawn_web_browser returning." << LL_ENDL;
}
-void *LLWindowSDL::getPlatformWindow()
+void* LLWindowSDL::getPlatformWindow()
{
- return nullptr;
+ return (void*)mWindow;
}
void LLWindowSDL::bringToFront()
@@ -1968,6 +1959,8 @@ void LLWindowSDL::bringToFront()
//static
std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()
{
+ std::vector<std::string> rtns;
+#if LL_LINUX
// Use libfontconfig to find us a nice ordered list of fallback fonts
// specific to this system.
std::string final_fallback("/usr/share/fonts/truetype/kochi/kochi-gothic.ttf");
@@ -1984,7 +1977,7 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()
// renderable range if for some reason our FreeType actually fails
// to use some of the fonts we want it to.
const bool elide_unicode_coverage = true;
- std::vector<std::string> rtns;
+
FcFontSet *fs = nullptr;
FcPattern *sortpat = nullptr;
@@ -2058,6 +2051,7 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()
LL_INFOS() << "Using " << rtns.size() << "/" << found_font_count << " system fonts." << LL_ENDL;
rtns.push_back(final_fallback);
+#endif
return rtns;
}
diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h
index 974ba69b61..c3b2f32cf7 100644
--- a/indra/llwindow/llwindowsdl.h
+++ b/indra/llwindow/llwindowsdl.h
@@ -254,6 +254,8 @@ private:
uint64_t mLastFrameEvent = 0;
} mWaylandData;
+ bool mWaylandLoaded = false;
+
bool isWaylandWindowNotDrawing() const;
void setupWaylandFrameCallback();
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 3bf01d252d..4d79138aaf 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -30,6 +30,7 @@ include(LLPrimitive)
include(LLWindow)
include(SDL2)
include(NDOF)
+include(NFDE)
include(NVAPI)
include(OPENAL)
include(OpenGL)
@@ -1944,6 +1945,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
ll::ndof
ll::tracy
ll::openxr
+ ll::nfde
)
if( TARGET ll::intel_memops )
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 46681af808..423fe2469a 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -273,10 +273,6 @@ using namespace LL;
// define a self-registering event API object
#include "llappviewerlistener.h"
-#if LL_LINUX && LL_GTK
-#include "glib.h"
-#endif // (LL_LINUX) && LL_GTK
-
static LLAppViewerListener sAppViewerListener(LLAppViewer::instance);
////// Windows-specific includes to the bottom - nasty defines in these pollute the preprocessor
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index 7ce74649e2..3dbbda11f9 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -39,8 +39,9 @@
#include "llfindlocale.h"
#include <exception>
-
+#ifdef LL_GLIB
#include <gio/gio.h>
+#endif
#include <resolv.h>
#if (__GLIBC__*1000 + __GLIBC_MINOR__) >= 2034
diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp
index 17edca7ccb..032433434d 100644
--- a/indra/newview/lldirpicker.cpp
+++ b/indra/newview/lldirpicker.cpp
@@ -45,6 +45,13 @@
#include <shlobj.h>
#endif
+#if LL_NFD
+#include "nfd.hpp"
+#if LL_USE_SDL_WINDOW
+#include "nfd_sdl2.h"
+#endif
+#endif
+
//
// Implementation
//
@@ -65,7 +72,95 @@ bool LLDirPicker::check_local_file_access_enabled()
return true;
}
-#if LL_WINDOWS
+#if LL_NFD
+
+LLDirPicker::LLDirPicker() :
+ mFileName(nullptr),
+ mLocked(false)
+{
+ reset();
+}
+
+LLDirPicker::~LLDirPicker()
+{
+}
+
+
+void LLDirPicker::reset()
+{
+ mDir.clear();
+}
+
+bool LLDirPicker::getDir(std::string* filename, bool blocking)
+{
+ if( mLocked )
+ {
+ return false;
+ }
+
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return false;
+ }
+
+ bool success = false;
+
+ if (blocking)
+ {
+ // Modal, so pause agent
+ send_agent_pause();
+ }
+
+ // initialize NFD
+ NFD::Guard nfdGuard;
+
+ // auto-freeing memory
+ NFD::UniquePath outPath;
+
+ nfdwindowhandle_t windowHandle = nfdwindowhandle_t();
+#if LL_USE_SDL_WINDOW
+ if(!NFD_GetNativeWindowFromSDLWindow((SDL_Window*)gViewerWindow->getPlatformWindow(), &windowHandle))
+ {
+ windowHandle = nfdwindowhandle_t();
+ }
+#elif LL_WINDOWS
+ windowHandle = { NFD_WINDOW_HANDLE_TYPE_WINDOWS, gViewerWindow->getWindow()->getPlatformWindow() };
+#endif
+
+ // show the dialog
+ nfdresult_t result = NFD::PickFolder(outPath, nullptr, windowHandle);
+ if (result == NFD_OKAY)
+ {
+ mDir = std::string(outPath.get());
+ success = true;
+ }
+ else if (result == NFD_CANCEL)
+ {
+ LL_INFOS() << "User pressed cancel." << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS() << "DirPicker Error: " << NFD::GetError() << LL_ENDL;
+ }
+
+ if (blocking)
+ {
+ send_agent_resume();
+
+ // Account for the fact that the app has been stalled.
+ LLFrameTimer::updateFrameTime();
+ }
+
+ return success;
+}
+
+std::string LLDirPicker::getDirName()
+{
+ return mDir;
+}
+
+#elif LL_WINDOWS
LLDirPicker::LLDirPicker() :
mFileName(NULL),
@@ -286,7 +381,7 @@ std::queue<LLDirPickerThread*> LLDirPickerThread::sDeadQ;
void LLDirPickerThread::getFile()
{
-#if LL_WINDOWS
+#if LL_WINDOWS || (LL_NFD && !LL_DARWIN)
start();
#else
run();
@@ -296,7 +391,7 @@ void LLDirPickerThread::getFile()
//virtual
void LLDirPickerThread::run()
{
-#if LL_WINDOWS
+#if LL_WINDOWS || (LL_NFD && !LL_DARWIN)
bool blocking = false;
#else
bool blocking = true; // modal
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 3639064cc4..ca0b58b611 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -36,9 +36,11 @@
#include "llviewercontrol.h"
#include "llwindow.h" // beforeDialog()
-#if LL_LINUX
-#include "llwindowsdl.h" // for some X/GTK utils to help with filepickers
-#include "llhttpconstants.h" // file picker uses some of thes constants on Linux
+#if LL_NFD
+#include "nfd.hpp"
+#if LL_USE_SDL_WINDOW
+#include "nfd_sdl2.h"
+#endif
#endif
//
@@ -80,7 +82,7 @@ LLFilePicker::LLFilePicker()
{
reset();
-#if LL_WINDOWS
+#if LL_WINDOWS && !LL_NFD
mOFN.lStructSize = sizeof(OPENFILENAMEW);
mOFN.hwndOwner = NULL; // Set later
mOFN.hInstance = NULL;
@@ -165,7 +167,431 @@ void LLFilePicker::reset()
mCurrentFile = 0;
}
+#if LL_NFD
+std::vector<nfdfilteritem_t> LLFilePicker::setupFilter(ELoadFilter filter)
+{
+ std::vector<nfdfilteritem_t> filter_vec;
+ switch (filter)
+ {
+ case FFLOAD_EXE:
#if LL_WINDOWS
+ filter_vec.emplace_back(nfdfilteritem_t{"Executables", "exe"});
+#endif
+ break;
+ case FFLOAD_ALL:
+ // Empty to allow picking all files by default
+ break;
+ case FFLOAD_WAV:
+ filter_vec.emplace_back(nfdfilteritem_t{"Sounds", "wav"});
+ break;
+ case FFLOAD_IMAGE:
+ filter_vec.emplace_back(nfdfilteritem_t{"Images", "tga,bmp,jpg,jpeg,png"});
+ break;
+ case FFLOAD_ANIM:
+ filter_vec.emplace_back(nfdfilteritem_t{"Animations", "bvh,anim"});
+ break;
+ case FFLOAD_GLTF:
+ case FFLOAD_MATERIAL:
+ filter_vec.emplace_back(nfdfilteritem_t{"GLTF Files", "gltf,glb"});
+ break;
+ case FFLOAD_COLLADA:
+ filter_vec.emplace_back(nfdfilteritem_t{"Scene", "dae"});
+ break;
+ case FFLOAD_XML:
+ filter_vec.emplace_back(nfdfilteritem_t{"XML files", "xml"});
+ break;
+ case FFLOAD_SLOBJECT:
+ filter_vec.emplace_back(nfdfilteritem_t{"Objects", "slobject"});
+ break;
+ case FFLOAD_RAW:
+ filter_vec.emplace_back(nfdfilteritem_t{"RAW files", "raw"});
+ break;
+ case FFLOAD_MODEL:
+ filter_vec.emplace_back(nfdfilteritem_t{"Model files", "dae"});
+ break;
+ case FFLOAD_HDRI:
+ filter_vec.emplace_back(nfdfilteritem_t{"EXR files", "exr"});
+ break;
+ case FFLOAD_MATERIAL_TEXTURE:
+ filter_vec.emplace_back(nfdfilteritem_t{"GLTF Import", "gltf,glb,tga,bmp,jpg,jpeg,png"});
+ filter_vec.emplace_back(nfdfilteritem_t{"GLTF Files", "gltf,glb"});
+ filter_vec.emplace_back(nfdfilteritem_t{"Images", "tga,bmp,jpg,jpeg,png"});
+ break;
+ case FFLOAD_SCRIPT:
+ filter_vec.emplace_back(nfdfilteritem_t{"Script files (*.lsl)", "lsl"});
+ break;
+ case FFLOAD_DICTIONARY:
+ filter_vec.emplace_back(nfdfilteritem_t{"Dictionary files", "dic,xcu"});
+ break;
+ case FFLOAD_LUA:
+ filter_vec.emplace_back(nfdfilteritem_t{"Script files (*.lua)", "lua"});
+ break;
+ default:
+ break;
+ }
+ return filter_vec;
+}
+
+bool LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking)
+{
+ if( mLocked )
+ {
+ return false;
+ }
+ bool success = false;
+
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return false;
+ }
+
+ // initialize NFD
+ NFD::Guard nfdGuard;
+
+ // auto-freeing memory
+ NFD::UniquePath outPath;
+
+ // prepare filters for the dialog
+ auto filterItem = setupFilter(filter);
+
+ nfdwindowhandle_t windowHandle = nfdwindowhandle_t();
+#if LL_USE_SDL_WINDOW
+ if(!NFD_GetNativeWindowFromSDLWindow((SDL_Window*)gViewerWindow->getPlatformWindow(), &windowHandle))
+ {
+ windowHandle = nfdwindowhandle_t();
+ }
+#elif LL_WINDOWS
+ windowHandle = { NFD_WINDOW_HANDLE_TYPE_WINDOWS, gViewerWindow->getWindow()->getPlatformWindow() };
+#endif
+
+ if (blocking)
+ {
+ // Modal, so pause agent
+ send_agent_pause();
+ }
+
+ reset();
+
+ // show the dialog
+ nfdresult_t result = NFD::OpenDialog(outPath, filterItem.data(), narrow(filterItem.size()), nullptr, windowHandle);
+ if (result == NFD_OKAY)
+ {
+ mFiles.push_back(outPath.get());
+ success = true;
+ }
+
+ if (blocking)
+ {
+ send_agent_resume();
+ // Account for the fact that the app has been stalled.
+ LLFrameTimer::updateFrameTime();
+ }
+
+ return success;
+}
+
+bool LLFilePicker::getOpenFileModeless(ELoadFilter filter,
+ void (*callback)(bool, std::vector<std::string> &, void*),
+ void *userdata)
+{
+ if( mLocked )
+ return false;
+
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return false;
+ }
+
+ reset();
+ LL_WARNS() << "NOT IMPLEMENTED" << LL_ENDL;
+ return false;
+}
+
+bool LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking)
+{
+ if( mLocked )
+ {
+ return false;
+ }
+ bool success = false;
+
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return false;
+ }
+
+ // initialize NFD
+ NFD::Guard nfdGuard;
+
+ auto filterItem = setupFilter(filter);
+
+ reset();
+
+ if (blocking)
+ {
+ // Modal, so pause agent
+ send_agent_pause();
+ }
+
+ nfdwindowhandle_t windowHandle = nfdwindowhandle_t();
+#if LL_USE_SDL_WINDOW
+ if(!NFD_GetNativeWindowFromSDLWindow((SDL_Window*)gViewerWindow->getPlatformWindow(), &windowHandle))
+ {
+ windowHandle = nfdwindowhandle_t();
+ }
+#elif LL_WINDOWS
+ windowHandle = { NFD_WINDOW_HANDLE_TYPE_WINDOWS, gViewerWindow->getWindow()->getPlatformWindow() };
+#endif
+
+ // auto-freeing memory
+ NFD::UniquePathSet outPaths;
+
+ // show the dialog
+ nfdresult_t result = NFD::OpenDialogMultiple(outPaths, filterItem.data(), narrow(filterItem.size()), nullptr, windowHandle);
+ if (result == NFD_OKAY)
+ {
+ LL_INFOS() << "Success!" << LL_ENDL;
+
+ nfdpathsetsize_t numPaths;
+ NFD::PathSet::Count(outPaths, numPaths);
+
+ nfdpathsetsize_t i;
+ for (i = 0; i < numPaths; ++i)
+ {
+ NFD::UniquePathSetPath path;
+ NFD::PathSet::GetPath(outPaths, i, path);
+ mFiles.push_back(path.get());
+ LL_INFOS() << "Path " << i << ": " << path.get() << LL_ENDL;
+ }
+ success = true;
+ }
+ else if (result == NFD_CANCEL)
+ {
+ LL_INFOS() << "User pressed cancel." << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS() << "Error: " << NFD::GetError() << LL_ENDL;
+ }
+
+ if (blocking)
+ {
+ send_agent_resume();
+
+ // Account for the fact that the app has been stalled.
+ LLFrameTimer::updateFrameTime();
+ }
+
+ return success;
+}
+
+bool LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter,
+ void (*callback)(bool, std::vector<std::string> &, void*),
+ void *userdata )
+{
+ if( mLocked )
+ return false;
+
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return false;
+ }
+
+ reset();
+
+ LL_WARNS() << "NOT IMPLEMENTED" << LL_ENDL;
+ return false;
+}
+
+bool LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, bool blocking)
+{
+ if( mLocked )
+ {
+ return false;
+ }
+ bool success = false;
+
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return false;
+ }
+
+ // initialize NFD
+ NFD::Guard nfdGuard;
+
+ std::vector<nfdfilteritem_t> filter_vec;
+ std::string saved_filename = filename;
+ switch( filter )
+ {
+ case FFSAVE_ALL:
+ filter_vec.emplace_back(nfdfilteritem_t{"WAV Sounds", "wav"});
+ filter_vec.emplace_back(nfdfilteritem_t{"Targa, Bitmap Images", "tga,bmp"});
+ break;
+ case FFSAVE_WAV:
+ if (filename.empty())
+ {
+ saved_filename = "untitled.wav";
+ }
+ filter_vec.emplace_back(nfdfilteritem_t{"WAV Sounds", "wav"});
+ break;
+ case FFSAVE_TGA:
+ if (filename.empty())
+ {
+ saved_filename = "untitled.tga";
+ }
+ filter_vec.emplace_back(nfdfilteritem_t{"Targa Images", "tga"});
+ break;
+ case FFSAVE_BMP:
+ if (filename.empty())
+ {
+ saved_filename = "untitled.bmp";
+ }
+ filter_vec.emplace_back(nfdfilteritem_t{"Bitmap Images", "bmp"});
+ break;
+ case FFSAVE_PNG:
+ if (filename.empty())
+ {
+ saved_filename = "untitled.png";
+ }
+ filter_vec.emplace_back(nfdfilteritem_t{"PNG Images", "png"});
+ break;
+ case FFSAVE_TGAPNG:
+ if (filename.empty())
+ {
+ saved_filename = "untitled.png";
+ }
+
+ filter_vec.emplace_back(nfdfilteritem_t{"PNG Images", "png"});
+ filter_vec.emplace_back(nfdfilteritem_t{"Targa Images", "tga"});
+ filter_vec.emplace_back(nfdfilteritem_t{"JPEG Images", "jpg,jpeg"});
+ filter_vec.emplace_back(nfdfilteritem_t{"Jpeg2000 Images", "j2c"});
+ filter_vec.emplace_back(nfdfilteritem_t{"Bitmap Images", "bmp"});
+ break;
+ case FFSAVE_JPEG:
+ if (filename.empty())
+ {
+ saved_filename = "untitled.jpeg";
+ }
+ filter_vec.emplace_back(nfdfilteritem_t{"JPEG Images", "jpg,jpeg"});
+ break;
+ case FFSAVE_AVI:
+ if (filename.empty())
+ {
+ saved_filename = "untitled.avi";
+ }
+ filter_vec.emplace_back(nfdfilteritem_t{"AVI Movie File", "avi"});
+ break;
+ case FFSAVE_ANIM:
+ if (filename.empty())
+ {
+ saved_filename = "untitled.xaf";
+ }
+ filter_vec.emplace_back(nfdfilteritem_t{"XAF Anim File", "xaf"});
+ break;
+ case FFSAVE_XML:
+ if (filename.empty())
+ {
+ saved_filename = "untitled.xml";
+ }
+ filter_vec.emplace_back(nfdfilteritem_t{"XML File", "xml"});
+ break;
+ case FFSAVE_COLLADA:
+ if (filename.empty())
+ {
+ saved_filename = "untitled.collada";
+ }
+ filter_vec.emplace_back(nfdfilteritem_t{"COLLADA File", "collada"});
+ break;
+ case FFSAVE_RAW:
+ if (filename.empty())
+ {
+ saved_filename = "untitled.raw";
+ }
+ filter_vec.emplace_back(nfdfilteritem_t{"RAW files", "raw"});
+ break;
+ case FFSAVE_J2C:
+ if (filename.empty())
+ {
+ saved_filename = "untitled.j2c";
+ }
+ filter_vec.emplace_back(nfdfilteritem_t{"Compressed Images", "j2c"});
+ break;
+ case FFSAVE_SCRIPT:
+ if (filename.empty())
+ {
+ saved_filename = "untitled.lsl";
+ }
+ filter_vec.emplace_back(nfdfilteritem_t{"LSL Files", "lsl"});
+ break;
+ default:
+ return false;
+ }
+
+ nfdwindowhandle_t windowHandle = nfdwindowhandle_t();
+#if LL_USE_SDL_WINDOW
+ if(!NFD_GetNativeWindowFromSDLWindow((SDL_Window*)gViewerWindow->getPlatformWindow(), &windowHandle))
+ {
+ windowHandle = nfdwindowhandle_t();
+ }
+#elif LL_WINDOWS
+ windowHandle = { NFD_WINDOW_HANDLE_TYPE_WINDOWS, gViewerWindow->getWindow()->getPlatformWindow() };
+#endif
+
+ reset();
+
+ if (blocking)
+ {
+ // Modal, so pause agent
+ send_agent_pause();
+ }
+
+ {
+ NFD::UniquePath savePath;
+
+ // show the dialog
+ nfdresult_t result = NFD::SaveDialog(savePath, filter_vec.data(), narrow(filter_vec.size()), nullptr, saved_filename.c_str(), windowHandle);
+ if (result == NFD_OKAY) {
+ mFiles.push_back(savePath.get());
+ success = true;
+ }
+ gKeyboard->resetKeys();
+ }
+
+ if (blocking)
+ {
+ send_agent_resume();
+
+ // Account for the fact that the app has been stalled.
+ LLFrameTimer::updateFrameTime();
+ }
+
+ return success;
+}
+
+bool LLFilePicker::getSaveFileModeless(ESaveFilter filter,
+ const std::string& filename,
+ void (*callback)(bool, std::string&, void*),
+ void *userdata)
+{
+ if( mLocked )
+ return false;
+
+ // if local file browsing is turned off, return without opening dialog
+ if ( check_local_file_access_enabled() == false )
+ {
+ return false;
+ }
+
+ reset();
+ LL_WARNS() << "NOT IMPLEMENTED" << LL_ENDL;
+ return false;
+}
+#elif LL_WINDOWS
bool LLFilePicker::setupFilter(ELoadFilter filter)
{
@@ -1104,488 +1530,6 @@ bool LLFilePicker::getSaveFileModeless(ESaveFilter filter,
#elif LL_LINUX
-# if LL_GTK
-
-// static
-void LLFilePicker::add_to_selectedfiles(gpointer data, gpointer user_data)
-{
- // We need to run g_filename_to_utf8 in the user's locale
- std::string saved_locale(setlocale(LC_ALL, NULL));
- setlocale(LC_ALL, "");
-
- LLFilePicker* picker = (LLFilePicker*) user_data;
- GError *error = NULL;
- gchar* filename_utf8 = g_filename_to_utf8((gchar*)data,
- -1, NULL, NULL, &error);
- if (error)
- {
- // *FIXME.
- // This condition should really be notified to the user, e.g.
- // through a message box. Just logging it is inappropriate.
-
- // g_filename_display_name is ideal, but >= glib 2.6, so:
- // a hand-rolled hacky makeASCII which disallows control chars
- std::string display_name;
- for (const gchar *str = (const gchar *)data; *str; str++)
- {
- display_name += (char)((*str >= 0x20 && *str <= 0x7E) ? *str : '?');
- }
- LL_WARNS() << "g_filename_to_utf8 failed on \"" << display_name << "\": " << error->message << LL_ENDL;
- }
-
- if (filename_utf8)
- {
- picker->mFiles.push_back(std::string(filename_utf8));
- LL_DEBUGS() << "ADDED FILE " << filename_utf8 << LL_ENDL;
- g_free(filename_utf8);
- }
-
- setlocale(LC_ALL, saved_locale.c_str());
-}
-
-// static
-void LLFilePicker::chooser_responder(GtkWidget *widget, gint response, gpointer user_data)
-{
- LLFilePicker* picker = (LLFilePicker*)user_data;
-
- LL_DEBUGS() << "GTK DIALOG RESPONSE " << response << LL_ENDL;
-
- if (response == GTK_RESPONSE_ACCEPT)
- {
- GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
- g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data);
- g_slist_foreach(file_list, (GFunc)g_free, NULL);
- g_slist_free (file_list);
- }
-
- // let's save the extension of the last added file(considering current filter)
- GtkFileFilter *gfilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(widget));
- if(gfilter)
- {
- std::string filter = gtk_file_filter_get_name(gfilter);
-
- if(filter == LLTrans::getString("png_image_files"))
- {
- picker->mCurrentExtension = ".png";
- }
- else if(filter == LLTrans::getString("targa_image_files"))
- {
- picker->mCurrentExtension = ".tga";
- }
- }
-
- // set the default path for this usage context.
- const char* cur_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget));
- if (cur_folder != NULL)
- {
- picker->mContextToPathMap[picker->mCurContextName] = cur_folder;
- }
-
- gtk_widget_destroy(widget);
- gtk_main_quit();
-}
-
-
-GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder, std::string context)
-{
-#ifndef LL_MESA_HEADLESS
- if (LLWindowSDL::ll_try_gtk_init())
- {
- GtkWidget *win = NULL;
- GtkFileChooserAction pickertype =
- is_save?
- (is_folder?
- GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER :
- GTK_FILE_CHOOSER_ACTION_SAVE) :
- (is_folder?
- GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER :
- GTK_FILE_CHOOSER_ACTION_OPEN);
-
- win = gtk_file_chooser_dialog_new(NULL, NULL,
- pickertype,
- GTK_STOCK_CANCEL,
- GTK_RESPONSE_CANCEL,
- is_folder ?
- GTK_STOCK_APPLY :
- (is_save ?
- GTK_STOCK_SAVE :
- GTK_STOCK_OPEN),
- GTK_RESPONSE_ACCEPT,
- (gchar *)NULL);
- mCurContextName = context;
-
- // get the default path for this usage context if it's been
- // seen before.
- std::map<std::string,std::string>::iterator
- this_path = mContextToPathMap.find(context);
- if (this_path != mContextToPathMap.end())
- {
- gtk_file_chooser_set_current_folder
- (GTK_FILE_CHOOSER(win),
- this_path->second.c_str());
- }
-
-# if LL_X11
- // Make GTK tell the window manager to associate this
- // dialog with our non-GTK raw X11 window, which should try
- // to keep it on top etc.
- Window XWindowID = LLWindowSDL::get_SDL_XWindowID();
- if (None != XWindowID)
- {
- gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin
- GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID);
- gdk_window_set_transient_for(GTK_WIDGET(win)->window,
- gdkwin);
- }
- else
- {
- LL_WARNS() << "Hmm, couldn't get xwid to use for transient." << LL_ENDL;
- }
-# endif //LL_X11
-
- g_signal_connect (GTK_FILE_CHOOSER(win),
- "response",
- G_CALLBACK(LLFilePicker::chooser_responder),
- this);
-
- gtk_window_set_modal(GTK_WINDOW(win), TRUE);
-
- /* GTK 2.6: if (is_folder)
- gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win),
- TRUE); */
-
- return GTK_WINDOW(win);
- }
- else
- {
- return NULL;
- }
-#else
- return NULL;
-#endif //LL_MESA_HEADLESS
-}
-
-static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter,
- GtkWindow *picker,
- std::string filtername)
-{
- gtk_file_filter_set_name(gfilter, filtername.c_str());
- gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker),
- gfilter);
- GtkFileFilter *allfilter = gtk_file_filter_new();
- gtk_file_filter_add_pattern(allfilter, "*");
- gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str());
- gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter);
- gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter);
-}
-
-static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker,
- std::string pattern,
- std::string filtername)
-{
- GtkFileFilter *gfilter = gtk_file_filter_new();
- gtk_file_filter_add_pattern(gfilter, pattern.c_str());
- add_common_filters_to_gtkchooser(gfilter, picker, filtername);
- return filtername;
-}
-
-static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker,
- std::string mime,
- std::string filtername)
-{
- GtkFileFilter *gfilter = gtk_file_filter_new();
- gtk_file_filter_add_mime_type(gfilter, mime.c_str());
- add_common_filters_to_gtkchooser(gfilter, picker, filtername);
- return filtername;
-}
-
-static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker)
-{
- return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav",
- LLTrans::getString("sound_files") + " (*.wav)");
-}
-
-static std::string add_anim_filter_to_gtkchooser(GtkWindow *picker)
-{
- GtkFileFilter *gfilter = gtk_file_filter_new();
- gtk_file_filter_add_pattern(gfilter, "*.bvh");
- gtk_file_filter_add_pattern(gfilter, "*.anim");
- std::string filtername = LLTrans::getString("animation_files") + " (*.bvh; *.anim)";
- add_common_filters_to_gtkchooser(gfilter, picker, filtername);
- return filtername;
-}
-
-static std::string add_xml_filter_to_gtkchooser(GtkWindow *picker)
-{
- return add_simple_pattern_filter_to_gtkchooser(picker, "*.xml",
- LLTrans::getString("xml_files") + " (*.xml)");
-}
-
-static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker)
-{
- return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae",
- LLTrans::getString("scene_files") + " (*.dae)");
-}
-
-static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker)
-{
- GtkFileFilter *gfilter = gtk_file_filter_new();
- gtk_file_filter_add_pattern(gfilter, "*.tga");
- gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str());
- gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str());
- gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str());
- std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)";
- add_common_filters_to_gtkchooser(gfilter, picker, filtername);
- return filtername;
-}
-
-static std::string add_script_filter_to_gtkchooser(GtkWindow *picker)
-{
- return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN,
- LLTrans::getString("script_files") + " (*.lsl)");
-}
-
-static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker)
-{
- return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN,
- LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)");
-}
-
-static std::string add_save_texture_filter_to_gtkchooser(GtkWindow *picker)
-{
- GtkFileFilter *gfilter_tga = gtk_file_filter_new();
- GtkFileFilter *gfilter_png = gtk_file_filter_new();
-
- gtk_file_filter_add_pattern(gfilter_tga, "*.tga");
- gtk_file_filter_add_mime_type(gfilter_png, "image/png");
- std::string caption = LLTrans::getString("save_texture_image_files") + " (*.tga; *.png)";
- gtk_file_filter_set_name(gfilter_tga, LLTrans::getString("targa_image_files").c_str());
- gtk_file_filter_set_name(gfilter_png, LLTrans::getString("png_image_files").c_str());
-
- gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker),
- gfilter_png);
- gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker),
- gfilter_tga);
- return caption;
-}
-
-bool LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking )
-{
- bool rtn = false;
-
- // if local file browsing is turned off, return without opening dialog
- if (!check_local_file_access_enabled())
- {
- return false;
- }
-
- gViewerWindow->getWindow()->beforeDialog();
-
- reset();
-
- GtkWindow* picker = buildFilePicker(true, false, "savefile");
-
- if (picker)
- {
- std::string suggest_name = "untitled";
- std::string suggest_ext = "";
- std::string caption = LLTrans::getString("save_file_verb") + " ";
- switch (filter)
- {
- case FFSAVE_WAV:
- caption += add_wav_filter_to_gtkchooser(picker);
- suggest_ext = ".wav";
- break;
- case FFSAVE_TGA:
- caption += add_simple_pattern_filter_to_gtkchooser
- (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)");
- suggest_ext = ".tga";
- break;
- case FFSAVE_BMP:
- caption += add_simple_mime_filter_to_gtkchooser
- (picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)");
- suggest_ext = ".bmp";
- break;
- case FFSAVE_PNG:
- caption += add_simple_mime_filter_to_gtkchooser
- (picker, "image/png", LLTrans::getString("png_image_files") + " (*.png)");
- suggest_ext = ".png";
- break;
- case FFSAVE_TGAPNG:
- caption += add_save_texture_filter_to_gtkchooser(picker);
- suggest_ext = ".png";
- break;
- case FFSAVE_AVI:
- caption += add_simple_mime_filter_to_gtkchooser
- (picker, "video/x-msvideo",
- LLTrans::getString("avi_movie_file") + " (*.avi)");
- suggest_ext = ".avi";
- break;
- case FFSAVE_ANIM:
- caption += add_simple_pattern_filter_to_gtkchooser
- (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)");
- suggest_ext = ".xaf";
- break;
- case FFSAVE_XML:
- caption += add_simple_pattern_filter_to_gtkchooser
- (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)");
- suggest_ext = ".xml";
- break;
- case FFSAVE_RAW:
- caption += add_simple_pattern_filter_to_gtkchooser
- (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)");
- suggest_ext = ".raw";
- break;
- case FFSAVE_J2C:
- // *TODO: Should this be 'image/j2c' ?
- caption += add_simple_mime_filter_to_gtkchooser
- (picker, "images/jp2",
- LLTrans::getString("compressed_image_files") + " (*.j2c)");
- suggest_ext = ".j2c";
- break;
- case FFSAVE_SCRIPT:
- caption += add_script_filter_to_gtkchooser(picker);
- suggest_ext = ".lsl";
- break;
- default:;
- break;
- }
-
- gtk_window_set_title(GTK_WINDOW(picker), caption.c_str());
-
- if (filename.empty())
- {
- suggest_name += suggest_ext;
-
- gtk_file_chooser_set_current_name
- (GTK_FILE_CHOOSER(picker),
- suggest_name.c_str());
- }
- else
- {
- gtk_file_chooser_set_current_name
- (GTK_FILE_CHOOSER(picker), filename.c_str());
- }
-
- gtk_widget_show_all(GTK_WIDGET(picker));
-
- gtk_main();
-
- rtn = (getFileCount() == 1);
-
- if(rtn && filter == FFSAVE_TGAPNG)
- {
- std::string selected_file = mFiles.back();
- mFiles.pop_back();
- mFiles.push_back(selected_file + mCurrentExtension);
- }
- }
-
- gViewerWindow->getWindow()->afterDialog();
-
- return rtn;
-}
-
-bool LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking )
-{
- bool rtn = false;
-
- // if local file browsing is turned off, return without opening dialog
- if (!check_local_file_access_enabled())
- {
- return false;
- }
-
- gViewerWindow->getWindow()->beforeDialog();
-
- reset();
-
- GtkWindow* picker = buildFilePicker(false, false, "openfile");
-
- if (picker)
- {
- std::string caption = LLTrans::getString("load_file_verb") + " ";
- std::string filtername = "";
- switch (filter)
- {
- case FFLOAD_WAV:
- filtername = add_wav_filter_to_gtkchooser(picker);
- break;
- case FFLOAD_ANIM:
- filtername = add_anim_filter_to_gtkchooser(picker);
- break;
- case FFLOAD_XML:
- filtername = add_xml_filter_to_gtkchooser(picker);
- break;
- case FFLOAD_GLTF:
- filtername = dead_code_should_blow_up_here(picker);
- break;
- case FFLOAD_COLLADA:
- filtername = add_collada_filter_to_gtkchooser(picker);
- break;
- case FFLOAD_IMAGE:
- filtername = add_imageload_filter_to_gtkchooser(picker);
- break;
- case FFLOAD_SCRIPT:
- filtername = add_script_filter_to_gtkchooser(picker);
- break;
- case FFLOAD_DICTIONARY:
- filtername = add_dictionary_filter_to_gtkchooser(picker);
- break;
- default:;
- break;
- }
-
- caption += filtername;
-
- gtk_window_set_title(GTK_WINDOW(picker), caption.c_str());
-
- gtk_widget_show_all(GTK_WIDGET(picker));
- gtk_main();
-
- rtn = (getFileCount() == 1);
- }
-
- gViewerWindow->getWindow()->afterDialog();
-
- return rtn;
-}
-
-bool LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking)
-{
- bool rtn = false;
-
- // if local file browsing is turned off, return without opening dialog
- if (!check_local_file_access_enabled())
- {
- return false;
- }
-
- gViewerWindow->getWindow()->beforeDialog();
-
- reset();
-
- GtkWindow* picker = buildFilePicker(false, false, "openfile");
-
- if (picker)
- {
- gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker),
- TRUE);
-
- gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str());
-
- gtk_widget_show_all(GTK_WIDGET(picker));
- gtk_main();
- rtn = !mFiles.empty();
- }
-
- gViewerWindow->getWindow()->afterDialog();
-
- return rtn;
-}
-
-# else // LL_GTK
-
// Hacky stubs designed to facilitate fake getSaveFile and getOpenFile with
// static results, when we don't have a real filepicker.
@@ -1673,8 +1617,6 @@ bool LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter,
return false;
}
-#endif // LL_GTK
-
#else // not implemented
bool LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename )
diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h
index 4d71a3b392..8c89570174 100644
--- a/indra/newview/llfilepicker.h
+++ b/indra/newview/llfilepicker.h
@@ -54,6 +54,10 @@
#include <commdlg.h>
#endif
+#if LL_NFD
+#include "nfd.hpp"
+#endif
+
class LLFilePicker
{
public:
@@ -151,14 +155,18 @@ private:
// is enabled and if not, tidy up and indicate we're not allowed to do this.
bool check_local_file_access_enabled();
-#if LL_WINDOWS
+#if LL_NFD
+ std::vector<nfdfilteritem_t> setupFilter(ELoadFilter filter);
+#endif
+
+#if LL_WINDOWS && !LL_NFD
OPENFILENAMEW mOFN; // for open and save dialogs
WCHAR mFilesW[FILENAME_BUFFER_SIZE];
bool setupFilter(ELoadFilter filter);
#endif
-#if LL_DARWIN
+#if LL_DARWIN && !LL_NFD
S32 mPickOptions;
std::vector<std::string> mFileVector;
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 2a871a24af..14c9c53a9c 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -137,10 +137,10 @@ std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ;
void LLFilePickerThread::getFile()
{
-#if LL_WINDOWS
+#if LL_WINDOWS || (LL_NFD && !LL_DARWIN)
// Todo: get rid of LLFilePickerThread and make this modeless
start();
-#elif LL_DARWIN
+#elif LL_DARWIN && !LL_NFD
runModeless();
#else
run();
@@ -150,7 +150,7 @@ void LLFilePickerThread::getFile()
//virtual
void LLFilePickerThread::run()
{
-#if LL_WINDOWS
+#if LL_WINDOWS || (LL_NFD && !LL_DARWIN)
bool blocking = false;
#else
bool blocking = true; // modal