macOS/QuickLook: support rich thumbnail #107072

Open
Ankit Meel wants to merge 10 commits from ankitm/blender:ankitm/2ql into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
5 changed files with 45 additions and 67 deletions
Showing only changes of commit 0263e6ab40 - Show all commits

View File

@ -4,6 +4,8 @@
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleName</key>
<string>blender-thumbnailer</string>
<key>CFBundleDisplayName</key>
<string>blender_thumbnailer</string>
<key>CFBundleExecutable</key>
@ -12,22 +14,19 @@
<string>org.blenderfoundation.blender.thumbnailer</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>blender-thumbnailer</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<!-- TODO automate -->
<string>3.6.0</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleVersion</key>
<!-- TODO automate -->
<string>3.6.0 2023-04-18</string>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}, Blender Foundation</string>
<key>LSMinimumSystemVersion</key>
<!-- TODO automate -->
<string>10.15</string>
<key>NSExtension</key>
<dict>
@ -35,15 +34,18 @@
<dict>
<key>QLSupportedContentTypes</key>
<array>
<!-- The supported file UTIs. Not inherited from parent bundle. -->
<string>org.blenderfoundation.blender.file</string>
</array>
<key>QLThumbnailMinimumDimension</key>
<integer>10</integer>
<integer>0</integer>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.quicklook.thumbnail</string>
<key>NSExtensionPrincipalClass</key>
<!-- Must be the same as the class implementing the reply method. -->
<string>ThumbnailProvider</string>
<!-- Shows checkbox in System Preferences. -->

Is this required, and common for these kinds of thumbnails generators? I don't see it for any other apps, but maybe I just happen to not have any apps that do this.

Is this required, and common for these kinds of thumbnails generators? I don't see it for any other apps, but maybe I just happen to not have any apps that do this.

Not required and not sure about commonness. But since there's no other way to disable it, I added it.

I could remove the key from plist and let the system decide.

Not required and not sure about commonness. But since there's no other way to disable it, I added it. I could remove the key from plist and let the system decide.

I'd leave it out and let the system decide.

I'd leave it out and let the system decide.
<key>com.apple.showsInExtensionsManager</key>
<true/>
</dict>

View File

@ -2,10 +2,12 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- Extension must be codesigned even locally. -->
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
ankitm marked this conversation as resolved Outdated

Inconsistent indentation.

Inconsistent indentation.
<!-- Is needed for debugging the process -->
<key>com.apple.security.get-task-allow</key>
<true/>
</dict>

View File

@ -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"
)

View File

@ -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
ankitm marked this conversation as resolved Outdated

Add newline before this.

Add newline before this.
* 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:
* <dict>
* <key>NSExtensionAttributes</key>
* <dict>
* <key>QLSupportedContentTypes</key>
* <array>
* <!-- Exactly the file UTIs to be supported. Not inherited from parent bundle. -->
* <string>org.blenderfoundation.blender.file</string>
* </array>
* <key>QLThumbnailMinimumDimension</key>
* <!-- To be explored the impact of. -->
* <integer>10</integer>
* </dict>
* <key>NSExtensionPointIdentifier</key>
* <!--com.apple.quicklook.thumbnail for preview extensions -->
* <string>com.apple.quicklook.thumbnail</string>
* <key>NSExtensionPrincipalClass</key>
* <!-- Must be the same as in the code. -->
* <string>ThumbnailProvider</string>
* <!-- Shows checkbox in System Preferences. -->
* <key>com.apple.showsInExtensionsManager</key>
* <true/>
* </dict>
* 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

View File

@ -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 "$<IF:$<CONFIG:Debug>,${BL_CODESIGN_ENTITLEMENTS_DEBUG},${BL_CODESIGN_ENTITLEMENTS_RELEASE}>")
set(BL_CODESIGN_ENTITLEMENTS "${OSX_APP_SOURCEDIR}/../thumbnail_entitlements.plist")
ankitm marked this conversation as resolved Outdated

Not using relative path is more clear I think, their relative location has no particular importance: ${CMAKE_SOURCE_DIR}/release/darwin/thumbnail_entitlements.plist.

Don't invent new BL_ prefix for variable names, suggest to use THUMBNAIL_ENTITLEMENTS

Not using relative path is more clear I think, their relative location has no particular importance: `${CMAKE_SOURCE_DIR}/release/darwin/thumbnail_entitlements.plist`. Don't invent new `BL_` prefix for variable names, suggest to use `THUMBNAIL_ENTITLEMENTS`
install(CODE

Does this now run on every make install? That would slow down incremental builds. Is there a way to make it run only when the appex is updated?

Does this now run on every `make install`? That would slow down incremental builds. Is there a way to make it run only when the appex is updated?
Review
time codesign --entitlements release/darwin/thumbnail_entitlements.plist --force --deep --sign - ../build_darwin_debug_lite/bin/Blender.app/Contents/Plugins/blender-thumbnailer.appex
../build_darwin_debug_lite/bin/Blender.app/Contents/Plugins/blender-thumbnailer.appex: replacing existing signature
codesign --entitlements release/darwin/thumbnail_entitlements.plist --force    0.02s user 0.02s system 72% cpu 0.053 total

insignificant
Even my poor machine makes it unnoticeable. We aren't signing the full blender.app.

``` time codesign --entitlements release/darwin/thumbnail_entitlements.plist --force --deep --sign - ../build_darwin_debug_lite/bin/Blender.app/Contents/Plugins/blender-thumbnailer.appex ../build_darwin_debug_lite/bin/Blender.app/Contents/Plugins/blender-thumbnailer.appex: replacing existing signature codesign --entitlements release/darwin/thumbnail_entitlements.plist --force 0.02s user 0.02s system 72% cpu 0.053 total ``` insignificant Even my poor machine makes it unnoticeable. We aren't signing the full blender.app.
"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