From 27080dc7f7f9a733706e0d9120b8ed805e8170c8 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 26 Jan 2023 16:58:00 +0200 Subject: SL-18996 make MacOS picker dialogs modeless to avoid disconnects #2 --- indra/newview/llfilepicker.cpp | 284 ++++++++++++++++++++++++------------- indra/newview/llfilepicker.h | 12 +- indra/newview/llfilepicker_mac.h | 8 ++ indra/newview/llfilepicker_mac.mm | 50 ++++++- indra/newview/llviewermenufile.cpp | 53 +++---- indra/newview/llviewermenufile.h | 3 +- 6 files changed, 287 insertions(+), 123 deletions(-) (limited to 'indra') diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 06cb78741e..e6b6c22cc3 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -285,6 +285,15 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) return success; } +BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, + void (*callback)(bool, std::vector &, void*), + void *userdata) +{ + // not supposed to be used yet, use LLFilePickerThread + LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; + return FALSE; +} + BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking) { if( mLocked ) @@ -362,6 +371,15 @@ BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking) return success; } +BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, + void (*callback)(bool, std::vector &, void*), + void *userdata ) +{ + // not supposed to be used yet, use LLFilePickerThread + LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; + return FALSE; +} + BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, bool blocking) { if( mLocked ) @@ -584,6 +602,16 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, return success; } +BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, + const std::string& filename, + void (*callback)(bool, std::string&, void*), + void *userdata) +{ + // not supposed to be used yet, use LLFilePickerThread + LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; + return FALSE; +} + #elif LL_DARWIN std::vector* LLFilePicker::navOpenFilterProc(ELoadFilter filter) //(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode) @@ -688,119 +716,113 @@ bool LLFilePicker::doNavChooseDialogModeless(ELoadFilter filter, return false; } - gViewerWindow->getWindow()->beforeDialog(); - std::vector *allowed_types=navOpenFilterProc(filter); doLoadDialogModeless(allowed_types, mPickOptions, callback, userdata); - - gViewerWindow->getWindow()->afterDialog(); return true; } -bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filename) +void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension, std::string &type, std::string &creator) { - - // Setup the type, creator, and extension - std::string extension, type, creator; - - switch (filter) - { - case FFSAVE_WAV: - type = "WAVE"; - creator = "TVOD"; - extension = "wav"; - break; - case FFSAVE_TGA: - type = "TPIC"; - creator = "prvw"; - extension = "tga"; - break; - case FFSAVE_TGAPNG: - type = "PNG"; - creator = "prvw"; - extension = "png,tga"; - break; - case FFSAVE_BMP: - type = "BMPf"; - creator = "prvw"; - extension = "bmp"; - break; - case FFSAVE_JPEG: - type = "JPEG"; - creator = "prvw"; - extension = "jpeg"; - break; - case FFSAVE_PNG: - type = "PNG "; - creator = "prvw"; - extension = "png"; - break; - case FFSAVE_AVI: - type = "\?\?\?\?"; - creator = "\?\?\?\?"; - extension = "mov"; - break; + switch (filter) + { + case LLFilePicker::FFSAVE_WAV: + type = "WAVE"; + creator = "TVOD"; + extension = "wav"; + break; + case LLFilePicker::FFSAVE_TGA: + type = "TPIC"; + creator = "prvw"; + extension = "tga"; + break; + case LLFilePicker::FFSAVE_TGAPNG: + type = "PNG"; + creator = "prvw"; + extension = "png,tga"; + break; + case LLFilePicker::FFSAVE_BMP: + type = "BMPf"; + creator = "prvw"; + extension = "bmp"; + break; + case LLFilePicker::FFSAVE_JPEG: + type = "JPEG"; + creator = "prvw"; + extension = "jpeg"; + break; + case LLFilePicker::FFSAVE_PNG: + type = "PNG "; + creator = "prvw"; + extension = "png"; + break; + case LLFilePicker::FFSAVE_AVI: + type = "\?\?\?\?"; + creator = "\?\?\?\?"; + extension = "mov"; + break; - case FFSAVE_ANIM: - type = "\?\?\?\?"; - creator = "\?\?\?\?"; - extension = "xaf"; - break; + case LLFilePicker::FFSAVE_ANIM: + type = "\?\?\?\?"; + creator = "\?\?\?\?"; + extension = "xaf"; + break; #ifdef _CORY_TESTING - case FFSAVE_GEOMETRY: - type = "\?\?\?\?"; - creator = "\?\?\?\?"; - extension = "slg"; - break; -#endif - - case FFSAVE_XML: - type = "\?\?\?\?"; - creator = "\?\?\?\?"; - extension = "xml"; - break; - - case FFSAVE_RAW: - type = "\?\?\?\?"; - creator = "\?\?\?\?"; - extension = "raw"; - break; + case LLFilePicker::FFSAVE_GEOMETRY: + type = "\?\?\?\?"; + creator = "\?\?\?\?"; + extension = "slg"; + break; +#endif + + case LLFilePicker::FFSAVE_XML: + type = "\?\?\?\?"; + creator = "\?\?\?\?"; + extension = "xml"; + break; + + case LLFilePicker::FFSAVE_RAW: + type = "\?\?\?\?"; + creator = "\?\?\?\?"; + extension = "raw"; + break; - case FFSAVE_J2C: - type = "\?\?\?\?"; - creator = "prvw"; - extension = "j2c"; - break; - - case FFSAVE_SCRIPT: - type = "LSL "; - creator = "\?\?\?\?"; - extension = "lsl"; - break; - - case FFSAVE_ALL: - default: - type = "\?\?\?\?"; - creator = "\?\?\?\?"; - extension = ""; - break; - } + case LLFilePicker::FFSAVE_J2C: + type = "\?\?\?\?"; + creator = "prvw"; + extension = "j2c"; + break; + + case LLFilePicker::FFSAVE_SCRIPT: + type = "LSL "; + creator = "\?\?\?\?"; + extension = "lsl"; + break; + + case LLFilePicker::FFSAVE_ALL: + default: + type = "\?\?\?\?"; + creator = "\?\?\?\?"; + extension = ""; + break; + } +} + +bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filename) +{ + // Setup the type, creator, and extension + std::string extension, type, creator; + + set_nav_save_data(filter, extension, type, creator); std::string namestring = filename; if (namestring.empty()) namestring="Untitled"; -// if (! boost::algorithm::ends_with(namestring, extension) ) -// { -// namestring = namestring + "." + extension; -// -// } - gViewerWindow->getWindow()->beforeDialog(); // Run the dialog @@ -821,6 +843,30 @@ bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filena return false; } +bool LLFilePicker::doNavSaveDialogModeless(ESaveFilter filter, + const std::string& filename, + void (*callback)(bool, std::string&, void*), + void *userdata) +{ + // Setup the type, creator, and extension + std::string extension, type, creator; + + set_nav_save_data(filter, extension, type, creator); + + std::string namestring = filename; + if (namestring.empty()) namestring="Untitled"; + + // Run the dialog + doSaveDialogModeless(&namestring, + &type, + &creator, + &extension, + mPickOptions, + callback, + userdata); + return true; +} + BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) { if( mLocked ) @@ -956,7 +1002,9 @@ BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter, bool blocking) } -BOOL LLFilePicker::getMultipleOpenFilesModeless( ELoadFilter filter, void (*callback)(bool, std::vector &, void*), void *userdata ) +BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, + void (*callback)(bool, std::vector &, void*), + void *userdata ) { if( mLocked ) return FALSE; @@ -1016,6 +1064,27 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, 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(); + + mPickOptions &= ~F_MULTIPLE; + + return doNavSaveDialogModeless(filter, filename, callback, userdata); +} //END LL_DARWIN #elif LL_LINUX @@ -1523,6 +1592,15 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename return FALSE; } +BOOL LLFilePicker::getSaveFileModeless(ESaveFilter filter, + const std::string& filename, + void (*callback)(bool, std::string&, void*), + void *userdata) +{ + LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; + return FALSE; +} + BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) { // if local file browsing is turned off, return without opening dialog @@ -1548,6 +1626,14 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) return TRUE; } +BOOL LLFilePicker::getOpenFileModeless(ELoadFilter filter, + void (*callback)(bool, std::vector &, void*), + void *userdata) +{ + LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; + return FALSE; +} + BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) { // if local file browsing is turned off, return without opening dialog @@ -1561,6 +1647,14 @@ BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking) return FALSE; } +BOOL LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter, + void (*callback)(bool, std::vector &, void*), + void *userdata ) +{ + LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL; + return FALSE; +} + #endif // LL_GTK #else // not implemented diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 04adeb8526..5e2b7f51f2 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -114,6 +114,10 @@ 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 getSaveFileModeless(ESaveFilter filter, + const std::string& filename, + void (*callback)(bool, std::string&, void*), + void *userdata); BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); // Todo: implement getOpenFileModeless and getMultipleOpenFilesModeless // for windows and use directly instead of ugly LLFilePickerThread @@ -170,9 +174,15 @@ private: std::vector mFileVector; bool doNavChooseDialog(ELoadFilter filter); - bool doNavChooseDialogModeless(ELoadFilter filter, void (*callback)(bool, std::vector&, void*), void *userdata); + bool doNavChooseDialogModeless(ELoadFilter filter, + void (*callback)(bool, std::vector&, void*), + void *userdata); bool doNavSaveDialog(ESaveFilter filter, const std::string& filename); std::vector* navOpenFilterProc(ELoadFilter filter); + bool doNavSaveDialogModeless(ESaveFilter filter, + const std::string& filename, + void (*callback)(bool, std::string&, void*), + void *userdata); #endif #if LL_GTK diff --git a/indra/newview/llfilepicker_mac.h b/indra/newview/llfilepicker_mac.h index d6b69bb856..2ec9d0c4e6 100644 --- a/indra/newview/llfilepicker_mac.h +++ b/indra/newview/llfilepicker_mac.h @@ -52,6 +52,14 @@ std::string* doSaveDialog(const std::string* file, const std::string* creator, const std::string* extension, unsigned int flags); + +void doSaveDialogModeless(const std::string* file, + const std::string* type, + const std::string* creator, + const std::string* extension, + unsigned int flags, + void (*callback)(bool, std::string&, void*), + void *userdata); enum { F_FILE = 0x00000001, F_DIRECTORY = 0x00000002, diff --git a/indra/newview/llfilepicker_mac.mm b/indra/newview/llfilepicker_mac.mm index f6892f40fa..8f5b3030db 100644 --- a/indra/newview/llfilepicker_mac.mm +++ b/indra/newview/llfilepicker_mac.mm @@ -112,9 +112,9 @@ void doLoadDialogModeless(const std::vector* allowed_types, [panel beginWithCompletionHandler:^(NSModalResponse result) { + std::vector outfiles; if (result == NSOKButton) { - std::vector outfiles; NSArray *filesToOpen = [panel URLs]; int i, count = [filesToOpen count]; @@ -128,11 +128,15 @@ void doLoadDialogModeless(const std::vector* allowed_types, } callback(true, outfiles, userdata); } - else + else // no valid result { callback(false, outfiles, userdata); } } + else // cancel + { + callback(false, outfiles, userdata); + } }]; } @@ -168,4 +172,46 @@ std::string* doSaveDialog(const std::string* file, return outfile; } +void doSaveDialogModeless(const std::string* file, + const std::string* type, + const std::string* creator, + const std::string* extension, + unsigned int flags, + void (*callback)(bool, std::string&, void*), + void *userdata) +{ + NSSavePanel *panel = [NSSavePanel savePanel]; + + NSString *extensionns = [NSString stringWithCString:extension->c_str() encoding:[NSString defaultCStringEncoding]]; + NSArray *fileType = [extensionns componentsSeparatedByString:@","]; + + //[panel setMessage:@"Save Image File"]; + [panel setTreatsFilePackagesAsDirectories: ( flags & F_NAV_SUPPORT ) ]; + [panel setCanSelectHiddenExtension:true]; + [panel setAllowedFileTypes:fileType]; + NSString *fileName = [NSString stringWithCString:file->c_str() encoding:[NSString defaultCStringEncoding]]; + + NSURL* url = [NSURL fileURLWithPath:fileName]; + [panel setNameFieldStringValue: fileName]; + [panel setDirectoryURL: url]; + + + [panel beginWithCompletionHandler:^(NSModalResponse result) + { + if (result == NSOKButton) + { + NSURL* url = [panel URL]; + NSString* p = [url path]; + std::string outfile([p UTF8String]); + + callback(true, outfile, userdata); + } + else // cancel + { + std::string outfile; + callback(false, outfile, userdata); + } + }]; +} + #endif diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 259ae7c1fb..27fe7a7018 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -123,17 +123,10 @@ std::queue LLFilePickerThread::sDeadQ; void LLFilePickerThread::getFile() { #if LL_WINDOWS + // Todo: get rid of LLFilePickerThread and make this modeless start(); #elif LL_DARWIN - if (!mIsSaveDialog) - { - runModeless(); - } - else - { - // Todo: implement Modeless - run(); - } + runModeless(); #else run(); #endif @@ -185,22 +178,18 @@ void LLFilePickerThread::runModeless() if (mIsSaveDialog) { - // TODO: not implemented - /*if (picker.getSaveFile(mSaveFilter, mProposedName, blocking)) - { - mResponses.push_back(picker.getFirstFile()); - }*/ + result = picker.getSaveFileModeless(mSaveFilter, + mProposedName, + modelessStringCallback, + this); + } + else if (mIsGetMultiple) + { + result = picker.getMultipleOpenFilesModeless(mLoadFilter, modelessVectorCallback, this); } else { - if (mIsGetMultiple) - { - result = picker.getMultipleOpenFilesModeless(mLoadFilter, modelessCallback, this); - } - else - { - result = picker.getOpenFileModeless(mLoadFilter, modelessCallback, this); - } + result = picker.getOpenFileModeless(mLoadFilter, modelessVectorCallback, this); } if (!result) @@ -210,12 +199,28 @@ void LLFilePickerThread::runModeless() } } -void LLFilePickerThread::modelessCallback(bool result, +void LLFilePickerThread::modelessStringCallback(bool success, + std::string &response, + void *user_data) +{ + LLFilePickerThread *picker = (LLFilePickerThread*)user_data; + if (success) + { + picker->mResponses.push_back(response); + } + + { + LLMutexLock lock(sMutex); + sDeadQ.push(picker); + } +} + +void LLFilePickerThread::modelessVectorCallback(bool success, std::vector &responses, void *user_data) { LLFilePickerThread *picker = (LLFilePickerThread*)user_data; - if (result) + if (success) { if (picker->mIsGetMultiple) { diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 7cb2cf0d11..61572b9996 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -106,7 +106,8 @@ public: virtual void run(); void runModeless(); - static void modelessCallback(bool result, std::vector &responses, void *user_data); + static void modelessStringCallback(bool success, std::string &response, void *user_data); + static void modelessVectorCallback(bool success, std::vector &responses, void *user_data); virtual void notify(const std::vector& filenames) = 0; }; -- cgit v1.2.3