Warning, /frameworks/extra-cmake-modules/modules/ECMAddAppIcon.cmake is written in an unsupported language. File is not indexed.

0001 # SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
0002 # SPDX-FileCopyrightText: 2014 Ralf Habacker <ralf.habacker@freenet.de>
0003 # SPDX-FileCopyrightText: 2006-2009 Alexander Neundorf <neundorf@kde.org>
0004 # SPDX-FileCopyrightText: 2006, 2007 Laurent Montel <montel@kde.org>
0005 # SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org>
0006 #
0007 # SPDX-License-Identifier: BSD-3-Clause
0008 
0009 #[=======================================================================[.rst:
0010 ECMAddAppIcon
0011 -------------
0012 
0013 Add icons to executable files and packages.
0014 
0015 ::
0016 
0017  ecm_add_app_icon(<sources_var_name(|target (since 5.83))>
0018                   ICONS <icon> [<icon> [...]]
0019                   [SIDEBAR_ICONS <icon> [<icon> [...]] # Since 5.49
0020                   [OUTFILE_BASENAME <name>]) # Since 5.49
0021                   )
0022 
0023 The given icons, whose names must match the pattern::
0024 
0025   <size>-<other_text>.png
0026 
0027 will be added as platform-specific application icons
0028 to the variable named ``<sources_var_name>`` or, if the first argument
0029 is a target (since 5.83), to the ``SOURCES`` property of ``<target>``.
0030 Any target must be created with add_executable() and not be an alias.
0031 
0032 Other icon files are ignored but on Mac SVG files can be supported and
0033 it is thus possible to mix those with png files in a single macro call.
0034 
0035 The platforms currently supported are Windows and Mac OS X, on all others
0036 the call has no effect and is ignored.
0037 
0038 ``<size>`` is a numeric pixel size (typically 16, 32, 48, 64, 128 or 256).
0039 ``<other_text>`` can be any other text. See the platform notes below for any
0040 recommendations about icon sizes.
0041 
0042 ``SIDEBAR_ICONS`` can be used to add Mac OS X sidebar
0043 icons to the generated iconset. They are used when a folder monitored by the
0044 application is dragged into Finder's sidebar. Since 5.49.
0045 
0046 ``OUTFILE_BASENAME`` will be used as the basename for the icon file. If
0047 you specify it, the icon file will be called ``<OUTFILE_BASENAME>.icns`` on Mac OS X
0048 and ``<OUTFILE_BASENAME>.ico`` on Windows. If you don't specify it, it defaults
0049 to ``<sources_var_name>.<ext>``. Since 5.49.
0050 
0051 
0052 Windows notes
0053    * Icons are compiled into the executable using a resource file.
0054    * Icons may not show up in Windows Explorer if the executable
0055      target does not have the ``WIN32_EXECUTABLE`` property set.
0056    * Icotool (see :find-module:`FindIcoTool`) is required.
0057    * Supported sizes: 16, 24, 32, 48, 64, 128, 256, 512 and 1024.
0058 
0059 Mac OS X notes
0060    * The executable target must have the ``MACOSX_BUNDLE`` property set.
0061    * Icons are added to the bundle.
0062    * If the ksvg2icns tool from KIconThemes is available, .svg and .svgz
0063      files are accepted; the first that is converted successfully to .icns
0064      will provide the application icon. SVG files are ignored otherwise.
0065    * The tool iconutil (provided by Apple) is required for bitmap icons.
0066    * Supported sizes: 16, 32, 64, 128, 256 (and 512, 1024 after OS X 10.9).
0067    * At least a 128x128px (or an SVG) icon is required.
0068    * Larger sizes are automatically used to substitute for smaller sizes on
0069      "Retina" (high-resolution) displays. For example, a 32px icon, if
0070      provided, will be used as a 32px icon on standard-resolution displays,
0071      and as a 16px-equivalent icon (with an "@2x" tag) on high-resolution
0072      displays. That is why you should provide 64px and 1024px icons although
0073      they are not supported anymore directly. Instead they will be used as
0074      32px@2x and 512px@2x. If an SVG icon is provided, ksvg2icns will be
0075      used internally to automatically generate all appropriate sizes,
0076      including the high-resolution ones.
0077    * This function sets the ``MACOSX_BUNDLE_ICON_FILE`` variable to the name
0078      of the generated icns file, so that it will be used as the
0079      ``MACOSX_BUNDLE_ICON_FILE`` target property when you call
0080      ``add_executable``.
0081    * Sidebar icons should typically provided in 16, 32, 64, 128 and 256px.
0082 
0083 Since 1.7.0.
0084 #]=======================================================================]
0085 
0086 function(ecm_add_app_icon appsources_or_target)
0087     set(options)
0088     set(oneValueArgs OUTFILE_BASENAME)
0089     set(multiValueArgs ICONS SIDEBAR_ICONS)
0090     cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
0091 
0092     if(NOT ARG_ICONS)
0093         message(FATAL_ERROR "No ICONS argument given to ecm_add_app_icon")
0094     endif()
0095     if (TARGET ${appsources_or_target})
0096         get_target_property(target_type ${appsources_or_target} TYPE)
0097         if (NOT target_type STREQUAL "EXECUTABLE")
0098             message(FATAL_ERROR "Target argument passed to ecm_add_app_icon is not an executable: ${appsources_or_target}")
0099         endif()
0100         get_target_property(aliased_target ${appsources_or_target} ALIASED_TARGET)
0101         if(aliased_target)
0102             message(FATAL_ERROR "Target argument passed to ecm_add_app_icon must not be an alias: ${appsources_or_target}")
0103         endif()
0104     endif()
0105     if(ARG_UNPARSED_ARGUMENTS)
0106         message(FATAL_ERROR "Unexpected arguments to ecm_add_app_icon: ${ARG_UNPARSED_ARGUMENTS}")
0107     endif()
0108 
0109     if(APPLE)
0110         find_program(KSVG2ICNS NAMES ksvg2icns)
0111         foreach(icon ${ARG_ICONS})
0112             get_filename_component(icon_full ${icon} ABSOLUTE)
0113             get_filename_component(icon_type ${icon_full} EXT)
0114             # do we have ksvg2icns in the path and did we receive an svg (or compressed svg) icon?
0115             if(KSVG2ICNS AND (${icon_type} STREQUAL ".svg" OR ${icon_type} STREQUAL ".svgz"))
0116                 # convert the svg icon to an icon resource
0117                 execute_process(COMMAND ${KSVG2ICNS} "${icon_full}"
0118                     WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} RESULT_VARIABLE KSVG2ICNS_ERROR)
0119                 if(${KSVG2ICNS_ERROR})
0120                     message(AUTHOR_WARNING "ksvg2icns could not generate an OS X application icon from ${icon}")
0121                 else()
0122                     # install the icns file we just created
0123                     get_filename_component(icon_name ${icon_full} NAME_WE)
0124                     set(MACOSX_BUNDLE_ICON_FILE ${icon_name}.icns PARENT_SCOPE)
0125                     if (TARGET ${appsources_or_target})
0126                         target_sources(${appsources_or_target} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/${icon_name}.icns")
0127                     else()
0128                         set(${appsources_or_target} "${${appsources_or_target}};${CMAKE_CURRENT_BINARY_DIR}/${icon_name}.icns" PARENT_SCOPE)
0129                     endif()
0130                     set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${icon_name}.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
0131                     # we're done now
0132                     return()
0133                 endif()
0134             endif()
0135         endforeach()
0136     endif()
0137 
0138 
0139     _ecm_add_app_icon_categorize_icons("${ARG_ICONS}" "icons" "16;24;32;48;64;128;256;512;1024")
0140     if(ARG_SIDEBAR_ICONS)
0141         _ecm_add_app_icon_categorize_icons("${ARG_SIDEBAR_ICONS}" "sidebar_icons" "16;32;64;128;256")
0142     endif()
0143 
0144     set(mac_icons
0145                   # Icons: https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html#//apple_ref/doc/uid/TP40012302-CH7-SW4
0146                   ${icons_at_16px}
0147                   ${icons_at_32px}
0148                   ${icons_at_64px}
0149                   ${icons_at_128px}
0150                   ${icons_at_256px}
0151                   ${icons_at_512px}
0152                   ${icons_at_1024px})
0153 
0154     set(mac_sidebar_icons
0155                   # Sidebar Icons: https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Finder.html#//apple_ref/doc/uid/TP40014214-CH15-SW15
0156                   ${sidebar_icons_at_16px}
0157                   ${sidebar_icons_at_32px}
0158                   ${sidebar_icons_at_64px}
0159                   ${sidebar_icons_at_128px}
0160                   ${sidebar_icons_at_256px})
0161 
0162     if (NOT (mac_icons OR mac_sidebar_icons))
0163         message(AUTHOR_WARNING "No icons suitable for use on macOS provided")
0164     endif()
0165 
0166 
0167     set(windows_icons_classic ${icons_at_16px}
0168                               ${icons_at_24px}
0169                               ${icons_at_32px}
0170                               ${icons_at_48px}
0171                               ${icons_at_64px}
0172                               ${icons_at_128px})
0173     set(windows_icons_modern  ${windows_icons_classic}
0174                               ${icons_at_256px}
0175                               ${icons_at_512px}
0176                               ${icons_at_1024px})
0177 
0178     if (NOT (windows_icons_modern OR windows_icons_classic))
0179         message(AUTHOR_WARNING "No icons suitable for use on Windows provided")
0180     endif()
0181 
0182     if (ARG_OUTFILE_BASENAME)
0183         set (_outfilebasename "${ARG_OUTFILE_BASENAME}")
0184     else()
0185         set (_outfilebasename "${appsources_or_target}")
0186     endif()
0187     set (_outfilename "${CMAKE_CURRENT_BINARY_DIR}/${_outfilebasename}")
0188 
0189     if (WIN32 AND (windows_icons_modern OR windows_icons_classic))
0190         set(saved_CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}")
0191         set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_FIND_MODULE_DIR})
0192         find_package(IcoTool)
0193         set(CMAKE_MODULE_PATH "${saved_CMAKE_MODULE_PATH}")
0194 
0195         function(create_windows_icon_and_rc command args deps)
0196                 add_custom_command(
0197                     OUTPUT "${_outfilename}.ico"
0198                     COMMAND ${command}
0199                     ARGS ${args}
0200                     DEPENDS ${deps}
0201                     WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
0202                 )
0203                 # this bit's a little hacky to make the dependency stuff work
0204                 file(WRITE "${_outfilename}.rc.in" "IDI_ICON1        ICON        DISCARDABLE    \"${_outfilename}.ico\"\n")
0205                 add_custom_command(
0206                     OUTPUT "${_outfilename}.rc"
0207                     COMMAND ${CMAKE_COMMAND}
0208                     ARGS -E copy "${_outfilename}.rc.in" "${_outfilename}.rc"
0209                     DEPENDS "${_outfilename}.ico"
0210                     WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
0211                 )
0212         endfunction()
0213 
0214         if (IcoTool_FOUND)
0215             list(APPEND icotool_args "-c" "-o" "${_outfilename}.ico")
0216 
0217             # According to https://stackoverflow.com/a/40851713/2886832
0218             # Windows always chooses the first icon above 255px, all other ones will be ignored
0219             set(maxSize 0)
0220             foreach(size 256 512 1024)
0221                 if(icons_at_${size}px)
0222                     set(maxSize "${size}")
0223                 endif()
0224             endforeach()
0225 
0226             foreach(size 16 24 32 48 64 128 ${maxSize})
0227                 if(NOT icons_at_${size}px)
0228                     continue()
0229                 endif()
0230 
0231                 set(icotool_icon_arg "")
0232                 if(size STREQUAL "${maxSize}")
0233                     # maxSize icon needs to be included as raw png
0234                     list(APPEND icotool_args "-r")
0235                 endif()
0236 
0237                 foreach(icon ${icons_at_${size}px})
0238                     list(APPEND icotool_args "${icons_at_${size}px}")
0239                 endforeach()
0240             endforeach()
0241 
0242             create_windows_icon_and_rc(IcoTool::IcoTool "${icotool_args}" "${windows_icons_modern}")
0243             if (TARGET ${appsources_or_target})
0244                 target_sources(${appsources_or_target} PRIVATE "${_outfilename}.rc")
0245             else()
0246                 set(${appsources_or_target} "${${appsources_or_target}};${_outfilename}.rc" PARENT_SCOPE)
0247             endif()
0248         else()
0249             message(WARNING "Unable to find the icotool utilities or icons in matching sizes - application will not have an application icon!")
0250         endif()
0251     elseif (APPLE AND (mac_icons OR mac_sidebar_icons))
0252         # first generate .iconset directory structure, then convert to .icns format using the Mac OS X "iconutil" utility,
0253         # to create retina compatible icon, you need png source files in pixel resolution 16x16, 32x32, 64x64, 128x128,
0254         # 256x256, 512x512, 1024x1024
0255         find_program(ICONUTIL_EXECUTABLE NAMES iconutil)
0256         if (ICONUTIL_EXECUTABLE)
0257             add_custom_command(
0258                 OUTPUT "${_outfilename}.iconset"
0259                 COMMAND ${CMAKE_COMMAND}
0260                 ARGS -E make_directory "${_outfilename}.iconset"
0261             )
0262             set(iconset_icons)
0263             macro(copy_icon filename sizename type)
0264                 add_custom_command(
0265                     OUTPUT "${_outfilename}.iconset/${type}_${sizename}.png"
0266                     COMMAND ${CMAKE_COMMAND}
0267                     ARGS -E copy
0268                          "${filename}"
0269                          "${_outfilename}.iconset/${type}_${sizename}.png"
0270                     DEPENDS
0271                         "${_outfilename}.iconset"
0272                         "${filename}"
0273                     WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
0274                 )
0275                 list(APPEND iconset_icons
0276                         "${_outfilename}.iconset/${type}_${sizename}.png")
0277             endmacro()
0278 
0279             # List of supported sizes and filenames taken from:
0280             # https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html#//apple_ref/doc/uid/TP40012302-CH7-SW4
0281             foreach(size 16 32 128 256 512)
0282                 math(EXPR double_size "2 * ${size}")
0283                 foreach(file ${icons_at_${size}px})
0284                     copy_icon("${file}" "${size}x${size}" "icon")
0285                 endforeach()
0286                 foreach(file ${icons_at_${double_size}px})
0287                     copy_icon("${file}" "${size}x${size}@2x" "icon")
0288                 endforeach()
0289             endforeach()
0290 
0291             # List of supported sizes and filenames taken from:
0292             # https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Finder.html#//apple_ref/doc/uid/TP40014214-CH15-SW15
0293             foreach(file ${sidebar_icons_at_16px})
0294                 copy_icon("${file}" "16x16" "sidebar")
0295             endforeach()
0296             foreach(file ${sidebar_icons_at_32px})
0297                 copy_icon("${file}" "16x16@2x" "sidebar")
0298             endforeach()
0299             foreach(file ${sidebar_icons_at_32px})
0300                 copy_icon("${file}" "18x18" "sidebar")
0301             endforeach()
0302             foreach(file ${sidebar_icons_at_64px})
0303                 copy_icon("${file}" "18x18@2x" "sidebar")
0304             endforeach()
0305             foreach(file ${sidebar_icons_at_128px})
0306                 copy_icon("${file}" "32x32" "sidebar")
0307             endforeach()
0308             foreach(file ${sidebar_icons_at_256px})
0309                 copy_icon("${file}" "32x32@2x" "sidebar")
0310             endforeach()
0311 
0312             # generate .icns icon file
0313             add_custom_command(
0314                 OUTPUT "${_outfilename}.icns"
0315                 COMMAND ${ICONUTIL_EXECUTABLE}
0316                 ARGS
0317                     --convert icns
0318                     --output "${_outfilename}.icns"
0319                     "${_outfilename}.iconset"
0320                 DEPENDS "${iconset_icons}"
0321                 WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
0322             )
0323             # This will register the icon into the bundle
0324             set(MACOSX_BUNDLE_ICON_FILE "${_outfilebasename}.icns" PARENT_SCOPE)
0325 
0326             # Append the icns file to the sources list so it will be a dependency to the
0327             # main target
0328             if (TARGET ${appsources_or_target})
0329                 target_sources(${appsources_or_target} PRIVATE "${_outfilename}.icns")
0330             else()
0331                 set(${appsources_or_target} "${${appsources_or_target}};${_outfilename}.icns" PARENT_SCOPE)
0332             endif()
0333 
0334             # Install the icon into the Resources dir in the bundle
0335             set_source_files_properties("${_outfilename}.icns" PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
0336         else()
0337             message(STATUS "Unable to find the iconutil utility - application will not have an application icon!")
0338         endif()
0339     endif()
0340 endfunction()
0341 
0342 macro(_ecm_add_app_icon_categorize_icons icons type known_sizes)
0343     set(_${type}_known_sizes)
0344     foreach(size ${known_sizes})
0345         set(${type}_at_${size}px)
0346         list(APPEND _${type}_known_sizes ${size})
0347     endforeach()
0348 
0349 
0350     foreach(icon ${icons})
0351         get_filename_component(icon_full ${icon} ABSOLUTE)
0352         if (NOT EXISTS "${icon_full}")
0353             message(AUTHOR_WARNING "${icon_full} does not exist, ignoring")
0354         else()
0355             get_filename_component(icon_name ${icon} NAME)
0356             string(REGEX MATCH "([0-9]+|sc)\\-[^/]+\\.([a-z]+)$"
0357                                _dummy "${icon_name}")
0358             set(size  "${CMAKE_MATCH_1}")
0359             set(ext   "${CMAKE_MATCH_2}")
0360 
0361             if (NOT (ext STREQUAL "svg" OR ext STREQUAL "svgz"))
0362                 if (NOT size)
0363                     message(AUTHOR_WARNING "${icon_full} is not named correctly for ecm_add_app_icon - ignoring")
0364                 elseif (NOT ext STREQUAL "png")
0365                     message(AUTHOR_WARNING "${icon_full} is not a png file - ignoring")
0366                 else()
0367                     list(FIND _${type}_known_sizes ${size} offset)
0368 
0369                     if (offset GREATER -1)
0370                         list(APPEND ${type}_at_${size}px "${icon_full}")
0371                     elseif()
0372                         message(STATUS "not found ${type}_at_${size}px ${icon_full}")
0373                     endif()
0374                 endif()
0375             endif()
0376         endif()
0377     endforeach()
0378 endmacro()