diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2023-01-25 20:53:01 +0200 |
---|---|---|
committer | akleshchev <117672381+akleshchev@users.noreply.github.com> | 2023-01-27 17:25:18 +0200 |
commit | 2398a28af6f6c225c77b77bef422d1d2dec4a2bb (patch) | |
tree | 518dd7f9e6bb477d74016e8b787594bf9299e9c1 | |
parent | e3a90ba4c1b7fffbb27361155dd67f86097f9a4d (diff) |
SL-18996 [WIP] MacOS make picker dialogs non-modal to avoid disconnects #1
-rw-r--r-- | indra/newview/llfilepicker.cpp | 83 | ||||
-rw-r--r-- | indra/newview/llfilepicker.h | 5 | ||||
-rw-r--r-- | indra/newview/llfilepicker_mac.h | 6 | ||||
-rw-r--r-- | indra/newview/llfilepicker_mac.mm | 68 | ||||
-rw-r--r-- | indra/newview/llviewermenufile.cpp | 73 | ||||
-rw-r--r-- | indra/newview/llviewermenufile.h | 2 |
6 files changed, 220 insertions, 17 deletions
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 3669fb1eeb..06cb78741e 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -678,6 +678,30 @@ bool LLFilePicker::doNavChooseDialog(ELoadFilter filter) return false; } +bool LLFilePicker::doNavChooseDialogModeless(ELoadFilter filter, + void (*callback)(bool, std::vector<std::string> &,void*), + void *userdata) +{ + // if local file browsing is turned off, return without opening dialog + if ( check_local_file_access_enabled() == false ) + { + return false; + } + + gViewerWindow->getWindow()->beforeDialog(); + + std::vector<std::string> *allowed_types=navOpenFilterProc(filter); + + doLoadDialogModeless(allowed_types, + mPickOptions, + callback, + userdata); + + gViewerWindow->getWindow()->afterDialog(); + + return true; +} + bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filename) { @@ -852,18 +876,52 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) 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(); + + mPickOptions &= ~F_MULTIPLE; + mPickOptions |= F_FILE; + + if (filter == FFLOAD_DIRECTORY) //This should only be called from lldirpicker. + { + + mPickOptions |= ( F_NAV_SUPPORT | F_DIRECTORY ); + mPickOptions &= ~F_FILE; + } + + if (filter == FFLOAD_ALL) // allow application bundles etc. to be traversed; important for DEV-16869, but generally useful + { + mPickOptions |= F_NAV_SUPPORT; + } + + return doNavChooseDialogModeless(filter, callback, userdata); +} + 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; } + + BOOL success = FALSE; reset(); @@ -897,6 +955,27 @@ BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking) 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(); + + mPickOptions |= F_FILE; + + mPickOptions |= F_MULTIPLE; + + return doNavChooseDialogModeless(filter, callback, userdata); +} + BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, bool blocking) { diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 04ba4416d7..04adeb8526 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -115,7 +115,11 @@ public: // open the dialog. This is a modal operation BOOL getSaveFile( ESaveFilter filter = FFSAVE_ALL, const std::string& filename = LLStringUtil::null, bool blocking = true); BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); + // Todo: implement getOpenFileModeless and getMultipleOpenFilesModeless + // for windows and use directly instead of ugly LLFilePickerThread + BOOL getOpenFileModeless( ELoadFilter filter, void (*callback)(bool, std::vector<std::string> &, void*), void *userdata); // MAC only. BOOL getMultipleOpenFiles( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); + BOOL getMultipleOpenFilesModeless( ELoadFilter filter, void (*callback)(bool, std::vector<std::string> &, void*), void *userdata ); // MAC only // Get the filename(s) found. getFirstFile() sets the pointer to // the start of the structure and allows the start of iteration. @@ -166,6 +170,7 @@ private: std::vector<std::string> mFileVector; bool doNavChooseDialog(ELoadFilter filter); + bool doNavChooseDialogModeless(ELoadFilter filter, void (*callback)(bool, std::vector<std::string>&, void*), void *userdata); bool doNavSaveDialog(ESaveFilter filter, const std::string& filename); std::vector<std::string>* navOpenFilterProc(ELoadFilter filter); #endif diff --git a/indra/newview/llfilepicker_mac.h b/indra/newview/llfilepicker_mac.h index e0b7e2e8ce..d6b69bb856 100644 --- a/indra/newview/llfilepicker_mac.h +++ b/indra/newview/llfilepicker_mac.h @@ -41,6 +41,12 @@ //void modelessPicker(); std::vector<std::string>* doLoadDialog(const std::vector<std::string>* allowed_types, unsigned int flags); + +void doLoadDialogModeless(const std::vector<std::string>* allowed_types, + unsigned int flags, + void (*callback)(bool, std::vector<std::string>&, void*), + void *userdata); + std::string* doSaveDialog(const std::string* file, const std::string* type, const std::string* creator, diff --git a/indra/newview/llfilepicker_mac.mm b/indra/newview/llfilepicker_mac.mm index 1438e4dc0a..f6892f40fa 100644 --- a/indra/newview/llfilepicker_mac.mm +++ b/indra/newview/llfilepicker_mac.mm @@ -29,27 +29,22 @@ #include <iostream> #include "llfilepicker_mac.h" -std::vector<std::string>* doLoadDialog(const std::vector<std::string>* allowed_types, - unsigned int flags) +NSOpenPanel *init_panel(const std::vector<std::string>* allowed_types, unsigned int flags) { - int i, result; - - //Aura TODO: We could init a small window and release it at the end of this routine - //for a modeless interface. + int i; NSOpenPanel *panel = [NSOpenPanel openPanel]; - //NSString *fileName = nil; NSMutableArray *fileTypes = nil; - if ( allowed_types && !allowed_types->empty()) + if ( allowed_types && !allowed_types->empty()) { fileTypes = [[NSMutableArray alloc] init]; for (i=0;i<allowed_types->size();++i) { - [fileTypes addObject: - [NSString stringWithCString:(*allowed_types)[i].c_str() + [fileTypes addObject: + [NSString stringWithCString:(*allowed_types)[i].c_str() encoding:[NSString defaultCStringEncoding]]]; } } @@ -62,21 +57,30 @@ std::vector<std::string>* doLoadDialog(const std::vector<std::string>* allowed_t [panel setCanChooseFiles: ( (flags & F_FILE)?true:false )]; [panel setTreatsFilePackagesAsDirectories: ( flags & F_NAV_SUPPORT ) ]; - std::vector<std::string>* outfiles = NULL; - if (fileTypes) { [panel setAllowedFileTypes:fileTypes]; - result = [panel runModal]; } - else + else { // I suggest it's better to open the last path and let this default to home dir as necessary // for consistency with other OS X apps // //[panel setDirectoryURL: fileURLWithPath(NSHomeDirectory()) ]; - result = [panel runModal]; } + return panel; +} + +std::vector<std::string>* doLoadDialog(const std::vector<std::string>* allowed_types, + unsigned int flags) +{ + int result; + + NSOpenPanel *panel = init_panel(allowed_types,flags); + + result = [panel runModal]; + + std::vector<std::string>* outfiles = NULL; if (result == NSOKButton) { @@ -97,6 +101,40 @@ std::vector<std::string>* doLoadDialog(const std::vector<std::string>* allowed_t return outfiles; } +void doLoadDialogModeless(const std::vector<std::string>* allowed_types, + unsigned int flags, + void (*callback)(bool, std::vector<std::string> &, void*), + void *userdata) +{ + // Note: might need to return and save this panel + // so that it does not close immediately + NSOpenPanel *panel = init_panel(allowed_types,flags); + + [panel beginWithCompletionHandler:^(NSModalResponse result) + { + if (result == NSOKButton) + { + std::vector<std::string> outfiles; + NSArray *filesToOpen = [panel URLs]; + int i, count = [filesToOpen count]; + + if (count > 0) + { + + for (i=0; i<count; i++) { + NSString *aFile = [[filesToOpen objectAtIndex:i] path]; + std::string *afilestr = new std::string([aFile UTF8String]); + outfiles.push_back(*afilestr); + } + callback(true, outfiles, userdata); + } + else + { + callback(false, outfiles, userdata); + } + } + }]; +} std::string* doSaveDialog(const std::string* file, const std::string* type, diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index fdf1d04c09..259ae7c1fb 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -124,6 +124,16 @@ void LLFilePickerThread::getFile() { #if LL_WINDOWS start(); +#elif LL_DARWIN + if (!mIsSaveDialog) + { + runModeless(); + } + else + { + // Todo: implement Modeless + run(); + } #else run(); #endif @@ -166,7 +176,70 @@ void LLFilePickerThread::run() LLMutexLock lock(sMutex); sDeadQ.push(this); } +} + +void LLFilePickerThread::runModeless() +{ + BOOL result = FALSE; + LLFilePicker picker; + if (mIsSaveDialog) + { + // TODO: not implemented + /*if (picker.getSaveFile(mSaveFilter, mProposedName, blocking)) + { + mResponses.push_back(picker.getFirstFile()); + }*/ + } + else + { + if (mIsGetMultiple) + { + result = picker.getMultipleOpenFilesModeless(mLoadFilter, modelessCallback, this); + } + else + { + result = picker.getOpenFileModeless(mLoadFilter, modelessCallback, this); + } + } + + if (!result) + { + LLMutexLock lock(sMutex); + sDeadQ.push(this); + } +} + +void LLFilePickerThread::modelessCallback(bool result, + std::vector<std::string> &responses, + void *user_data) +{ + LLFilePickerThread *picker = (LLFilePickerThread*)user_data; + if (result) + { + if (picker->mIsGetMultiple) + { + picker->mResponses = responses; + } + else + { + std::vector<std::string>::iterator iter = responses.begin(); + while (iter != responses.end()) + { + if (!iter->empty()) + { + picker->mResponses.push_back(*iter); + break; + } + iter++; + } + } + } + + { + LLMutexLock lock(sMutex); + sDeadQ.push(picker); + } } //static diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index beeac418d9..7cb2cf0d11 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -105,6 +105,8 @@ public: void getFile(); virtual void run(); + void runModeless(); + static void modelessCallback(bool result, std::vector<std::string> &responses, void *user_data); virtual void notify(const std::vector<std::string>& filenames) = 0; }; |