From 96acded5e88d027db3a0517669d48e868d188244 Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Tue, 18 Apr 2023 16:53:10 +0530 Subject: [PATCH 01/10] macOS/QuickLook: support rich thumbnail --- source/blender/blendthumb/CMakeLists.txt | 32 +++++++- source/blender/blendthumb/src/Info.plist | 51 ++++++++++++ ...ThumbnailExtensionMacOS.entitlements.Debug | 12 +++ ...umbnailExtensionMacOS.entitlements.Release | 10 +++ .../blendthumb/src/ThumbnailProvider.h | 13 +++ .../blendthumb/src/ThumbnailProvider.mm | 82 +++++++++++++++++++ source/creator/CMakeLists.txt | 21 ++++- 7 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 source/blender/blendthumb/src/Info.plist create mode 100644 source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Debug create mode 100644 source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Release create mode 100644 source/blender/blendthumb/src/ThumbnailProvider.h create mode 100644 source/blender/blendthumb/src/ThumbnailProvider.mm diff --git a/source/blender/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt index feec85d9056..078ebf0cc50 100644 --- a/source/blender/blendthumb/CMakeLists.txt +++ b/source/blender/blendthumb/CMakeLists.txt @@ -38,8 +38,9 @@ if(WIN32) target_link_libraries(BlendThumb bf_blenlib dbghelp.lib Version.lib) set_target_properties(BlendThumb PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB:msvcrt") +endif() -else() +if(UNIX AND NOT APPLE) # ----------------------------------------------------------------------------- # Build `blender-thumbnailer` executable @@ -54,3 +55,32 @@ else() target_link_libraries(blender-thumbnailer ${PTHREADS_LIBRARIES}) endif() endif() + +if(APPLE) + set(SRC + src/ThumbnailProvider.mm + src/ThumbnailProvider.h + src/Info.plist + ) + + add_executable(blender-thumbnailer MACOSX_BUNDLE ${SRC}) + set_target_properties(blender-thumbnailer PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/src/Info.plist + MACOSX_FRAMEWORK_IDENTIFIER org.blenderfoundation.blender.thumbnailer + ) + set_target_properties(blender-thumbnailer PROPERTIES + BUNDLE_EXTENSION appex + BL_CODESIGN_ENTITLEMENTS_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/src/ThumbnailExtensionMacOS.entitlements.Debug + BL_CODESIGN_ENTITLEMENTS_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/src/ThumbnailExtensionMacOS.entitlements.Release + ) + setup_platform_linker_flags(blender-thumbnailer) + target_link_libraries(blender-thumbnailer + bf_blenlib + # For main function + "-e _NSExtensionMain" + "-framework QuickLookThumbnailing" + ) + if(DEFINED PTHREADS_LIBRARIES) + target_link_libraries(blender-thumbnailer ${PTHREADS_LIBRARIES}) + endif() +endif() \ No newline at end of file diff --git a/source/blender/blendthumb/src/Info.plist b/source/blender/blendthumb/src/Info.plist new file mode 100644 index 00000000000..49a2eef2473 --- /dev/null +++ b/source/blender/blendthumb/src/Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + blender_thumbnailer + CFBundleExecutable + blender-thumbnailer + CFBundleIdentifier + org.blenderfoundation.blender.thumbnailer + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + blender-thumbnailer + CFBundlePackageType + XPC! + CFBundleShortVersionString + + 3.6.0 + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + + 3.6.0 2023-04-18 + LSMinimumSystemVersion + + 10.15 + NSExtension + + NSExtensionAttributes + + QLSupportedContentTypes + + org.blenderfoundation.blender.file + + QLThumbnailMinimumDimension + 10 + + NSExtensionPointIdentifier + com.apple.quicklook.thumbnail + NSExtensionPrincipalClass + ThumbnailProvider + com.apple.showsInExtensionsManager + + + + diff --git a/source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Debug b/source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Debug new file mode 100644 index 00000000000..0aa4c41dd33 --- /dev/null +++ b/source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Debug @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + com.apple.security.get-task-allow + + + diff --git a/source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Release b/source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Release new file mode 100644 index 00000000000..c517feb0cec --- /dev/null +++ b/source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Release @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + + diff --git a/source/blender/blendthumb/src/ThumbnailProvider.h b/source/blender/blendthumb/src/ThumbnailProvider.h new file mode 100644 index 00000000000..5f68588c557 --- /dev/null +++ b/source/blender/blendthumb/src/ThumbnailProvider.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ThumbnailProvider : QLThumbnailProvider + +@end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/source/blender/blendthumb/src/ThumbnailProvider.mm b/source/blender/blendthumb/src/ThumbnailProvider.mm new file mode 100644 index 00000000000..15f62e091fb --- /dev/null +++ b/source/blender/blendthumb/src/ThumbnailProvider.mm @@ -0,0 +1,82 @@ + +#include "ThumbnailProvider.h" + +/** + * This section intends to list the important steps for creating a thumbnail extension. + * qlgenerator has been deprecated. App extensions are the way forward. + * Process goes something like this: + * 1. If an app is launched, or is registered with lsregister, its plugins also get registered. + * 2. When a file thumbnail in Finder or QuickLook is requested, the system looks for a plugin + * that supports the file type UTI. + * 3. The plugin is launched in a sandboxed environment and should call the handler with a reply. + * + * # Plugin Info.plist + * The Info.plist file should contain the following keys: + * + * NSExtensionAttributes + * + * QLSupportedContentTypes + * + * + * org.blenderfoundation.blender.file + * + * QLThumbnailMinimumDimension + * + * 10 + * + * NSExtensionPointIdentifier + * + * com.apple.quicklook.thumbnail + * NSExtensionPrincipalClass + * + * ThumbnailProvider + * + * com.apple.showsInExtensionsManager + * + * + * + * # Codesigning + * - The plugin should be codesigned with entitlements at least for sandbox and read-only/ + * read-write (for access to the given file). + * - com.apple.security.get-task-allow is required for debugging. + * + * # Registering the plugin + * The plugin should be registered with lsregister. Either by calling lsregister or by launching + * the parent app. + * + * # Debugging + * Since read-only entitlement is there, creating files to log is not possible. So NSLOG and + * viewing it in Console.app (after triggering a thumbnail) is the + * way to go. Interesting processes are: qlmanage, quicklookd, kernel, + * blender-thumbnailer, secinitd, com.apple.quicklook.ThumbnailsAgent + * + * LLDB/ Xcode, Other debugging tools can be used to debug the plugin. /usr/bin/qlmanage + * is the target. Other args follow. + * + * # Troubleshooting + * - Sometimes blender-thumbnailer running in background can be killed. + * - qlmanage -r && killall Finder + * + * # Triggering a thumbnail + * - qlmanage -t /path/to/file.blend + * - qlmanage -t -s 512 -o /tmp/ /path/to/file.blend + * + */ + +@implementation ThumbnailProvider + +- (void)provideThumbnailForFileRequest:(QLFileThumbnailRequest *)request + completionHandler:(void (^)(QLThumbnailReply *_Nullable reply, + NSError *_Nullable error))handler +{ + + NSLog(@"hello world from blender"); + NSURL *foo = [[NSURL alloc] initFileURLWithFileSystemRepresentation:"" + isDirectory:NO + relativeToURL:nil]; + QLThumbnailReply *reply = [QLThumbnailReply replyWithImageFileURL:foo]; + + handler(reply, nil); +} + +@end \ No newline at end of file diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 3462fcd5b99..e27deddfa57 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1352,7 +1352,16 @@ elseif(APPLE) if(WITH_BLENDER_THUMBNAILER) install( TARGETS blender-thumbnailer - DESTINATION Blender.app/Contents/MacOS/ + DESTINATION Blender.app/Contents/Plugins + ) + get_target_property(BL_CODESIGN_ENTITLEMENTS_DEBUG blender-thumbnailer BL_CODESIGN_ENTITLEMENTS_DEBUG) + get_target_property(BL_CODESIGN_ENTITLEMENTS_RELEASE blender-thumbnailer BL_CODESIGN_ENTITLEMENTS_RELEASE) + set(BL_CODESIGN_ENTITLEMENTS "$,${BL_CODESIGN_ENTITLEMENTS_DEBUG},${BL_CODESIGN_ENTITLEMENTS_RELEASE}>") + install(CODE + "execute_process(COMMAND codesign + --deep --force --sign - --entitlements \"${BL_CODESIGN_ENTITLEMENTS}\" --timestamp=none + \"${EXECUTABLE_OUTPUT_PATH}/Blender.app/Contents/Plugins/blender-thumbnailer.appex\" + )" ) endif() @@ -1686,6 +1695,16 @@ execute_process(\ endif() endif() +if(APPLE) + # Register with lsregister + install( + CODE " + execute_process(COMMAND /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister + -f -R -trusted + \"${EXECUTABLE_OUTPUT_PATH}/Blender.app\" + )" + ) +endif() # ----------------------------------------------------------------------------- # Post-install script -- 2.30.2 From 0263e6ab40c6a25eca19d5d3a65e1ab95fec93c0 Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Wed, 19 Apr 2023 02:41:35 +0530 Subject: [PATCH 02/10] Fix Code review comments --- .../Contents}/Info.plist | 20 +++---- .../darwin/thumbnail_entitlements.plist | 2 + source/blender/blendthumb/CMakeLists.txt | 12 +---- .../blendthumb/src/ThumbnailProvider.mm | 54 +++++++------------ source/creator/CMakeLists.txt | 24 ++++----- 5 files changed, 45 insertions(+), 67 deletions(-) rename {source/blender/blendthumb/src => release/darwin/Blender.app/Contents/Plugins/blender-thumbnailer.appex/Contents}/Info.plist (75%) rename source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Debug => release/darwin/thumbnail_entitlements.plist (78%) diff --git a/source/blender/blendthumb/src/Info.plist b/release/darwin/Blender.app/Contents/Plugins/blender-thumbnailer.appex/Contents/Info.plist similarity index 75% rename from source/blender/blendthumb/src/Info.plist rename to release/darwin/Blender.app/Contents/Plugins/blender-thumbnailer.appex/Contents/Info.plist index 49a2eef2473..0750a360358 100644 --- a/source/blender/blendthumb/src/Info.plist +++ b/release/darwin/Blender.app/Contents/Plugins/blender-thumbnailer.appex/Contents/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion en + CFBundleName + blender-thumbnailer CFBundleDisplayName blender_thumbnailer CFBundleExecutable @@ -12,22 +14,19 @@ org.blenderfoundation.blender.thumbnailer CFBundleInfoDictionaryVersion 6.0 - CFBundleName - blender-thumbnailer CFBundlePackageType XPC! - CFBundleShortVersionString - - 3.6.0 CFBundleSupportedPlatforms MacOSX + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} CFBundleVersion - - 3.6.0 2023-04-18 + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleGetInfoString + ${MACOSX_BUNDLE_LONG_VERSION_STRING}, Blender Foundation LSMinimumSystemVersion - 10.15 NSExtension @@ -35,15 +34,18 @@ QLSupportedContentTypes + org.blenderfoundation.blender.file QLThumbnailMinimumDimension - 10 + 0 NSExtensionPointIdentifier com.apple.quicklook.thumbnail NSExtensionPrincipalClass + ThumbnailProvider + com.apple.showsInExtensionsManager diff --git a/source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Debug b/release/darwin/thumbnail_entitlements.plist similarity index 78% rename from source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Debug rename to release/darwin/thumbnail_entitlements.plist index 0aa4c41dd33..92479e1d5f9 100644 --- a/source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Debug +++ b/release/darwin/thumbnail_entitlements.plist @@ -2,10 +2,12 @@ + com.apple.security.app-sandbox com.apple.security.files.user-selected.read-only + com.apple.security.get-task-allow diff --git a/source/blender/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt index 078ebf0cc50..e79f5fad024 100644 --- a/source/blender/blendthumb/CMakeLists.txt +++ b/source/blender/blendthumb/CMakeLists.txt @@ -60,23 +60,13 @@ if(APPLE) set(SRC src/ThumbnailProvider.mm src/ThumbnailProvider.h - src/Info.plist ) add_executable(blender-thumbnailer MACOSX_BUNDLE ${SRC}) - set_target_properties(blender-thumbnailer PROPERTIES - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/src/Info.plist - MACOSX_FRAMEWORK_IDENTIFIER org.blenderfoundation.blender.thumbnailer - ) - set_target_properties(blender-thumbnailer PROPERTIES - BUNDLE_EXTENSION appex - BL_CODESIGN_ENTITLEMENTS_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/src/ThumbnailExtensionMacOS.entitlements.Debug - BL_CODESIGN_ENTITLEMENTS_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/src/ThumbnailExtensionMacOS.entitlements.Release - ) setup_platform_linker_flags(blender-thumbnailer) target_link_libraries(blender-thumbnailer bf_blenlib - # For main function + # Avoid linker error about undefined _main symbol. "-e _NSExtensionMain" "-framework QuickLookThumbnailing" ) diff --git a/source/blender/blendthumb/src/ThumbnailProvider.mm b/source/blender/blendthumb/src/ThumbnailProvider.mm index 15f62e091fb..94ae95db1a6 100644 --- a/source/blender/blendthumb/src/ThumbnailProvider.mm +++ b/source/blender/blendthumb/src/ThumbnailProvider.mm @@ -3,64 +3,50 @@ /** * This section intends to list the important steps for creating a thumbnail extension. - * qlgenerator has been deprecated. App extensions are the way forward. - * Process goes something like this: + * qlgenerator has been deprecated and removed in platforms we support. App extensions are the way + * forward. But there's little guidance on how to do it outside Xcode. + * + * The process of thumbnail generation goes something like this: * 1. If an app is launched, or is registered with lsregister, its plugins also get registered. * 2. When a file thumbnail in Finder or QuickLook is requested, the system looks for a plugin * that supports the file type UTI. * 3. The plugin is launched in a sandboxed environment and should call the handler with a reply. * * # Plugin Info.plist - * The Info.plist file should contain the following keys: - * - * NSExtensionAttributes - * - * QLSupportedContentTypes - * - * - * org.blenderfoundation.blender.file - * - * QLThumbnailMinimumDimension - * - * 10 - * - * NSExtensionPointIdentifier - * - * com.apple.quicklook.thumbnail - * NSExtensionPrincipalClass - * - * ThumbnailProvider - * - * com.apple.showsInExtensionsManager - * - * + * The Info.plist file should be properly configured. See the template Info.plist + * under release/darwin for more info. * * # Codesigning - * - The plugin should be codesigned with entitlements at least for sandbox and read-only/ - * read-write (for access to the given file). - * - com.apple.security.get-task-allow is required for debugging. + * The plugin should be codesigned with entitlements at least for sandbox and read-only/ + * read-write (for access to the given file). It's needed even to run the plugin locally. + * com.apple.security.get-task-allow is required for debugging. * * # Registering the plugin * The plugin should be registered with lsregister. Either by calling lsregister or by launching * the parent app. + * /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister * * # Debugging * Since read-only entitlement is there, creating files to log is not possible. So NSLOG and - * viewing it in Console.app (after triggering a thumbnail) is the - * way to go. Interesting processes are: qlmanage, quicklookd, kernel, - * blender-thumbnailer, secinitd, com.apple.quicklook.ThumbnailsAgent + * viewing it in Console.app (after triggering a thumbnail) is the way to go. Interesting processes + * are: qlmanage, quicklookd, kernel, blender-thumbnailer, secinitd, + * com.apple.quicklook.ThumbnailsAgent * - * LLDB/ Xcode, Other debugging tools can be used to debug the plugin. /usr/bin/qlmanage - * is the target. Other args follow. + * LLDB/ Xcode etc., debuggers can be used to get extra logs than CLI invocation but breakpoints + * still are a painpoint. /usr/bin/qlmanage is the target executable. Other args to qlmanage + * follow. * * # Troubleshooting + * - Is it registered with lsregister and there isn't a conflict with another plugin taking + * precendence? + * - Is it codesigned and sandboxed? * - Sometimes blender-thumbnailer running in background can be killed. * - qlmanage -r && killall Finder + * - lsregister -dump | grep Blender.app/ * * # Triggering a thumbnail * - qlmanage -t /path/to/file.blend * - qlmanage -t -s 512 -o /tmp/ /path/to/file.blend - * */ @implementation ThumbnailProvider diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index e27deddfa57..aa7353f0f19 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1317,6 +1317,16 @@ elseif(APPLE) MACOSX_BUNDLE_LONG_VERSION_STRING "${BLENDER_VERSION}.${BLENDER_VERSION_PATCH} ${BLENDER_DATE}" ) + if(WITH_BLENDER_THUMBNAILER) + set(OSX_THUMBNAILER_SOURCEDIR ${OSX_APP_SOURCEDIR}/Contents/PlugIns/blender-thumbnailer.appex) + set_target_properties(blender-thumbnailer PROPERTIES + BUNDLE_EXTENSION appex + MACOSX_BUNDLE_INFO_PLIST ${OSX_THUMBNAILER_SOURCEDIR}/Contents/Info.plist + MACOSX_BUNDLE_SHORT_VERSION_STRING "${BLENDER_VERSION}.${BLENDER_VERSION_PATCH}" + MACOSX_BUNDLE_LONG_VERSION_STRING "${BLENDER_VERSION}.${BLENDER_VERSION_PATCH} ${BLENDER_DATE}" + ) + endif() + # Gather the date in finder-style. execute_process( COMMAND date "+%m/%d/%Y/%H:%M" @@ -1354,9 +1364,7 @@ elseif(APPLE) TARGETS blender-thumbnailer DESTINATION Blender.app/Contents/Plugins ) - get_target_property(BL_CODESIGN_ENTITLEMENTS_DEBUG blender-thumbnailer BL_CODESIGN_ENTITLEMENTS_DEBUG) - get_target_property(BL_CODESIGN_ENTITLEMENTS_RELEASE blender-thumbnailer BL_CODESIGN_ENTITLEMENTS_RELEASE) - set(BL_CODESIGN_ENTITLEMENTS "$,${BL_CODESIGN_ENTITLEMENTS_DEBUG},${BL_CODESIGN_ENTITLEMENTS_RELEASE}>") + set(BL_CODESIGN_ENTITLEMENTS "${OSX_APP_SOURCEDIR}/../thumbnail_entitlements.plist") install(CODE "execute_process(COMMAND codesign --deep --force --sign - --entitlements \"${BL_CODESIGN_ENTITLEMENTS}\" --timestamp=none @@ -1695,16 +1703,6 @@ execute_process(\ endif() endif() -if(APPLE) - # Register with lsregister - install( - CODE " - execute_process(COMMAND /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister - -f -R -trusted - \"${EXECUTABLE_OUTPUT_PATH}/Blender.app\" - )" - ) -endif() # ----------------------------------------------------------------------------- # Post-install script -- 2.30.2 From aafc8e6be098b67b08fabdc36740b9b35fc82f39 Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Wed, 19 Apr 2023 14:27:16 +0530 Subject: [PATCH 03/10] Implement drawing function --- source/blender/blendthumb/CMakeLists.txt | 4 +- .../blendthumb/src/ThumbnailProvider.mm | 111 ++++++++++++++++-- 2 files changed, 103 insertions(+), 12 deletions(-) diff --git a/source/blender/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt index e79f5fad024..3d46f7dffb9 100644 --- a/source/blender/blendthumb/CMakeLists.txt +++ b/source/blender/blendthumb/CMakeLists.txt @@ -57,12 +57,12 @@ if(UNIX AND NOT APPLE) endif() if(APPLE) - set(SRC + set(SRC_APPEX src/ThumbnailProvider.mm src/ThumbnailProvider.h ) - add_executable(blender-thumbnailer MACOSX_BUNDLE ${SRC}) + add_executable(blender-thumbnailer MACOSX_BUNDLE ${SRC} ${SRC_APPEX}) setup_platform_linker_flags(blender-thumbnailer) target_link_libraries(blender-thumbnailer bf_blenlib diff --git a/source/blender/blendthumb/src/ThumbnailProvider.mm b/source/blender/blendthumb/src/ThumbnailProvider.mm index 94ae95db1a6..a7744a66390 100644 --- a/source/blender/blendthumb/src/ThumbnailProvider.mm +++ b/source/blender/blendthumb/src/ThumbnailProvider.mm @@ -1,6 +1,15 @@ #include "ThumbnailProvider.h" +#include +#include +#include +#include + +#include "BLI_fileops.h" +#include "BLI_filereader.h" +#include "blendthumb.hh" + /** * This section intends to list the important steps for creating a thumbnail extension. * qlgenerator has been deprecated and removed in platforms we support. App extensions are the way @@ -38,17 +47,88 @@ * * # Troubleshooting * - Is it registered with lsregister and there isn't a conflict with another plugin taking - * precendence? - * - Is it codesigned and sandboxed? + * precendence? `lsregister -dump | grep Blender.app/` + * - Is it codesigned and sandboxed? `codesign -d --entitlements - /path/to/plugin` * - Sometimes blender-thumbnailer running in background can be killed. * - qlmanage -r && killall Finder - * - lsregister -dump | grep Blender.app/ * * # Triggering a thumbnail * - qlmanage -t /path/to/file.blend * - qlmanage -t -s 512 -o /tmp/ /path/to/file.blend */ +class FileReaderRAII { + int src_file_ = -1; + + public: + explicit FileReaderRAII(int src_file) : src_file_(src_file) {} + ~FileReaderRAII() + { + if (src_file_ != -1) { + close(src_file_); + } + } + + bool good() + { + return src_file_ != -1; + } + + int get() + { + return src_file_; + } +}; + +static NSError *createErrorFromStr(NSString *errorStr) +{ + NSLog(@"Blender Thumbnailer Error: %@", errorStr); + return [NSError errorWithDomain:@"com.blenderfoundation.blender.thumbnailer" + code:-1 + userInfo:@{NSLocalizedDescriptionKey : errorStr}]; +} + +static NSImage *generateNSImageForFile(const char *src_blend_path, NSError **error) +{ + + /* Open source file `src_blend`. */ + FileReaderRAII src_file_fd = FileReaderRAII(BLI_open(src_blend_path, O_BINARY | O_RDONLY, 0)); + if (!src_file_fd.good()) { + *error = createErrorFromStr(@"Failed to open blend"); + return nil; + } + + FileReader *file_content = BLI_filereader_new_file(src_file_fd.get()); + if (file_content == nullptr) { + *error = createErrorFromStr(@"Failed to read from blend"); + return nil; + } + + /* Extract thumbnail from file. */ + Thumbnail thumb; + eThumbStatus err = blendthumb_create_thumb_from_file(file_content, &thumb); + if (err != BT_OK) { + *error = createErrorFromStr(@"Failed to create thumbnail from file"); + return nil; + } + + std::optional> png_buf_opt = blendthumb_create_png_data_from_thumb( + &thumb); + if (!png_buf_opt) { + *error = createErrorFromStr(@"Failed to create png data from thumbnail"); + return nil; + } + NSData *data = [NSData dataWithBytes:png_buf_opt->data() length:png_buf_opt->size()]; + CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data); + CGImageRef image = CGImageCreateWithPNGDataProvider( + provider, nullptr, true, kCGRenderingIntentDefault); + CGDataProviderRelease(provider); + NSImage *uiimage = [[NSImage alloc] initWithCGImage:image size:NSZeroSize]; + CGImageRelease(image); + CGDataProviderRelease(provider); + return uiimage; +} + @implementation ThumbnailProvider - (void)provideThumbnailForFileRequest:(QLFileThumbnailRequest *)request @@ -56,13 +136,24 @@ NSError *_Nullable error))handler { - NSLog(@"hello world from blender"); - NSURL *foo = [[NSURL alloc] initFileURLWithFileSystemRepresentation:"" - isDirectory:NO - relativeToURL:nil]; - QLThumbnailReply *reply = [QLThumbnailReply replyWithImageFileURL:foo]; - - handler(reply, nil); + NSLog(@"Generating thumbnail for %@", request.fileURL.path); + @autoreleasepool { + NSError *error = nil; + NSImage *image = generateNSImageForFile(request.fileURL.path.UTF8String, &error); + if (image == nil) { + handler(nil, error); + return; + } + handler([QLThumbnailReply replyWithContextSize:request.maximumSize + currentContextDrawingBlock:^BOOL { + [image drawInRect:NSMakeRect(0, + 0, + request.maximumSize.width, + request.maximumSize.height)]; + return YES; + }], + nil); + } } @end \ No newline at end of file -- 2.30.2 From abb0b51e1b02637b9336ec46b53d5047b91476d3 Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Wed, 19 Apr 2023 17:55:17 +0530 Subject: [PATCH 04/10] code review --- release/darwin/thumbnail_entitlements.plist | 3 - source/blender/blendthumb/CMakeLists.txt | 38 +++++----- ...umbnailExtensionMacOS.entitlements.Release | 10 --- ...umbnailProvider.h => thumbnail_provider.h} | 3 +- ...bnailProvider.mm => thumbnail_provider.mm} | 72 ++++++++++--------- 5 files changed, 58 insertions(+), 68 deletions(-) delete mode 100644 source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Release rename source/blender/blendthumb/src/{ThumbnailProvider.h => thumbnail_provider.h} (73%) rename source/blender/blendthumb/src/{ThumbnailProvider.mm => thumbnail_provider.mm} (66%) diff --git a/release/darwin/thumbnail_entitlements.plist b/release/darwin/thumbnail_entitlements.plist index 92479e1d5f9..9235bb7442b 100644 --- a/release/darwin/thumbnail_entitlements.plist +++ b/release/darwin/thumbnail_entitlements.plist @@ -7,8 +7,5 @@ com.apple.security.files.user-selected.read-only - - com.apple.security.get-task-allow - diff --git a/source/blender/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt index 3d46f7dffb9..17b574f4fbf 100644 --- a/source/blender/blendthumb/CMakeLists.txt +++ b/source/blender/blendthumb/CMakeLists.txt @@ -38,9 +38,24 @@ if(WIN32) target_link_libraries(BlendThumb bf_blenlib dbghelp.lib Version.lib) set_target_properties(BlendThumb PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB:msvcrt") -endif() -if(UNIX AND NOT APPLE) +elseif(APPLE) + # ----------------------------------------------------------------------------- + # Build `blender-thumbnailer.appex` app extension. + set(SRC_APPEX + src/thumbnail_provider.mm + src/thumbnail_provider.h + ) + + add_executable(blender-thumbnailer MACOSX_BUNDLE ${SRC} ${SRC_APPEX}) + setup_platform_linker_flags(blender-thumbnailer) + target_link_libraries(blender-thumbnailer + bf_blenlib + # Avoid linker error about undefined _main symbol. + "-e _NSExtensionMain" + "-framework QuickLookThumbnailing" + ) +elseif(UNIX) # ----------------------------------------------------------------------------- # Build `blender-thumbnailer` executable @@ -55,22 +70,3 @@ if(UNIX AND NOT APPLE) target_link_libraries(blender-thumbnailer ${PTHREADS_LIBRARIES}) endif() endif() - -if(APPLE) - set(SRC_APPEX - src/ThumbnailProvider.mm - src/ThumbnailProvider.h - ) - - add_executable(blender-thumbnailer MACOSX_BUNDLE ${SRC} ${SRC_APPEX}) - setup_platform_linker_flags(blender-thumbnailer) - target_link_libraries(blender-thumbnailer - bf_blenlib - # Avoid linker error about undefined _main symbol. - "-e _NSExtensionMain" - "-framework QuickLookThumbnailing" - ) - if(DEFINED PTHREADS_LIBRARIES) - target_link_libraries(blender-thumbnailer ${PTHREADS_LIBRARIES}) - endif() -endif() \ No newline at end of file diff --git a/source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Release b/source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Release deleted file mode 100644 index c517feb0cec..00000000000 --- a/source/blender/blendthumb/src/ThumbnailExtensionMacOS.entitlements.Release +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.files.user-selected.read-only - - - diff --git a/source/blender/blendthumb/src/ThumbnailProvider.h b/source/blender/blendthumb/src/thumbnail_provider.h similarity index 73% rename from source/blender/blendthumb/src/ThumbnailProvider.h rename to source/blender/blendthumb/src/thumbnail_provider.h index 5f68588c557..2f3718aa5a2 100644 --- a/source/blender/blendthumb/src/ThumbnailProvider.h +++ b/source/blender/blendthumb/src/thumbnail_provider.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include @@ -10,4 +11,4 @@ NS_ASSUME_NONNULL_BEGIN @end -NS_ASSUME_NONNULL_END \ No newline at end of file +NS_ASSUME_NONNULL_END diff --git a/source/blender/blendthumb/src/ThumbnailProvider.mm b/source/blender/blendthumb/src/thumbnail_provider.mm similarity index 66% rename from source/blender/blendthumb/src/ThumbnailProvider.mm rename to source/blender/blendthumb/src/thumbnail_provider.mm index a7744a66390..63623710544 100644 --- a/source/blender/blendthumb/src/ThumbnailProvider.mm +++ b/source/blender/blendthumb/src/thumbnail_provider.mm @@ -1,5 +1,4 @@ - -#include "ThumbnailProvider.h" +/* SPDX-License-Identifier: GPL-2.0-or-later */ #include #include @@ -8,8 +7,10 @@ #include "BLI_fileops.h" #include "BLI_filereader.h" +#include "BLI_utility_mixins.hh" #include "blendthumb.hh" +#include "thumbnail_provider.h" /** * This section intends to list the important steps for creating a thumbnail extension. * qlgenerator has been deprecated and removed in platforms we support. App extensions are the way @@ -36,18 +37,18 @@ * /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister * * # Debugging - * Since read-only entitlement is there, creating files to log is not possible. So NSLOG and + * Since read-only entitlement is there, creating files to log is not possible. So NSLog and * viewing it in Console.app (after triggering a thumbnail) is the way to go. Interesting processes * are: qlmanage, quicklookd, kernel, blender-thumbnailer, secinitd, * com.apple.quicklook.ThumbnailsAgent * * LLDB/ Xcode etc., debuggers can be used to get extra logs than CLI invocation but breakpoints - * still are a painpoint. /usr/bin/qlmanage is the target executable. Other args to qlmanage + * still are a pain point. /usr/bin/qlmanage is the target executable. Other args to qlmanage * follow. * * # Troubleshooting * - Is it registered with lsregister and there isn't a conflict with another plugin taking - * precendence? `lsregister -dump | grep Blender.app/` + * precedence? `lsregister -dump | grep Blender.app/` * - Is it codesigned and sandboxed? `codesign -d --entitlements - /path/to/plugin` * - Sometimes blender-thumbnailer running in background can be killed. * - qlmanage -r && killall Finder @@ -57,14 +58,18 @@ * - qlmanage -t -s 512 -o /tmp/ /path/to/file.blend */ -class FileReaderRAII { +class FileDescriptorRAII : blender::NonCopyable, blender::NonMovable { int src_file_ = -1; public: - explicit FileReaderRAII(int src_file) : src_file_(src_file) {} - ~FileReaderRAII() + explicit FileDescriptorRAII(const char *file_path) { - if (src_file_ != -1) { + src_file_ = BLI_open(file_path, O_BINARY | O_RDONLY, 0); + } + + ~FileDescriptorRAII() + { + if (good()) { close(src_file_); } } @@ -80,27 +85,26 @@ class FileReaderRAII { } }; -static NSError *createErrorFromStr(NSString *errorStr) +static NSError *create_nserror_from_string(NSString *errorStr) { NSLog(@"Blender Thumbnailer Error: %@", errorStr); - return [NSError errorWithDomain:@"com.blenderfoundation.blender.thumbnailer" + return [NSError errorWithDomain:@"org.blenderfoundation.blender.thumbnailer" code:-1 userInfo:@{NSLocalizedDescriptionKey : errorStr}]; } -static NSImage *generateNSImageForFile(const char *src_blend_path, NSError **error) +static NSImage *generate_nsimage_for_file(const char *src_blend_path, NSError **error) { - /* Open source file `src_blend`. */ - FileReaderRAII src_file_fd = FileReaderRAII(BLI_open(src_blend_path, O_BINARY | O_RDONLY, 0)); + FileDescriptorRAII src_file_fd = FileDescriptorRAII(src_blend_path); if (!src_file_fd.good()) { - *error = createErrorFromStr(@"Failed to open blend"); + *error = create_nserror_from_string(@"Failed to open blend"); return nil; } FileReader *file_content = BLI_filereader_new_file(src_file_fd.get()); if (file_content == nullptr) { - *error = createErrorFromStr(@"Failed to read from blend"); + *error = create_nserror_from_string(@"Failed to read from blend"); return nil; } @@ -108,25 +112,27 @@ static NSImage *generateNSImageForFile(const char *src_blend_path, NSError **err Thumbnail thumb; eThumbStatus err = blendthumb_create_thumb_from_file(file_content, &thumb); if (err != BT_OK) { - *error = createErrorFromStr(@"Failed to create thumbnail from file"); + *error = create_nserror_from_string(@"Failed to create thumbnail from file"); return nil; } std::optional> png_buf_opt = blendthumb_create_png_data_from_thumb( &thumb); if (!png_buf_opt) { - *error = createErrorFromStr(@"Failed to create png data from thumbnail"); + *error = create_nserror_from_string(@"Failed to create png data from thumbnail"); return nil; } - NSData *data = [NSData dataWithBytes:png_buf_opt->data() length:png_buf_opt->size()]; - CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data); - CGImageRef image = CGImageCreateWithPNGDataProvider( - provider, nullptr, true, kCGRenderingIntentDefault); + NSData *ns_data = [NSData dataWithBytesNoCopy:png_buf_opt->data() length:png_buf_opt->size()]; + CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)ns_data); + CGColorRenderingIntent intent = kCGRenderingIntentDefault; + bool shouldInterpolate = true; + CGFloat *decode = nullptr; + CGImageRef image_ref = CGImageCreateWithPNGDataProvider( + provider, decode, shouldInterpolate, intent); + NSImage *ns_image = [[NSImage alloc] initWithCGImage:image_ref size:NSZeroSize]; + CGImageRelease(image_ref); CGDataProviderRelease(provider); - NSImage *uiimage = [[NSImage alloc] initWithCGImage:image size:NSZeroSize]; - CGImageRelease(image); - CGDataProviderRelease(provider); - return uiimage; + return ns_image; } @implementation ThumbnailProvider @@ -139,21 +145,21 @@ static NSImage *generateNSImageForFile(const char *src_blend_path, NSError **err NSLog(@"Generating thumbnail for %@", request.fileURL.path); @autoreleasepool { NSError *error = nil; - NSImage *image = generateNSImageForFile(request.fileURL.path.UTF8String, &error); - if (image == nil) { + NSImage *ns_image = generate_nsimage_for_file(request.fileURL.path.UTF8String, &error); + if (ns_image == nil) { handler(nil, error); return; } handler([QLThumbnailReply replyWithContextSize:request.maximumSize currentContextDrawingBlock:^BOOL { - [image drawInRect:NSMakeRect(0, - 0, - request.maximumSize.width, - request.maximumSize.height)]; + [ns_image drawInRect:NSMakeRect(0, + 0, + request.maximumSize.width, + request.maximumSize.height)]; return YES; }], nil); } } -@end \ No newline at end of file +@end -- 2.30.2 From acaa6d1d9a8926646e5513f970dfa8dab646398a Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Wed, 19 Apr 2023 18:25:22 +0530 Subject: [PATCH 05/10] Fix crash added in last commit --- source/blender/blendthumb/src/thumbnail_provider.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blendthumb/src/thumbnail_provider.mm b/source/blender/blendthumb/src/thumbnail_provider.mm index 63623710544..2965cb52f83 100644 --- a/source/blender/blendthumb/src/thumbnail_provider.mm +++ b/source/blender/blendthumb/src/thumbnail_provider.mm @@ -122,7 +122,7 @@ static NSImage *generate_nsimage_for_file(const char *src_blend_path, NSError ** *error = create_nserror_from_string(@"Failed to create png data from thumbnail"); return nil; } - NSData *ns_data = [NSData dataWithBytesNoCopy:png_buf_opt->data() length:png_buf_opt->size()]; + NSData *ns_data = [NSData dataWithBytes:png_buf_opt->data() length:png_buf_opt->size()]; CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)ns_data); CGColorRenderingIntent intent = kCGRenderingIntentDefault; bool shouldInterpolate = true; -- 2.30.2 From a4f987cb66b00599e39023a75052087bfb151092 Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Thu, 20 Apr 2023 01:08:10 +0530 Subject: [PATCH 06/10] snake_case --- source/blender/blendthumb/src/thumbnail_provider.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/blendthumb/src/thumbnail_provider.mm b/source/blender/blendthumb/src/thumbnail_provider.mm index 2965cb52f83..8103b4127ea 100644 --- a/source/blender/blendthumb/src/thumbnail_provider.mm +++ b/source/blender/blendthumb/src/thumbnail_provider.mm @@ -125,10 +125,10 @@ static NSImage *generate_nsimage_for_file(const char *src_blend_path, NSError ** NSData *ns_data = [NSData dataWithBytes:png_buf_opt->data() length:png_buf_opt->size()]; CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)ns_data); CGColorRenderingIntent intent = kCGRenderingIntentDefault; - bool shouldInterpolate = true; + bool should_interpolate = true; CGFloat *decode = nullptr; CGImageRef image_ref = CGImageCreateWithPNGDataProvider( - provider, decode, shouldInterpolate, intent); + provider, decode, should_interpolate, intent); NSImage *ns_image = [[NSImage alloc] initWithCGImage:image_ref size:NSZeroSize]; CGImageRelease(image_ref); CGDataProviderRelease(provider); -- 2.30.2 From 9ecdf8a3f7f422069ea10ba479a6c67e8c48cd2b Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Thu, 20 Apr 2023 18:36:42 +0200 Subject: [PATCH 07/10] Remove show in system preferences --- .../Plugins/blender-thumbnailer.appex/Contents/Info.plist | 3 --- 1 file changed, 3 deletions(-) diff --git a/release/darwin/Blender.app/Contents/Plugins/blender-thumbnailer.appex/Contents/Info.plist b/release/darwin/Blender.app/Contents/Plugins/blender-thumbnailer.appex/Contents/Info.plist index 0750a360358..9243cedd20c 100644 --- a/release/darwin/Blender.app/Contents/Plugins/blender-thumbnailer.appex/Contents/Info.plist +++ b/release/darwin/Blender.app/Contents/Plugins/blender-thumbnailer.appex/Contents/Info.plist @@ -45,9 +45,6 @@ NSExtensionPrincipalClass ThumbnailProvider - - com.apple.showsInExtensionsManager - -- 2.30.2 From 987d0dffbdc91aaefba3ec2ee8954818cb79a96e Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Thu, 20 Apr 2023 19:47:00 +0200 Subject: [PATCH 08/10] clarify troubleshooting --- source/blender/blendthumb/src/thumbnail_provider.mm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/blender/blendthumb/src/thumbnail_provider.mm b/source/blender/blendthumb/src/thumbnail_provider.mm index 8103b4127ea..a228b38e712 100644 --- a/source/blender/blendthumb/src/thumbnail_provider.mm +++ b/source/blender/blendthumb/src/thumbnail_provider.mm @@ -48,10 +48,12 @@ * * # Troubleshooting * - Is it registered with lsregister and there isn't a conflict with another plugin taking - * precedence? `lsregister -dump | grep Blender.app/` - * - Is it codesigned and sandboxed? `codesign -d --entitlements - /path/to/plugin` + * precedence? `lsregister -dump | grep blender-thumbnailer.appex` + * - Is it codesigned and sandboxed? + * `codesign -d --entitlements ent.plist -f -s - /path/to/appex` * - Sometimes blender-thumbnailer running in background can be killed. * - qlmanage -r && killall Finder + * - The code cannot attempt to do anything outside sandbox like writing to blend. * * # Triggering a thumbnail * - qlmanage -t /path/to/file.blend -- 2.30.2 From bf23dd632d944f9958d9811071e7968b01116466 Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Sun, 23 Apr 2023 07:36:04 +0200 Subject: [PATCH 09/10] tab to space --- release/darwin/thumbnail_entitlements.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/darwin/thumbnail_entitlements.plist b/release/darwin/thumbnail_entitlements.plist index 9235bb7442b..5401397cffb 100644 --- a/release/darwin/thumbnail_entitlements.plist +++ b/release/darwin/thumbnail_entitlements.plist @@ -6,6 +6,6 @@ com.apple.security.app-sandbox com.apple.security.files.user-selected.read-only - + -- 2.30.2 From 4f1171df41cbd39e4a5c0001ab117f293eda68b2 Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Sun, 23 Apr 2023 07:39:39 +0200 Subject: [PATCH 10/10] rename var --- source/creator/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index aa7353f0f19..25ad8b119b3 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1364,10 +1364,10 @@ elseif(APPLE) TARGETS blender-thumbnailer DESTINATION Blender.app/Contents/Plugins ) - set(BL_CODESIGN_ENTITLEMENTS "${OSX_APP_SOURCEDIR}/../thumbnail_entitlements.plist") + set(THUMBNAIL_ENTITLEMENTS "${CMAKE_SOURCE_DIR}/release/darwin/thumbnail_entitlements.plist") install(CODE "execute_process(COMMAND codesign - --deep --force --sign - --entitlements \"${BL_CODESIGN_ENTITLEMENTS}\" --timestamp=none + --deep --force --sign - --entitlements \"${THUMBNAIL_ENTITLEMENTS}\" --timestamp=none \"${EXECUTABLE_OUTPUT_PATH}/Blender.app/Contents/Plugins/blender-thumbnailer.appex\" )" ) -- 2.30.2