1
0
Fork 0
inkscape/buildtools/media-check-icons.py
Daniel Baumann 02d935e272
Adding upstream version 1.4.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 23:40:13 +02:00

198 lines
6.6 KiB
Python
Executable file

#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
# Icon checker: test that icon themes contain all needed icons
# Author: Martin Owens <doctormo@geek-2.com>
# Licensed under GPL version 2 or any later version, read the file "COPYING" for more information.
import fnmatch
import os
import sys
from collections import defaultdict
THEME_PATH = os.path.join('.', 'share', 'icons')
IGNORE_THEMES = [
'application',
'Tango',
]
IGNORE_ICONS = [
# These are hard coded as symbolic in the gtk source code
'list-add-symbolic.svg',
'list-add.svg',
'list-remove-symbolic.svg',
'list-remove.svg',
'accessories-character-map.svg',
'accessories-character-map-symbolic.svg',
'applications-graphics.svg',
'applications-graphics-symbolic.svg',
'dialog-information.svg',
'dialog-information-symbolic.svg',
'edit-find.svg',
'edit-find-symbolic.svg',
'folder-open.svg',
'folder-open-symbolic.svg',
'tools-check-spelling.svg',
'tools-check-spelling-symbolic.svg',
'dialog-warning.svg',
'dialog-warning-symbolic.svg',
'format-justify-center.svg',
'format-justify-center-symbolic.svg',
'format-justify-fill.svg',
'format-justify-fill-symbolic.svg',
'format-justify-left.svg',
'format-justify-left-symbolic.svg',
'format-justify-right.svg',
'format-justify-right-symbolic.svg',
'dialog-warning-symbolic.svg',
'edit-clear.svg',
'edit-clear-symbolic.svg',
'view-refresh-symbolic.svg',
'view-refresh.svg',
# Those are illustrations rather than icons
'feBlend-icon-symbolic.svg',
'feColorMatrix-icon-symbolic.svg',
'feComponentTransfer-icon-symbolic.svg',
'feComposite-icon-symbolic.svg',
'feConvolveMatrix-icon-symbolic.svg',
'feDiffuseLighting-icon-symbolic.svg',
'feDisplacementMap-icon-symbolic.svg',
'feFlood-icon-symbolic.svg',
'feGaussianBlur-icon-symbolic.svg',
'feImage-icon-symbolic.svg',
'feMerge-icon-symbolic.svg',
'feMorphology-icon-symbolic.svg',
'feOffset-icon-symbolic.svg',
'feSpecularLighting-icon-symbolic.svg',
'feTile-icon-symbolic.svg',
'feTurbulence-icon-symbolic.svg',
'feBlend-icon.svg',
'feColorMatrix-icon.svg',
'feComponentTransfer-icon.svg',
'feComposite-icon.svg',
'feConvolveMatrix-icon.svg',
'feDiffuseLighting-icon.svg',
'feDisplacementMap-icon.svg',
'feFlood-icon.svg',
'feGaussianBlur-icon.svg',
'feImage-icon.svg',
'feMerge-icon.svg',
'feMorphology-icon.svg',
'feOffset-icon.svg',
'feSpecularLighting-icon.svg',
'feTile-icon.svg',
'feTurbulence-icon.svg',
]
NO_PROBLEM,\
BAD_SYMBOLIC_NAME,\
BAD_SCALABLE_NAME,\
MISSING_FROM,\
ONLY_FOUND_IN = range(5)
def icon_themes():
for name in os.listdir(THEME_PATH):
filename = os.path.join(THEME_PATH, name)
if name in IGNORE_THEMES or not os.path.isdir(filename):
continue
yield name, filename
def find_errors_in(themes):
data = defaultdict(set)
bad_symbolic = []
bad_scalable = []
names = set()
for name, path in themes:
for root, dirs, files in os.walk(path):
orig = root
root = root[len(path)+1:]
if '/' not in root:
continue
(kind, root) = root.split('/', 1)
if kind not in ("symbolic", "scalable"):
continue # Not testing cursors, maybe later.
theme_name = f"{name}-{kind}"
names.add(theme_name)
for fname in files:
if fname in IGNORE_ICONS:
continue
if not fname.endswith('.svg'):
continue
if kind == "symbolic":
if not fname.endswith('-symbolic.svg'):
bad_symbolic.append(os.path.join(orig, fname))
continue
else:
# Make filenames consistant for comparison
fname = fname.replace('-symbolic.svg', '.svg')
elif kind == "scalable" and fname.endswith('-symbolic.svg'):
bad_scalable.append(os.path.join(orig, fname))
continue
filename = os.path.join(root, fname)
data[filename].add(theme_name)
if bad_symbolic:
yield BAD_SYMBOLIC_NAME, bad_symbolic
if bad_scalable:
yield BAD_SCALABLE_NAME, bad_scalable
only_found_in = defaultdict(list)
missing_from = defaultdict(list)
for filename in sorted(data):
datum = data[filename]
if datum == names:
continue
elif len(datum) == 1:
only_found_in[list(datum)[0]].append(filename)
continue
for theme in (names - datum):
missing_from[theme].append(filename)
if only_found_in:
yield ONLY_FOUND_IN, only_found_in
if missing_from:
yield MISSING_FROM, missing_from
if __name__ == '__main__':
errors = list(find_errors_in(icon_themes()))
if errors:
count = 0
for error, themes in errors:
if isinstance(themes, list):
count += len(themes)
elif isinstance(themes, dict):
count += sum([len(v) for v in themes.values()])
sys.stderr.write(f" == {count} problems found in icon themes! == \n\n")
for error, themes in errors:
if error is BAD_SCALABLE_NAME:
sys.stderr.write(f"Scalable themes should not have symbolic icons in them (They end with -symbolic.svg so won't be used):\n")
for name in themes:
sys.stderr.write(f" - {name}\n")
sys.stderr.write("\n")
elif error is BAD_SYMBOLIC_NAME:
sys.stderr.write(f"Symbolic themes should only have symbolic icons in them (They don't end with -symbolic.svg so can't be used):\n")
for name in themes:
sys.stderr.write(f" - {name}\n")
sys.stderr.write("\n")
elif error is MISSING_FROM:
for theme in themes:
sys.stderr.write(f"Icons missing from {theme}:\n")
for name in themes[theme]:
sys.stderr.write(f" - {name}\n")
sys.stderr.write("\n")
elif error is ONLY_FOUND_IN:
for theme in themes:
sys.stderr.write(f"Icons only found in {theme}:\n")
for name in themes[theme]:
sys.stderr.write(f" + {name}\n")
sys.stderr.write("\n")
else:
pass
sys.exit(5)
# vi:sw=4:expandtab: