Skip to content

Instantly share code, notes, and snippets.

@bkw777
Last active July 14, 2025 15:37
Show Gist options
  • Save bkw777/b1de087799134f2d13ec81805cb0e2ac to your computer and use it in GitHub Desktop.
Save bkw777/b1de087799134f2d13ec81805cb0e2ac to your computer and use it in GitHub Desktop.
FreeCAD AppImage desktop integration
#!/bin/bash
#h
#h install_freecad_appimage.sh
#h
#h Configures desktop integration for a FreeCAD AppImage.
#h * copies FreeCad*.AppImage to ~/.local/bin/freecad
#h * installs mime-type, .desktop, and icon under ~/.local/share
#h All files installed in $HOME. No sudo needed.
#h Brian K. White <[email protected]>
#h
#h Usage:
#h $0
#h $0 /path/or/url/to/*.AppImage
#h $0 -r|--remove
#h $0 -h|--help
#h
#h Installs FreeCAD*.AppImage from current dir or specified file or url
#h
#h -r, --remove = Uninstall
#h -h, --help = This help
#h
# TODO
# - verify download, ex: https://ar.al/2021/11/24/the-magic-one-line-imagemagick-7-appimage-installer/
# - extract and install symlink to AppRun instead of installing appimage itself as executable
# - use package .svg
# - use package .desktop (may still ignore the packages ideas for mimetype & icon)
# - option to install to system or user
# - genericize to support other apps besides FreeCAD
# - reorganize into functions
# - replace awk with bash, remove awk dep
# - support curl/wget/aria2c (more?)
# - xdg-open browser to download page
# - update options: delete & replace, side-by-side versions, dirty overwrite w/o delete
N=FreeCAD
n=${N,,}
t="application/x-$n"
g='*.fc*'
p="$HOME/.profile"
l="$HOME/.local"
s="$l/share"
b="$l/bin"
_m=$s/mime
m=$_m/packages/${n}.xml
ih=icons/hicolor
_i=$s/$ih
in=${t//\//-}
i=$_i/scalable/mimetypes/${in}.svg
d=$s/applications/${N}.desktop
e=$b/$n
case $1 in
-h|--help|-\?)
awk -v n=$0 '/^#h /{$1="";sub(/\$0/,n);print $0}' $0
exit
;;
-r|--remove)
rm -v $m $i $d $e
update-mime-database $_m
update-icon-caches $_i
exit
;;
esac
# add search path for icons
[[ ":$XDG_DATA_DIRS:" =~ ":$s:" ]] || {
printf 'XDG_DATA_DIRS does not include %s\n' "$s"
. $p
[[ ":$XDG_DATA_DIRS:" =~ ":$s:" ]] || {
printf 'Adding "%s" to XDG_DATA_DIRS in $p\n' "$s"
printf '# %(%Y%m%d)T %s: Let *.desktop find icons in ~/.local\nXDG_DATA_DIRS="%s"\n' -1 $0 "$s${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}" >> $p
}
printf '%s is updated.\n' "$p"
echo "Log out & back in for the search path update to take effect."
echo "Then run this script again to proceed."
exit
}
# executable
mkdir -p ${e%/*}
unset a
[[ -f "$1" ]] && a=$1
[[ -z "$a" && "$1" =~ "^http*://*.AppImage" ]] && wget $1
[[ "$a" ]] || {
f=(${N}*.AppImage)
[[ "${f[0]}" == "${N}\*.AppImage" ]] || a=${f[0]}
}
[[ "$a" ]] || {
echo "Download an AppImage from https://wiki.freecad.org/AppImage"
exit
}
cp -vf $a $e
chmod -v 755 $e
# mimetype
echo "writing $m"
mkdir -p ${m%/*}
cat > $m <<-%%EOF
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
<mime-type type="$t">
<!-- <sub-class-of type="application/zip"/> -->
<comment>$N document files</comment>
<glob pattern="$g"/>
</mime-type>
</mime-info>
%%EOF
update-mime-database $_m
# icon
echo "writing $i"
mkdir -p ${i%/*}
cat > $i <<-%%EOF
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="48"
height="48"
viewBox="0 0 48 48"
version="1.1"
id="svg1"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<title id="title11">$N</title>
<defs id="defs1" />
<g id="g1" transform="matrix(2,0,0,2,0.11243557,0)">
<path
d="m 22,3.9997423 -3.999742,4.0002581 h -8 V 10.999806 H 14 v 4.000259 h -3.999742 v 4.999678 L 5.9999997,24 h 4.0503843 c 0.30326,-1e-6 0.571883,-0.195269 0.66559,-0.48369 l 0.723985,-2.22828 c 0.06925,-0.213087 0.236489,-0.379833 0.449583,-0.449065 l 0.556553,-0.180868 c 0.213108,-0.06926 0.446577,-0.03248 0.627866,0.09922 l 1.894968,1.377173 c 0.245331,0.178232 0.57787,0.178229 0.823203,0 l 1.698598,-1.234547 c 0.245363,-0.178242 0.347963,-0.493948 0.254247,-0.782378 l -0.723984,-2.22828 c -0.06926,-0.213109 -0.03197,-0.446575 0.09974,-0.627866 l 0.344164,-0.473355 c 0.131697,-0.181276 0.34179,-0.288856 0.565855,-0.28887 l 2.343001,5.1e-4 c 0.303278,10e-6 0.571885,-0.19577 0.66559,-0.484207 l 0.649054,-1.996771 c 0.0937,-0.288413 -0.0089,-0.60465 -0.254247,-0.782895 L 19.538664,11.858666 C 19.357381,11.726957 19.250306,11.516889 19.250311,11.292812 V 10.70732 c 1.9e-5,-0.224072 0.107062,-0.434681 0.288353,-0.566372 L 21.711646,8.5622376 C 21.892924,8.4305313 21.999999,8.219938 22,7.9958659 Z"
style="fill:#418fde;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.64567;stroke-linecap:square"
id="path8" />
<path
id="path7"
style="display:inline;fill:#ff585d;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.64567;stroke-linecap:square"
d="m 18,0 -4,4 h 4 V 8 L 22,4 V 0 Z M 6,16 2,20 v 4 h 4 l 4,-4 H 6 Z" />
<path
d="M 6,0 2,4 V 20 L 6,16 V 4 h 8 l 4,-4 z"
style="fill:#cb333b;fill-rule:evenodd;stroke-width:2.64567;stroke-linecap:square"
id="path3" />
<path
d="M 5.9999997,19.999743 H 10.000258 V 15.000065 H 14 V 10.999806 H 10.000258 V 8.0000004 h 8 V 3.9997423 H 5.9999997 Z"
style="fill:#fefefe;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.64567;stroke-linecap:square"
id="path9" />
</g>
<metadata id="metadata11">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:title>$N</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
</svg>
%%EOF
it=$ih/index.theme
[[ -e $s/$it ]] || ln -sf /usr/share/$it $s/$it
update-icon-caches $_i
# .desktop
echo "writing $d"
mkdir -p ${d%/*}
cat > $d <<-%%EOF
[Desktop Entry]
Name=$N
Exec=$n - --single-instance %F
Terminal=false
Type=Application
Categories=Graphics;Science;Education;Engineering;X-CNC;
StartupNotify=true
StartupWMClass=$N
Icon=$in
MimeType=$t;model/obj;image/vnd.dwg;image/vnd.dxf;model/vnd.collada+xml;application/iges;model/iges;model/step;model/step+zip;model/stl;application/vnd.shp;model/vrml;
%%EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment