summaryrefslogtreecommitdiffstats
path: root/packaging/macos/src
diff options
context:
space:
mode:
Diffstat (limited to 'packaging/macos/src')
-rw-r--r--packaging/macos/src/cairosvg.sh38
-rw-r--r--packaging/macos/src/ink.sh329
-rw-r--r--packaging/macos/src/inkscape.bundle181
-rw-r--r--packaging/macos/src/inkscape_dmg.py246
-rw-r--r--packaging/macos/src/jhb-custom.conf.sh41
-rw-r--r--packaging/macos/src/png2icns.sh37
-rw-r--r--packaging/macos/src/svg2icns.sh56
7 files changed, 928 insertions, 0 deletions
diff --git a/packaging/macos/src/cairosvg.sh b/packaging/macos/src/cairosvg.sh
new file mode 100644
index 0000000..bcd2aa6
--- /dev/null
+++ b/packaging/macos/src/cairosvg.sh
@@ -0,0 +1,38 @@
+# SPDX-FileCopyrightText: 2021 René de Hesselle <dehesselle@web.de>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+### description ################################################################
+
+# cairosvg is a Python package so we can convert svg to png.
+
+### shellcheck #################################################################
+
+# shellcheck shell=bash # no shebang as this file is intended to be sourced
+
+### dependencies ###############################################################
+
+# Nothing here.
+
+### variables ##################################################################
+
+# https://cairocffi.readthedocs.io/en/stable/
+# https://github.com/Kozea/cairocffi
+# https://cairosvg.org
+# https://github.com/Kozea/CairoSVG
+CAIROSVG_PIP="\
+ cairocffi==1.2.0\
+ cairosvg==2.5.2\
+"
+
+### functions ##################################################################
+
+function cairosvg_install
+{
+ # shellcheck disable=SC2086 # we need word splitting here
+ jhb run pip3 install $CAIROSVG_PIP
+}
+
+### main #######################################################################
+
+# Nothing here. \ No newline at end of file
diff --git a/packaging/macos/src/ink.sh b/packaging/macos/src/ink.sh
new file mode 100644
index 0000000..fe4d19c
--- /dev/null
+++ b/packaging/macos/src/ink.sh
@@ -0,0 +1,329 @@
+# SPDX-FileCopyrightText: 2021 René de Hesselle <dehesselle@web.de>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+### description ################################################################
+
+# This file contains everything related to Inkscape.
+
+### shellcheck #################################################################
+
+# shellcheck shell=bash # no shebang as this file is intended to be sourced
+# shellcheck disable=SC2034 # multipe vars only used outside this script
+
+### dependencies ###############################################################
+
+# Nothing here.
+
+### variables ##################################################################
+
+#----------------------------------------------- source directory and git branch
+
+# There are 3 possible scenarios:
+#
+# 1. We're running inside Inkscape's CI:
+# The repository has already been cloned, set INK_DIR accordingly.
+#
+# 2. We're not running inside Inkscape's CI and INK_DIR has been set:
+# Use INK_DIR provided as-is, we expect the source to be there.
+#
+# 3. We're not running inside Inkscape's CI CI and INK_DIR has not been set:
+# Set INK_DIR to our default location, we'll clone the repo there.
+
+if [ "$CI_PROJECT_NAME" = "inkscape" ]; then # running in Inkscape's CI
+ INK_DIR=$CI_PROJECT_DIR
+else # not running in Inkscape's CI
+ # Use default directory if not provided.
+ if [ -z "$INK_DIR" ]; then
+ INK_DIR=$SRC_DIR/inkscape
+ fi
+
+ # Allow using a custom Inkscape repository and branch.
+ if [ -z "$INK_URL" ]; then
+ INK_URL=https://gitlab.com/inkscape/inkscape
+ fi
+
+ # Allow using a custom branch.
+ if [ -z "$INK_BRANCH" ]; then
+ INK_BRANCH=1.2.x
+ fi
+fi
+
+INK_BLD_DIR=$BLD_DIR/$(basename "$INK_DIR") # we build out-of-tree
+
+#------------------------------------------------------------------ build number
+
+INK_BUILD=${INK_BUILD:-0}
+
+#------------------------------------ Python runtime to be bundled with Inkscape
+
+# Inkscape will be bundled with its own (customized) Python 3 runtime to make
+# the core extensions work out-of-the-box.
+
+INK_PYTHON_VER_MAJOR=3
+INK_PYTHON_VER_MINOR=10
+INK_PYTHON_VER=$INK_PYTHON_VER_MAJOR.$INK_PYTHON_VER_MINOR
+INK_PYTHON_URL="https://gitlab.com/api/v4/projects/26780227/packages/generic/\
+python_macos/15/python_${INK_PYTHON_VER/./}_$(uname -m)_inkscape.tar.xz"
+INK_PYTHON_ICON_URL="https://gitlab.com/inkscape/vectors/content/-/raw/\
+5f4f4cdf/branding/projects/extensions_c1.svg"
+
+#----------------------------------- Python packages to be bundled with Inkscape
+
+# https://pypi.org/project/appdirs/
+INK_PYTHON_PKG_APPDIRS=appdirs==1.4.4
+
+# https://pypi.org/project/beautifulsoup4/
+# https://pypi.org/project/soupsieve/
+INK_PYTHON_PKG_BEAUTIFULSOUP4="\
+ beautifulsoup4==4.10.0\
+ soupsieve==2.3.1\
+"
+
+# https://pypi.org/project/CacheControl/
+# https://pypi.org/project/certifi/
+# https://pypi.org/project/charset-normalizer/
+# https://pypi.org/project/idna/
+# https://pypi.org/project/lockfile/
+# https://pypi.org/project/msgpack/
+# https://pypi.org/project/requests/
+# https://pypi.org/project/urllib3/
+INK_PYTHON_PKG_CACHECONTROL="\
+ CacheControl==0.12.10\
+ certifi==2021.10.8\
+ charset_normalizer==2.0.11\
+ idna==3.3\
+ lockfile==0.12.2\
+ msgpack==1.0.3\
+ requests==2.27.1\
+ urllib3==1.26.8\
+"
+
+# https://pypi.org/project/cssselect/
+INK_PYTHON_PKG_CSSSELECT=cssselect==1.1.0
+
+# https://pypi.org/project/lxml/
+INK_PYTHON_PKG_LXML=lxml==4.7.1
+
+# https://pypi.org/project/numpy/
+INK_PYTHON_PKG_NUMPY=https://files.pythonhosted.org/packages/\
+b4/85/8097082c4794d854e40f84639c83e33e516431faaeb9cecba39eba6921d5/\
+numpy-1.22.1-cp310-cp310-macosx_10_9_universal2.whl
+
+# https://pypi.org/project/Pillow/
+INK_PYTHON_PKG_PILLOW=Pillow==9.0.0
+
+# https://pypi.org/project/pycairo/
+# https://pypi.org/project/PyGObject/
+INK_PYTHON_PKG_PYGOBJECT="\
+ PyGObject==3.42.1\
+ pycairo==1.21.0\
+"
+
+# https://pypi.org/project/pyserial/
+INK_PYTHON_PKG_PYSERIAL=pyserial==3.5
+
+# https://pypi.org/project/scour/
+# https://pypi.org/project/six/
+INK_PYTHON_PKG_SCOUR="\
+ scour==0.38.2\
+ six==1.16.0\
+ packaging==21.3 \
+ pyparsing==3.0.7 \
+"
+
+#------------------------------------------- application bundle directory layout
+
+INK_APP_DIR=$ARTIFACT_DIR/Inkscape.app
+
+INK_APP_CON_DIR=$INK_APP_DIR/Contents
+INK_APP_RES_DIR=$INK_APP_CON_DIR/Resources
+INK_APP_FRA_DIR=$INK_APP_CON_DIR/Frameworks
+INK_APP_BIN_DIR=$INK_APP_RES_DIR/bin
+INK_APP_ETC_DIR=$INK_APP_RES_DIR/etc
+INK_APP_EXE_DIR=$INK_APP_CON_DIR/MacOS
+INK_APP_LIB_DIR=$INK_APP_RES_DIR/lib
+INK_APP_SPK_DIR=$INK_APP_LIB_DIR/python$INK_PYTHON_VER/site-packages
+
+INK_APP_PLIST=$INK_APP_CON_DIR/Info.plist
+
+### functions ##################################################################
+
+function ink_get_version
+{
+ local file=$INK_DIR/CMakeLists.txt
+ local ver_major
+ ver_major=$(grep INKSCAPE_VERSION_MAJOR "$file" | head -n 1 |
+ awk '{ print $2+0 }')
+ local ver_minor
+ ver_minor=$(grep INKSCAPE_VERSION_MINOR "$file" | head -n 1 |
+ awk '{ print $2+0 }')
+ local ver_patch
+ ver_patch=$(grep INKSCAPE_VERSION_PATCH "$file" | head -n 1 |
+ awk '{ print $2+0 }')
+ local ver_suffix
+ ver_suffix=$(grep INKSCAPE_VERSION_SUFFIX "$file" | head -n 1 |
+ awk '{ print $2 }')
+
+ ver_suffix=${ver_suffix%\"*} # remove "double quotes and all" from end
+ ver_suffix=${ver_suffix#\"} # remove "double quote" from beginning
+
+ echo "$ver_major.$ver_minor.$ver_patch$ver_suffix"
+}
+
+function ink_get_repo_shorthash
+{
+ # do it the same way as in CMakeScripts/inkscape-version.cmake
+ git -C "$INK_DIR" rev-parse --short HEAD
+}
+
+function ink_pipinstall
+{
+ local packages=$1 # name of variable that resolves to list of packages
+ local options=$2 # optional
+
+ # turn package names into filenames of our wheels
+ local wheels
+ for package in $(eval echo \$"$packages"); do
+ if [ "${package::8}" = "https://" ]; then
+ package=$(basename "$package")
+ else
+ package=$(eval echo "${package/==/-}"*.whl)
+ fi
+
+ # If present in TMP_DIR, use that. This is how the externally built
+ # packages can be fed into this.
+ if [ -f "$TMP_DIR/$package" ]; then
+ wheels="$wheels $TMP_DIR/$package"
+ else
+ wheels="$wheels $PKG_DIR/$package"
+ fi
+ done
+
+ local path_original=$PATH
+ export PATH=$INK_APP_FRA_DIR/Python.framework/Versions/Current/bin:$PATH
+
+ # shellcheck disable=SC2086 # we need word splitting here
+ pip$INK_PYTHON_VER_MAJOR install \
+ --prefix "$INK_APP_RES_DIR" \
+ --ignore-installed \
+ $options \
+ $wheels
+
+ export PATH=$path_original
+
+ local ink_pipinstall_func
+ ink_pipinstall_func=ink_pipinstall_$(echo "${packages##*_}" |
+ tr "[:upper:]" "[:lower:]")
+
+ if declare -F "$ink_pipinstall_func" > /dev/null; then
+ $ink_pipinstall_func
+ fi
+}
+
+function ink_pipinstall_lxml
+{
+ lib_change_paths \
+ @loader_path/../../.. \
+ "$INK_APP_LIB_DIR" \
+ "$INK_APP_SPK_DIR"/lxml/etree.cpython-"${INK_PYTHON_VER/./}"-darwin.so \
+ "$INK_APP_SPK_DIR"/lxml/objectify.cpython-"${INK_PYTHON_VER/./}"-darwin.so
+}
+
+function ink_pipinstall_numpy
+{
+ sed -i '' '1s|.*|#!/usr/bin/env python'"$INK_PYTHON_VER_MAJOR"'|' \
+ "$INK_APP_BIN_DIR"/f2py
+ sed -i '' '1s|.*|#!/usr/bin/env python'"$INK_PYTHON_VER_MAJOR"'|' \
+ "$INK_APP_BIN_DIR"/f2py$INK_PYTHON_VER_MAJOR
+ sed -i '' '1s|.*|#!/usr/bin/env python'"$INK_PYTHON_VER_MAJOR"'|' \
+ "$INK_APP_BIN_DIR"/f2py$INK_PYTHON_VER
+
+ find "$INK_APP_LIB_DIR/python$INK_PYTHON_VER/site-packages/numpy" \
+ '(' -name "*.so" -o -name "*.dylib" ')' \
+ -exec codesign --remove-signature {} \;
+
+ find "$INK_APP_LIB_DIR/python$INK_PYTHON_VER/site-packages/numpy" \
+ -name "*.a" -delete
+}
+
+function ink_pipinstall_pygobject
+{
+ lib_change_paths \
+ @loader_path/../../.. \
+ "$INK_APP_LIB_DIR" \
+ "$INK_APP_SPK_DIR"/gi/_gi.cpython-"${INK_PYTHON_VER/./}"-darwin.so \
+ "$INK_APP_SPK_DIR"/gi/_gi_cairo.cpython-"${INK_PYTHON_VER/./}"-darwin.so \
+ "$INK_APP_SPK_DIR"/cairo/_cairo.cpython-"${INK_PYTHON_VER/./}"-darwin.so
+}
+
+function ink_pipinstall_pyserial
+{
+ find "$INK_APP_SPK_DIR"/serial -type f -name "*.pyc" -exec rm {} \;
+ sed -i '' '1s|.*|#!/usr/bin/env python3|' \
+ "$INK_APP_BIN_DIR"/pyserial-miniterm
+ sed -i '' '1s|.*|#!/usr/bin/env python3|' "$INK_APP_BIN_DIR"/pyserial-ports
+}
+
+function ink_pipinstall_scour
+{
+ sed -i '' '1s|.*|#!/usr/bin/env python3|' "$INK_APP_BIN_DIR"/scour
+}
+
+function ink_download_python
+{
+ curl -o "$PKG_DIR"/"$(basename "${INK_PYTHON_URL%\?*}")" -L "$INK_PYTHON_URL"
+ curl -o "$PKG_DIR"/"$(basename "$INK_PYTHON_ICON_URL")" \
+ -L "$INK_PYTHON_ICON_URL"
+}
+
+function ink_install_python
+{
+ mkdir "$INK_APP_FRA_DIR"
+ tar -C "$INK_APP_FRA_DIR" -xf "$PKG_DIR"/"$(basename "${INK_PYTHON_URL%\?*}")"
+
+ # link it to INK_APP_BIN_DIR so it'll be in PATH for the app
+ mkdir -p "$INK_APP_BIN_DIR"
+ # shellcheck disable=SC2086 # it's an integer
+ ln -sf ../../Frameworks/Python.framework/Versions/Current/bin/\
+python$INK_PYTHON_VER_MAJOR "$INK_APP_BIN_DIR"
+
+ # create '.pth' file inside Framework to include our site-packages directory
+ # shellcheck disable=SC2086 # it's an integer
+ echo "../../../../../../../Resources/lib/python$INK_PYTHON_VER/site-packages"\
+ > "$INK_APP_FRA_DIR"/Python.framework/Versions/Current/lib/\
+python$INK_PYTHON_VER/site-packages/inkscape.pth
+
+ # use custom icon for Python.app
+ svg2icns \
+ "$PKG_DIR/$(basename "$INK_PYTHON_ICON_URL")" \
+ "$INK_APP_FRA_DIR/Python.framework/Resources/Python.app/Contents/\
+Resources/PythonInterpreter.icns" \
+ 8
+}
+
+function ink_build_wheels
+{
+ jhb run pip3 install wheel
+
+ for package_set in ${!INK_PYTHON_PKG_*}; do
+ local packages
+ for package in $(eval echo \$"$package_set"); do
+ if [ "${package::8}" = "https://" ]; then
+ curl -L -o "$PKG_DIR/$(basename "$package")" "$package"
+ else
+ packages="$packages $package"
+ fi
+ done
+
+ if [ -n "$packages" ]; then
+ # shellcheck disable=SC2086 # we need word splitting here
+ jhb run pip3 wheel --no-binary :all: $packages -w "$PKG_DIR"
+ packages=""
+ fi
+ done
+}
+
+### main #######################################################################
+
+# Nothing here.
diff --git a/packaging/macos/src/inkscape.bundle b/packaging/macos/src/inkscape.bundle
new file mode 100644
index 0000000..892963b
--- /dev/null
+++ b/packaging/macos/src/inkscape.bundle
@@ -0,0 +1,181 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<app-bundle>
+
+ <meta>
+ <!-- Where to pick up the GTK+ installation, icon themes,
+ etc. Note that "${env:JHBUILD_PREFIX}" is evaluated to the
+ value of the environment variable JHBUILD_PREFIX. You can
+ define additional prefixes and refer to them in paths
+ throughout this file on the form "${prefix:name}". This is
+ useful for installing certain libraries or even the
+ application itself separately. Note that JHBUILD_PREFIX is
+ defined by jhbuild, so it you are not using jhbuild you can
+ either define your own or just hardcode the path here.
+ -->
+ <prefix name="default">${env:JHBUILD_PREFIX}</prefix>
+
+ <!-- The project directory is the default location of the created
+ app. If you leave out the path, the current directory is
+ used. Note the usage of an environment variable here again.
+ -->
+ <destination overwrite="yes">${env:ARTIFACT_DIR}</destination>
+
+ <image>
+ <!-- Not implemented yet (DMG image). -->
+ </image>
+
+ <!-- Comment this out to keep the install names in binaries -->
+ <run-install-name-tool/>
+
+ <!-- Optionally specify a launcher script to use. If the
+ application sets up everything needed itself, like
+ environment variable, linker paths, etc, a launcher script is
+ not needed. If the source path is left out, the default
+ script will be used.
+ <launcher-script>${project}/gtk3-launcher.sh</launcher-script >
+ -->
+
+ <!-- Not implemented: Optional runtime, could be python or mono
+ for example.
+ -->
+ <!-- runtime copy="yes">/usr/bin/python</runtime -->
+ <!-- Indicate the active gtk version to use. This is needed only
+ for gtk+-3.0 projects. -->
+ <gtk>gtk+-3.0</gtk>
+ </meta>
+
+ <!-- The special macro "${project}" refers to the directory where
+ this bundle file is located. The application name and bundle
+ identifier are taken from the plist file.
+ -->
+ <plist>${project}/inkscape.plist</plist>
+
+ <main-binary>${prefix}/bin/inkscape</main-binary>
+
+ <!-- Copy in the input methods. Dunno if they actually work with
+ OSX. Note the ${gtkdir} macro, which expands to the correct
+ library subdirectory for the specified gtk version. -->
+ <binary>
+ ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/immodules/*.so
+ </binary>
+
+<!-- And the print backends -->
+ <binary>
+ ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/printbackends/*.so
+ </binary>
+
+<!-- Starting with 2.24, gdk-pixbuf installs into its own directory. -->
+ <binary>
+ ${prefix}/lib/gdk-pixbuf-2.0/${pkg:gdk-pixbuf-2.0:gdk_pixbuf_binary_version}/loaders/*.so
+ </binary>
+
+<!-- No longer needed for pango >= 1.38
+ <binary>
+ ${prefix}/lib/pango/${pkg:pango:pango_module_version}/modules/
+ </binary>
+-->
+ <binary>
+ ${prefix}/lib/inkscape/libinkscape_base.dylib
+ </binary>
+ <binary>
+ ${prefix}/lib/libexslt.0.dylib
+ </binary>
+ <binary>
+ ${prefix}/lib/libssl.1.1.dylib
+ </binary>
+ <binary>
+ ${prefix}/lib/gio/modules/*.so
+ </binary>
+ <binary>
+ ${prefix}/lib/enchant-2/*.so
+ </binary>
+ <!-- Ghostscript (disable this for GPLv2+ compliance!) -->
+ <binary>
+ ${prefix}/bin/gs
+ </binary>
+ <data>
+ ${prefix}/share/ghostscript
+ </data>
+ <data>
+ ${prefix}/bin/ps2pdf*
+ </data>
+ <!-- GObject Introspection -->
+ <binary>
+ ${prefix}/lib/libgirepository-1.0.1.dylib
+ </binary>
+ <gir>
+ ${prefix}/share/gir-1.0/*.gir
+ </gir>
+ <!-- WebP Codec -->
+ <binary>
+ ${prefix}/lib/libwebp.7.dylib
+ </binary>
+ <binary>
+ ${prefix}/lib/libwebpmux.3.dylib
+ </binary>
+ <binary>
+ ${prefix}/lib/libwebpdemux.2.dylib
+ </binary>
+ <!-- Translation filenames, one for each program or library that you
+ want to copy in to the bundle. The "dest" attribute is
+ optional, as usual. Bundler will find all translations of that
+ library/program under the indicated directory and copy them.-->
+ <translations name="gdk-pixbuf">
+ ${prefix}/share/locale
+ </translations>
+ <translations name="gtk30">
+ ${prefix}/share/locale
+ </translations>
+ <translations name="gtk30-properties">
+ ${prefix}/share/locale
+ </translations>
+ <translations name="inkscape">
+ ${prefix}/share/locale
+ </translations>
+
+ <!-- Data to copy in, usually Glade/UI files, images, sounds files
+ etc. The destination inside the bundle can be specified if the
+ files should end up at a different location, by using the
+ "dest" property. The destination must then start with the macro
+ "${bundle}", which refers to the bundle root directory.
+ -->
+ <!-- data>
+ ${prefix}/share/gtk3-demo
+ </data -->
+
+ <data>
+ ${prefix}/etc/fonts
+ </data>
+ <data>
+ ${prefix}/share/enchant
+ </data>
+ <data>
+ ${prefix}/share/fontconfig
+ </data>
+ <data>
+ ${prefix}/share/glib-2.0
+ </data>
+ <data>
+ ${prefix}/share/icons
+ </data>
+ <data>
+ ${prefix}/share/ImageMagick-6
+ </data>
+ <data>
+ ${prefix}/share/inkscape
+ </data>
+ <!-- Copy in the themes data. You may want to trim this to save space
+ in your bundle. -->
+ <data>
+ ${prefix}/share/themes
+ </data>
+
+ <!-- Copy icons. Note that the .icns file is an Apple format which
+ contains up to 4 sizes of icon. You can use
+ /Developer/Applications/Utilities/Icon Composer.app to import
+ artwork and create the file. >
+ <data dest="${bundle}/Contents/Resources">
+ ${project}/Giggle.icns
+ </data -->
+
+ </app-bundle>
diff --git a/packaging/macos/src/inkscape_dmg.py b/packaging/macos/src/inkscape_dmg.py
new file mode 100644
index 0000000..8a51d8b
--- /dev/null
+++ b/packaging/macos/src/inkscape_dmg.py
@@ -0,0 +1,246 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+import biplist
+import os.path
+
+#
+# Example settings file for dmgbuild
+#
+
+# Use like this: dmgbuild -s settings.py "Test Volume" test.dmg
+
+# You can actually use this file for your own application (not just TextEdit)
+# by doing e.g.
+#
+# dmgbuild -s settings.py -D app=/path/to/My.app "My Application" MyApp.dmg
+
+# .. Useful stuff ..............................................................
+
+application = defines.get('app', 'PLACEHOLDERAPPLICATION')
+appname = os.path.basename(application)
+
+def icon_from_app(app_path):
+ plist_path = os.path.join(app_path, 'Contents', 'Info.plist')
+ plist = biplist.readPlist(plist_path)
+ icon_name = plist['CFBundleIconFile']
+ icon_root,icon_ext = os.path.splitext(icon_name)
+ if not icon_ext:
+ icon_ext = '.icns'
+ icon_name = icon_root + icon_ext
+ return os.path.join(app_path, 'Contents', 'Resources', icon_name)
+
+# .. Basics ....................................................................
+
+# Uncomment to override the output filename
+# filename = 'test.dmg'
+
+# Uncomment to override the output volume name
+# volume_name = 'Test'
+
+# Volume format (see hdiutil create -help)
+format = defines.get('format', 'UDBZ')
+
+# Volume size
+size = defines.get('size', None)
+
+# Files to include
+files = [ application ]
+
+# Symlinks to create
+#symlinks = { 'Applications': '/Applications' }
+
+# Volume icon
+#
+# You can either define icon, in which case that icon file will be copied to the
+# image, *or* you can define badge_icon, in which case the icon file you specify
+# will be used to badge the system's Removable Disk icon
+#
+#icon = 'PLACEHOLDERICON'
+badge_icon = icon_from_app(application)
+
+# Where to put the icons
+icon_locations = {
+ appname: (390, 240),
+# 'Applications': (500, 120)
+ }
+
+# .. Window configuration ......................................................
+
+# Background
+#
+# This is a STRING containing any of the following:
+#
+# #3344ff - web-style RGB color
+# #34f - web-style RGB color, short form (#34f == #3344ff)
+# rgb(1,0,0) - RGB color, each value is between 0 and 1
+# hsl(120,1,.5) - HSL (hue saturation lightness) color
+# hwb(300,0,0) - HWB (hue whiteness blackness) color
+# cmyk(0,1,0,0) - CMYK color
+# goldenrod - X11/SVG named color
+# builtin-arrow - A simple built-in background with a blue arrow
+# /foo/bar/baz.png - The path to an image file
+#
+# The hue component in hsl() and hwb() may include a unit; it defaults to
+# degrees ('deg'), but also supports radians ('rad') and gradians ('grad'
+# or 'gon').
+#
+# Other color components may be expressed either in the range 0 to 1, or
+# as percentages (e.g. 60% is equivalent to 0.6).
+background = 'PLACEHOLDERBACKGROUND'
+
+show_status_bar = False
+show_tab_view = False
+show_toolbar = False
+show_pathbar = False
+show_sidebar = False
+sidebar_width = 180
+
+# Window position in ((x, y), (w, h)) format
+window_rect = ((100, 100), (500, 380))
+
+# Select the default view; must be one of
+#
+# 'icon-view'
+# 'list-view'
+# 'column-view'
+# 'coverflow'
+#
+default_view = 'icon-view'
+
+# General view configuration
+show_icon_preview = False
+
+# Set these to True to force inclusion of icon/list view settings (otherwise
+# we only include settings for the default view)
+include_icon_view_settings = 'auto'
+include_list_view_settings = 'auto'
+
+# .. Icon view configuration ...................................................
+
+arrange_by = None
+grid_offset = (0, 0)
+grid_spacing = 100
+scroll_position = (0, 0)
+label_pos = 'bottom' # or 'right'
+text_size = 12
+icon_size = 64
+
+# .. List view configuration ...................................................
+
+# Column names are as follows:
+#
+# name
+# date-modified
+# date-created
+# date-added
+# date-last-opened
+# size
+# kind
+# label
+# version
+# comments
+#
+list_icon_size = 16
+list_text_size = 12
+list_scroll_position = (0, 0)
+list_sort_by = 'name'
+list_use_relative_dates = True
+list_calculate_all_sizes = False,
+list_columns = ('name', 'date-modified', 'size', 'kind', 'date-added')
+list_column_widths = {
+ 'name': 300,
+ 'date-modified': 181,
+ 'date-created': 181,
+ 'date-added': 181,
+ 'date-last-opened': 181,
+ 'size': 97,
+ 'kind': 115,
+ 'label': 100,
+ 'version': 75,
+ 'comments': 300,
+ }
+list_column_sort_directions = {
+ 'name': 'ascending',
+ 'date-modified': 'descending',
+ 'date-created': 'descending',
+ 'date-added': 'descending',
+ 'date-last-opened': 'descending',
+ 'size': 'descending',
+ 'kind': 'ascending',
+ 'label': 'ascending',
+ 'version': 'ascending',
+ 'comments': 'ascending',
+ }
+
+# .. License configuration .....................................................
+
+# Text in the license configuration is stored in the resources, which means
+# it gets stored in a legacy Mac encoding according to the language. dmgbuild
+# will *try* to convert Unicode strings to the appropriate encoding, *but*
+# you should be aware that Python doesn't support all of the necessary encodings;
+# in many cases you will need to encode the text yourself and use byte strings
+# instead here.
+
+# Recognized language names are:
+#
+# af_ZA, ar, be_BY, bg_BG, bn, bo, br, ca_ES, cs_CZ, cy, da_DK, de_AT, de_CH,
+# de_DE, dz_BT, el_CY, el_GR, en_AU, en_CA, en_GB, en_IE, en_SG, en_US, eo,
+# es_419, es_ES, et_EE, fa_IR, fi_FI, fo_FO, fr_001, fr_BE, fr_CA, fr_CH,
+# fr_FR, ga-Latg_IE, ga_IE, gd, grc, gu_IN, gv, he_IL, hi_IN, hr_HR, hu_HU,
+# hy_AM, is_IS, it_CH, it_IT, iu_CA, ja_JP, ka_GE, kl, ko_KR, lt_LT, lv_LV,
+# mk_MK, mr_IN, mt_MT, nb_NO, ne_NP, nl_BE, nl_NL, nn_NO, pa, pl_PL, pt_BR,
+# pt_PT, ro_RO, ru_RU, se, sk_SK, sl_SI, sr_RS, sv_SE, th_TH, to_TO, tr_TR,
+# uk_UA, ur_IN, ur_PK, uz_UZ, vi_VN, zh_CN, zh_TW
+
+# license = {
+# 'default-language': 'en_US',
+# 'licenses': {
+# # For each language, the text of the license. This can be plain text,
+# # RTF (in which case it must start "{\rtf1"), or a path to a file
+# # containing the license text. If you're using RTF,
+# # watch out for Python escaping (or read it from a file).
+# 'English': b'''{\\rtf1\\ansi\\ansicpg1252\\cocoartf1504\\cocoasubrtf820
+# {\\fonttbl\\f0\\fnil\\fcharset0 Helvetica-Bold;\\f1\\fnil\\fcharset0 Helvetica;}
+# {\\colortbl;\\red255\\green255\\blue255;\\red0\\green0\\blue0;}
+# {\\*\\expandedcolortbl;;\\cssrgb\\c0\\c0\\c0;}
+# \\paperw11905\\paperh16837\\margl1133\\margr1133\\margb1133\\margt1133
+# \\deftab720
+# \\pard\\pardeftab720\\sa160\\partightenfactor0
+
+# \\f0\\b\\fs60 \\cf2 \\expnd0\\expndtw0\\kerning0
+# \\up0 \\nosupersub \\ulnone \\outl0\\strokewidth0 \\strokec2 Test License\\
+# \\pard\\pardeftab720\\sa160\\partightenfactor0
+
+# \\fs36 \\cf2 \\strokec2 What is this?\\
+# \\pard\\pardeftab720\\sa160\\partightenfactor0
+
+# \\f1\\b0\\fs22 \\cf2 \\strokec2 This is the English license. It says what you are allowed to do with this software.\\
+# \\
+# }''',
+# },
+# 'buttons': {
+# # For each language, text for the buttons on the licensing window.
+# #
+# # Default buttons and text are built-in for the following languages:
+# #
+# # English (en_US), German (de_DE), Spanish (es_ES), French (fr_FR),
+# # Italian (it_IT), Japanese (ja_JP), Dutch (nl_NL), Swedish (sv_SE),
+# # Brazilian Portuguese (pt_BR), Simplified Chinese (zh_CN),
+# # Traditional Chinese (zh_TW), Danish (da_DK), Finnish (fi_FI),
+# # Korean (ko_KR), Norwegian (nb_NO)
+# #
+# # You don't need to specify them for those languages; if you fail to
+# # specify them for some other language, English will be used instead.
+
+# 'en_US': (
+# b'English',
+# b'Agree',
+# b'Disagree',
+# b'Print',
+# b'Save',
+# b'If you agree with the terms of this license, press "Agree" to '
+# b'install the software. If you do not agree, press "Disagree".'
+# ),
+# },
+# }
diff --git a/packaging/macos/src/jhb-custom.conf.sh b/packaging/macos/src/jhb-custom.conf.sh
new file mode 100644
index 0000000..d4d7b2b
--- /dev/null
+++ b/packaging/macos/src/jhb-custom.conf.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+#
+# SPDX-FileCopyrightText: 2022 René de Hesselle <dehesselle@web.de>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+### description ################################################################
+
+# Custom configuration for jhb.
+
+### shellcheck #################################################################
+
+# shellcheck disable=SC2034 # no unused variables
+
+### dependencies ###############################################################
+
+# Nothing here.
+
+### variables ##################################################################
+
+VERSION=0.69
+VER_DIR_TEMPLATE="\$WRK_DIR/mibap-\$VERSION"
+
+RELEASE_ARCHIVE=mibap-"$VERSION"_$(uname -m).dmg
+
+# GitHub: https://github.com/dehesselle/mibap
+# GitLab: https://gitlab.com/inkscape/devel/mibap
+RELEASE_URLS=(
+ "https://github.com/dehesselle/mibap/releases/download/\
+v$VERSION/$RELEASE_ARCHIVE"
+ "https://gitlab.com/api/v4/projects/15865869/packages/generic/mibap/\
+$VERSION/$RELEASE_ARCHIVE"
+)
+
+### functions ##################################################################
+
+# Nothing here.
+
+### main #######################################################################
+
+# Nothing here.
diff --git a/packaging/macos/src/png2icns.sh b/packaging/macos/src/png2icns.sh
new file mode 100644
index 0000000..9781781
--- /dev/null
+++ b/packaging/macos/src/png2icns.sh
@@ -0,0 +1,37 @@
+# SPDX-FileCopyrightText: 2021 René de Hesselle <dehesselle@web.de>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+### description ################################################################
+
+# Convert png to icns.
+
+### shellcheck #################################################################
+
+# shellcheck shell=bash # no shebang as this file is intended to be sourced
+
+### dependencies ###############################################################
+
+# Nothing here.
+
+### variables ##################################################################
+
+# https://github.com/bitboss-ca/png2icns
+PNG2ICNS_VER=0.1
+PNG2ICNS_URL=https://github.com/bitboss-ca/png2icns/archive/\
+v$PNG2ICNS_VER.tar.gz
+
+### functions ##################################################################
+
+function png2icns_install
+{
+ local archive
+ archive=$PKG_DIR/$(basename $PNG2ICNS_URL)
+ curl -o "$archive" -L "$PNG2ICNS_URL"
+ tar -C "$SRC_DIR" -xf "$archive"
+ ln -s "$SRC_DIR"/png2icns-$PNG2ICNS_VER/png2icns.sh "$BIN_DIR"
+}
+
+### main #######################################################################
+
+# Nothing here. \ No newline at end of file
diff --git a/packaging/macos/src/svg2icns.sh b/packaging/macos/src/svg2icns.sh
new file mode 100644
index 0000000..c072646
--- /dev/null
+++ b/packaging/macos/src/svg2icns.sh
@@ -0,0 +1,56 @@
+# SPDX-FileCopyrightText: 2021 René de Hesselle <dehesselle@web.de>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+### description ################################################################
+
+# Convert svg to icns. This is the "wrapper" that utilizes/requires caivrosvg
+# and png2icns packages.
+
+### shellcheck #################################################################
+
+# shellcheck shell=bash # no shebang as this file is intended to be sourced
+
+### dependencies ###############################################################
+
+source "$(dirname "${BASH_SOURCE[0]}")"/cairosvg.sh
+source "$(dirname "${BASH_SOURCE[0]}")"/png2icns.sh
+
+### variables ##################################################################
+
+# Nothing here.
+
+### functions ##################################################################
+
+function svg2icns_install
+{
+ cairosvg_install
+ png2icns_install
+}
+
+function svg2icns
+{
+ local svg_file=$1
+ local icns_file=$2
+ local scale=$3 # optional
+
+ if [ -z "$scale" ]; then
+ scale=1
+ fi
+
+ local png_file
+ png_file=$TMP_DIR/$(basename -s .svg "$svg_file").png
+
+ # svg to png
+ jhb run cairosvg -f png -s $scale -o "$png_file" "$svg_file"
+
+ # png to icns
+ cd "$TMP_DIR" || exit 1 # png2icns.sh outputs to current directory
+ png2icns.sh "$png_file"
+
+ mv "$(basename -s .png "$png_file")".icns "$icns_file"
+}
+
+### main #######################################################################
+
+# Nothing here. \ No newline at end of file