InDesign SDK  20.5
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Porting Guide

What's New in the InDesign Plug-In SDK

HFS Action Items for Developers and Partners

As you may be aware, HFS (Hierarchical File System) paths have been deprecated by Apple (since Mac OS 10.0-10.9). Considering this deprecation, InDesign would also move away from HFS and adopt POSIX style paths going forward. (Please refer to the subsection below for details on the differences between HFS and POSIX.)

For a smooth transitioning period and to support the backward compatibility of plugins, refer to the public APIs mentioned here: https://forums.adobeprerelease.com/indesigndev/discussion/407/hfs-action-items-for-developers-and-partners

Action to be taken:

Remove the use of any hard-coded path delimiter, such as ':', ":", or kTextChar_Colon, etc., as a path separator. Instead, query it from APIs exposed in the FileUtils class as per the need.

Kindly go through all hard coded file/folder paths in your code and let us know if these APIs would aid in the smooth working of your plugins with both HFS & POSIX Path Style.

Quick comparison between HFS and POSIX

HFS (Hierarchical File System) POSIX (Portable Operating System Interface)
a. Developed by Apple a. Open-source (IEEE Computer Society standard)
b. Uses colon(:) as a separator to separate paths b. Uses forward slash (/) as a separator to separate paths
c. Case insensitive c. Case sensitive
d. Absolute path doesn't start with separator d. Absolute path starts with separator
e. Example: "Macintosh HD:Users:Username:Documents:File.txt" e. Example: "/home/user/Documents/file.txt"

InDesign is adopting the POSIX Path Style with the InDesign 20.0 release. Users and plug-in developers would not have the ability to switch between HFS and POSIX Style as cookie "ENABLE_POSIX_PATH" is removed.

API removal update

The public API FileUtils::IDFileToPMString(const IDFile& file, PMString& pathStr, bool16 isPosixPath) has been deprecated as POSIX is the only path style.

The alternative for the removed API is FileUtils::IDFileToPMString(const IDFile& file, PMString& pathStr). Plug-in developers are suggested to make changes to avoid getting a compile time error. Functionality of this API is same as the deprecated API when parameter "bool16 isPosixPath" is set as true.

Boost upgraded to version 1.74

There are updates in our internal platform components. As part of this, we have upgraded the boost from 1.72 to 1.74. This boost upgrade has breaking changes. To review the changes across different boost versions, please refer to the following boost release notes:

Xcode base SDK and deployment target

InDesign now uses MacOSX12.x.sdk as the Base SDK, OSX 12.x as the OS X Deployment Target, GNU C++-17 as the C++ Language Dialect, and libc++.dylib as the C++ Standard Library for Xcode projects. If your projects don't use the SDK shared Xcode setting files, you will need to update these settings manually.

Other project changes to note

  1. In common.xcconfig, CLANG_CXX_LANGUAGE_STANDARD has been set to gnu++17 i.e., the code is compiled as GNU C++-17 compliant.
  2. BOOST_SPIRIT_THREADSAFE has been defined centrally in common.xcconfig.
  3. ALWAYS_SEARCH_USER_PATHS has been set to NO in common.xcconfig. You may need to change #include statements that were using user search path files but with syntax "#include <some-file>" and replace them with syntax "#include "<some-header-file>"". This change is being done proactively as the setting ALWAYS_SEARCH_USER_PATHS is deprecated in future versions of Xcode.
  4. When you open SDK-plugins in Xcode 15.2, you might get the warning "Update to recommended settings". Either you can simply ignore this warning, or if you want to fix this, follow the below steps - a. Click on "Update to recommended settings" -> Click on "Perform Changes". b. Go to project Build Settings -> Apple Clang - Warnings - All languages -> Set "Implicit Conversion to 32 Bit Type" to No.

System Requirements

  • For Windows development, Windows 7 SP1 is the minimum requirement.
  • For Mac x86_64 development, Mac OS 13.5 or later is now required (Xcode 15.2 requires this).
  • For Mac arm64 development, Mac OS 13.5 or later is now required (Xcode 15.2 requires this).

IDE Requirements

Visual Studio version is Visual Studio 2022 (v17.9.6).

When installing Visual Studio 2022, please ensure that Windows SDK 10.0.22621.0 is also installed as this is used as the base SDK for InDesign projects. Also, please add a system environment variable called VS2022INSTALLDIR and set it to the path of the VS 2022 installation folder, upto the parent folder of folders "Common7", "VC" etc. For example, if you installed Visual Studio 2022 Enterprise edition, the value of VS2022INSTALLDIR should be C:\Program Files (x86\Microsoft Visual Studio\2022\Enterprise.

To update an existing Visual Studio project, the simplest method is to open the project in Visual Studio 2022 and use the prompt to update the project. In this window, please modify Windows SDK Version to 10.0.22621.0 and Platform Toolset to v143.

Alternatively you can modify the project file in a text editor by changing the ToolsVersion to 17.9.6 and PlatformToolset version to v143 and adding a new entry WindowsTargetPlatformVersion as 10.0.22621.0, as shown below.

<Project DefaultTargets="Build" ToolsVersion="17.9.6" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>

Dolly has been updated to generate new projects with these settings.

Other project changes to note

  1. In previous releases, all projects inherited a setting /Zc:sizedDealloc- from Base.props. This setting has now been removed.
  2. In Base.props, LanguageStandard has been set to stdcpp14 i.e. the code is compiled as C++-17 compliant.
  3. BOOST_SPIRIT_THREADSAFE has been defined centrally in Base.props.

IntelliSense

IntelliSense has never worked very well for InDesign code, and you may find that IntelliSense red squiggles appear under nearly every InDesign type or API, despite your project compiling successfully.

To disable the squiggles:

  1. Go to Tools > Options.
  2. In the options dialog, in the left pane, expand "Text Editor" and then expand "C/C++".
  3. Click on "Advanced" under "C/C++".
  4. In the right pane, scroll down until you see the "IntelliSense" section.
  5. Select "Disable Squiggles" and change its value to True.
  6. Click OK.

std::auto_ptr removal

With InDesign 17.0 SDK, in an effort to move away from std::auto_ptr and adapt higher C++ standards (i.e. C++17), we have removed std::auto_ptr usage from InDesign.

The new SDK and shared samples will expect you to use indesign::autoptr instead of std::auto_ptr.

Here are a few reasons for this.

  1. This is a drop-in replacement over older auto_ptr so should not cause any runtime changes.
  2. The implementation is aliased to std::shared_ptr. This allows us to do another iteration in future with certainty that complete cleanup of autoptr will not cause runtime issues.
  3. It is easier to adopt in a larger codebase without manual efforts in short term.

While doing this change, we have kept in mind that the interface signatures do not change unless change gets us closer to the goal of getting rid of autoptr constructs eventually. This implies that at a few places you may have to directly replae std::auto_ptr with std::unique_ptr or std::shared_ptr. This would be directly available in the API headers as to what is the altername of the std::auto_ptr in new SDK.

If you are not able to find the definition of indesign::autoptr, the header file containing this should be in /source/public/includes/... Calling out a few things explicitly:

  1. No, we are not moving to C++17 (yet.) If that is going to happen, We will post that information to you as soon as we can.
  2. Yes, we have just aliased the indesign::autoptr to std::shared_ptr.

API changes

For a full list of API changes see the API Changes page.

Multi-cycle effort to modernize InDesign native containers (since InDesign CC 2018)

While InDesign code base is built using C++-11 now, the code does not fully leverage modern STL containers and therefore loses out on newer features introduced in C++-11. We intend to modernize our containers over multiple cycles to be able to leverage these features.

The approach to modernization would be to ideally replace our containers with corresponding STL containers. For example, over time, K2Vector should be replaced by std::vector.

To facilitate the eventual K2Vector migration, following changes would be made to the K2Vector interface in InDesign CC 2018:

K2Vector non-standard constructor removal

K2Vector has a non-standard explicit constructor which takes 'size_type n' as parameter and reserves capacity for 'n' elements, but does not construct any elements so its size remains zero. STL's std::vector has a constructor with similar signature but actually constructs 'n' elements thereby resulting in a vector of size 'n'. Replacing K2Vector with std::vector without addressing this constructor would result in potential breaks in code that is using this K2Vector constructor. Therefore we intend to remove this constructor in InDesign CC 2018, so that existing code can be ported before the switch from K2Vector to std::vector happens. Code that uses this constructor can be ported as follows:

Current code (assuming a typename T):

K2Vector<T> var(10);

New code:

var.reserve(10);

K2Vector deprecated API "Location" removal

K2Vector's Location API has been marked deprecated for several cycles now. This API returns a value of type 'int32'. If the element being searched for is found in the K2Vector, then the return value is the index at which this value was found. Otherwise, the returned value is -1. Since std::vector interface does not contain this API, we need to remove this API altogether to facilitate switching to std::vector in future.

There are several different ways in which code currently using Location can be ported:

  • Often Location API is used to check if a particular element exists or does not exist in the K2Vector. Replacement functions K2found and K2notfound, defined in K2STLUtilities.h, can be used as replacement. Examples:

Current code (assuming a typename T):

K2Vector<T> myK2Vector;
T testVal(0);
if (myK2Vector.Location(testVal) == -1){} //not found
if (myK2Vector.Location(testVal) < 0){} //not found
if (myK2Vector.Location(testVal) >= 0){} //found
if (myK2Vector.Location(testVal) != -1){} //found

New code:

K2Vector<T> myK2Vector;
T testVal(0);
if (K2notfound(myK2Vector, testVal)){} //not found
if (K2found(myK2Vector, testVal)){} //found
  • If you want to perform an operation on the returned value or remove it from the K2Vector, consider using iterators directly. Examples:

Current code (assuming a typename T):

K2Vector<T> myK2Vector;
T testVal(0), newVal(1);
int32 loc = myK2Vector.Location(testVal);
if (loc != -1) //found
{
myK2Vector[loc] = newVal; //change the value, or remove it as in next statement...
myK2Vector.erase(myK2Vector.begin() + loc);
}

New code:

K2Vector<T> myK2Vector;
T testVal(0), newVal(1);
auto iter = K2find(myK2Vector, testVal);
if (iter != myK2Vector.end()) //found
{
*iter = newVal; //change the value, or remove it as in next statement...
myK2Vector.erase(iter);
}
  • If you do need the int32 value that used to be returned by Location API, because you need to store it or pass it to another API, replacement function K2location, defined in K2STLUtilities.h, can still be used. K2location will be removed or will undergo change in signature in future when we clean up code where int32 is used where size_type was intended. Examples:

Current code (assuming a typename T):

K2Vector<T> myK2Vector;
T testVal(0);
return myK2Vector.Location(testVal);

New code:

K2Vector<T> myK2Vector;
T testVal(0);
return K2location(myK2Vector, testVal);

K2Vector deprecated API "Length" removal

K2Vector's Length API has been marked deprecated for several cycles now. This API returns a value of type 'int32' representing the number of elements in the K2Vector. Standard API "size" already exists in the K2Vector interface and can be used in many situations - read the porting examples below where special care needs to be taken when replacing Length with size:

  • Often Length API is used to check if a K2Vector is empty or non-empty. K2Vector API "empty" can be used as a replacement for this use case. Examples:

Current code (assuming a typename T):

K2Vector<T> myK2Vector;
if (myK2Vector.Length() == 0){} //empty
if (myK2Vector.Length() != 0){} //non-empty
if (myK2Vector.Length() > 0){} //non-empty
if (myK2Vector.Length()){} //non-empty

New code:

K2Vector<T> myK2Vector;
if (myK2Vector.empty()){} //empty
if (!myK2Vector.empty()){} //non-empty
  • Sometimes the Length() API is actually used as a for loop condition to iterate over the entire K2Vector. Iterators, reverse iterators and range-based for loops can be used as a replacement. Examples:

Current code (assuming a typename T):

K2Vector<T> myK2Vector;
for (int32 i = 0; i < myK2Vector.Length(); ++i) //forward iteration of entire K2Vector
{ const T &val = myK2Vector[i]; }
for (int32 i = myK2Vector.Length() - 1; i >= 0 ; --i) //reverse iteration of entire K2Vector
{ const T &val = myK2Vector[i]; }

New code:

K2Vector<T> myK2Vector;
for (auto iter = myK2Vector.begin(); iter != myK2Vector.end(); ++iter) //forward iteration of entire K2Vector
{ const T &val = *iter; }
for (const auto &val : myK2Vector) //forward iteration of entire K2Vector using range-based for loop
{ }
for (auto iter = myK2Vector.rbegin(); iter != myK2Vector.rend(); ++iter) //reverse iteration of entire K2Vector
{ const T &val = *iter; }
  • If the actual size is needed, use either K2Vector::size() or K2length API that is defined in K2STLUtilities. API "size" should be used when you know it is safe to use the unsigned return value of size API in place of the signed return value of the Length API. If a signed return value is needed, use K2length instead (see example below). K2length will be removed in future when we clean up code where int32 is used where size_type was intended.

Current code (assuming a typename T):

K2Vector<T> myK2Vector, mySecondK2Vector;
if (myK2Vector.Length() == mySecondK2Vector.Length()){} //safe to use size()
int32 index = -1;
int32 prevSize = myK2Vector.Length(); //might be safe to use size() - depends on whether the value is compared with an existing int32 or not.
if (index < myK2Vector.Length()){} //NOT safe to use size() because the value of int32, -1, will be converted to unsigned and will be greater than the size of the K2Vector.

New code:

K2Vector<T> myK2Vector, mySecondK2Vector;
if (myK2Vector.size() == mySecondK2Vector.size()){} //safe to use size()
int32 index = -1;
int32 prevSize = myK2Vector.size(); //might be safe to use size() - depends on whether the value is compared with an existing int32 or not.
if (index < K2length(myK2Vector)){} //NOT safe to use size() because the value of int32, -1, will be converted to unsigned and will be greater than the size of the K2Vector.

SVG Icons

Icons and cursors can be created in their native-platform resource form. InDesign also supports SVG/PNG platform-independent files for icons. SVG is the preferred resource type to use in icon-based widgets. All the application tools icons and cursors use SVG files. Although PNG icons are still supported, continuing to use PNG Icons means that icons will become skewed and blurred when the icons are scaled. Instead of PNG icons, SVG icons should be preferred.

To create a SVG-based icon:

  1. In your .fr file, where you have the ToolDef, declare the SVG resources. There will be only one state for each each icon i.e. normal. For example, in the SDK snippet runner plugin we have declared SVG resource as:
    resource SVGA(kSnipRunGoIconSnapResourceID) "S_Play_Wi_N@2x.svg"
  2. Use the normal-state resource ID in your ToolDef definition, where you specify the icon ID for the tool.

Spectrum UI in InDesign (since InDesign CC 2017.1)

The overall theme of Spectrum UI is to bring a consistency in Adobe products’ UI and give these products a flat modern look. The major effort in this work is to remove bevels and embossing in the UI.

Changes needed to get Spectrum UI in plug-ins

Ideally, no changes should be needed. API signatures have not been modified in this UI modernization so existing plug-ins should automatically get UI appearance consistent to InDesign, if no custom drawing has been done for any widget i.e. following API has not been implemented:

IControlView::Draw(IViewPort* viewPort, SysRgn updateRgn = nil)

or following API has not been overridden:

DVHostedWidgetView::(dvaui::drawbot::Drawbot* drawbotP)

If custom drawing has been done using any of the above APIs, some rework may be needed depending on the type of customization done. An example of customization that was done by InDesign team was bevels. Bevel is a combination of highlight and shadow. We chose to replace it with a uniform border wherever it appeared. Another major change that we made was changing few icons as they did not have a flat appearance. This is an optional change for plug-in developers. If the currently used icons look inconsistent with the rest of the UI, they may be modified to match colors and flatter appearance. In such a situation, the plug-in will need recompilation.

Changes in API behavior

  • Owner drawn dropdowns: The width of the owner drawn dropdowns has been limited to a minimum value of kCC2016OwnerDrawDDItemMinWidth and maximum kCC2016OwnerDrawDDItemMaxWidth. These constants and other useful constants have been defined in StdHeightWidthConstants.h header file.
  • SetDrawListWidgetEndLine() API: The drawing of end line has been disabled from the scroller widget and SetDrawListWidgetEndLine() API has been marked deprecated. Drawing of end line via scroller widget in the list tree is not required as it is already being done while drawing the node separator for the last node. Users can set/reset the drawing of endline via the “kDrawEndLine” attribute in the “fr” as while drawing node separator “kDrawEndLine” attribute is queried and decision to draw the endline is made on the basis of its value.
  • Widgets added for Spectrum in Widgets.fh
  1. GenericPanelWithCustomBorderWidget: This widget is defined to have a configurable sides which should be drawn around the child widget. This is an extension to GenericPanelWithBorderWidget with additional information for sides to be drawn and the corner radius, if it is going to have rounded corners.

Parameters for GenericPanelWithCustomBorderWidget : Other than the parameters used by GenericPanelWithBorderWidget, the following parameters are needed:

  • The sides to be drawn: The constants kAllBorder, kLeftBorder, kRightBorder, kTopBorder, kBottomBorder are defined in StdHeightWidthConstants.h . If you have specified a corner radius to be used which is greater than 0, the border will be drawn with the specified sides and the corners made by those edges will have the corner radius specified.
  • The corner radius: Use the corner radius if you want the corners to be rounded. If the corner radius specified is less than or equal to 0, the corners will not be rounded.
  1. CSliderWidget: This can be used to create slider like widgets. The following parameters are read from the fr file:
  • CControlView: The IControlView description of the slider.
  • CSliderControlData: The minimum, maximum, and initial value of the slider. These values should be specified as double e.g. 0.0, 100.0, 50.0 will set the minimum, maximum, and initial value of the slider.
  • CSliderTickCount: The number of ticks to show on the slider. Generally, the minimum and maximum slider values are divided into equal parts to get the numbers of ticks. If number of ticks specified < 2, it will be ignored to have no ticks.

Any change in the value of the slider value is broadcast on ISubject interface of this widget with ClassID as kRealChangeStateMessage.