diff --git a/data/icons/generate_icons.py b/data/icons/generate_icons.py
new file mode 100644
index 00000000..73437979
--- /dev/null
+++ b/data/icons/generate_icons.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python3
+import argparse
+import contextlib
+import pathlib
+import shutil
+import subprocess
+import tempfile
+
+SIZES = [16, 24, 32, 40, 48, 64, 96, 128, 256]
+
+
+def run(cmd):
+ subprocess.run(cmd, check=True)
+
+
+def try_run(cmd):
+ result = subprocess.run(cmd, text=True, capture_output=True)
+ return result.returncode == 0, result.stderr.strip()
+
+
+def magick_cmd():
+ magick = shutil.which('magick')
+ if not magick:
+ raise RuntimeError('missing tool: install ImageMagick (magick)')
+ return magick
+
+
+@contextlib.contextmanager
+def magick_svg(svg):
+ text = pathlib.Path(svg).read_text(encoding='utf-8')
+ fixed = text.replace('href="image/', 'href="data:image/')
+ fixed = fixed.replace('xlink:href="image/', 'xlink:href="data:image/')
+ if fixed == text:
+ yield str(svg)
+ return
+ with tempfile.NamedTemporaryFile('w', suffix='.svg', delete=False, encoding='utf-8') as tmp:
+ tmp.write(fixed)
+ tmp_path = tmp.name
+ try:
+ yield tmp_path
+ finally:
+ pathlib.Path(tmp_path).unlink(missing_ok=True)
+
+
+def render_png(svg, out_png, size):
+ errors = []
+ rsvg = shutil.which('rsvg-convert')
+ if rsvg:
+ ok, err = try_run([rsvg, '-w', str(size), '-h', str(size), '-o', str(out_png), str(svg)])
+ if ok:
+ return
+ errors.append(err)
+ inkscape = shutil.which('inkscape')
+ if inkscape:
+ ok, err = try_run([
+ inkscape,
+ str(svg),
+ '--export-type=png',
+ '--export-width',
+ str(size),
+ '--export-height',
+ str(size),
+ '--export-filename',
+ str(out_png),
+ ])
+ if ok:
+ return
+ errors.append(err)
+ with magick_svg(svg) as svg_for_magick:
+ ok, err = try_run([
+ magick_cmd(),
+ svg_for_magick,
+ '-background',
+ 'none',
+ '-resize',
+ f'{size}x{size}',
+ str(out_png),
+ ])
+ if ok:
+ return
+ errors.append(err)
+ raise RuntimeError('failed to render png: ' + ' | '.join(e for e in errors if e))
+
+
+def build_ico(svg, out_ico):
+ with magick_svg(svg) as svg_for_magick:
+ run([
+ magick_cmd(),
+ svg_for_magick,
+ '-background',
+ 'none',
+ '-define',
+ 'icon:auto-resize=' + ','.join(str(size) for size in SIZES),
+ str(out_ico),
+ ])
+
+
+def parse_args():
+ parser = argparse.ArgumentParser(prog='generate_icons.py')
+ parser.add_argument('input_svg')
+ parser.add_argument('output_png')
+ parser.add_argument('--ico', dest='output_ico')
+ parser.add_argument('--size', type=int, default=48)
+ return parser.parse_args()
+
+
+def main():
+ args = parse_args()
+ magick_cmd()
+ svg = pathlib.Path(args.input_svg)
+ out_png = pathlib.Path(args.output_png)
+ out_png.parent.mkdir(parents=True, exist_ok=True)
+ render_png(svg, out_png, args.size)
+ if args.output_ico:
+ out_ico = pathlib.Path(args.output_ico)
+ out_ico.parent.mkdir(parents=True, exist_ok=True)
+ build_ico(svg, out_ico)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/data/icons/meson.build b/data/icons/meson.build
index 7d4c69c2..2891c5d8 100644
--- a/data/icons/meson.build
+++ b/data/icons/meson.build
@@ -1,9 +1,24 @@
+icon_gen = find_program('generate_icons.py')
+find_program('magick', required: true)
+
icondir = join_paths(get_option('datadir'), 'icons/hicolor')
-install_data(
- 'zoitechat.png',
- rename: 'net.zoite.Zoitechat.png',
- install_dir: join_paths(icondir, '48x48/apps')
+custom_target('zoitechat_png',
+ input: 'zoitechat.svg',
+ output: 'net.zoite.Zoitechat.png',
+ command: [icon_gen, '@INPUT@', '@OUTPUT@', '--size', '48'],
+ install: true,
+ install_dir: join_paths(icondir, '48x48/apps'),
)
+
+if host_machine.system() == 'windows'
+ custom_target('zoitechat_ico',
+ input: 'zoitechat.svg',
+ output: 'zoitechat.ico',
+ command: [icon_gen, '@INPUT@', '@PRIVATE_DIR@/zoitechat.png', '--size', '48', '--ico', '@OUTPUT@'],
+ build_by_default: true,
+ )
+endif
+
install_data(
'zoitechat.svg',
rename: 'net.zoite.Zoitechat.svg',
diff --git a/data/icons/zoitechat-b.svg b/data/icons/zoitechat-b.svg
deleted file mode 100644
index eadb6ad8..00000000
--- a/data/icons/zoitechat-b.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
diff --git a/data/icons/zoitechat-shadowless.svg b/data/icons/zoitechat-shadowless.svg
deleted file mode 100644
index eadb6ad8..00000000
--- a/data/icons/zoitechat-shadowless.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
diff --git a/data/icons/zoitechat.ico b/data/icons/zoitechat.ico
deleted file mode 100644
index 72dbc9d2..00000000
Binary files a/data/icons/zoitechat.ico and /dev/null differ
diff --git a/data/icons/zoitechat.png b/data/icons/zoitechat.png
deleted file mode 100644
index f6fa675b..00000000
Binary files a/data/icons/zoitechat.png and /dev/null differ
diff --git a/data/zoitechat.gresource.xml.in b/data/zoitechat.gresource.xml.in
new file mode 100644
index 00000000..97f4dd9a
--- /dev/null
+++ b/data/zoitechat.gresource.xml.in
@@ -0,0 +1,27 @@
+
+
+
+ @ZOITECHAT_PNG@
+ icons/zoitechat.svg
+ icons/book.png
+
+ icons/ulist_voice.png
+ icons/ulist_halfop.png
+ icons/ulist_op.png
+ icons/ulist_owner.png
+ icons/ulist_founder.png
+ icons/ulist_netop.png
+
+ @ZOITECHAT_PNG@
+ icons/tray_fileoffer.png
+ icons/tray_highlight.png
+ icons/tray_message.png
+
+ icons/tree_channel.png
+ icons/tree_dialog.png
+ icons/tree_server.png
+ icons/tree_util.png
+
+
+
+
diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c
index e69ddec7..91cda164 100644
--- a/src/fe-gtk/menu.c
+++ b/src/fe-gtk/menu.c
@@ -1915,7 +1915,14 @@ menu_about (GtkWidget *wid, gpointer sess)
gtk_about_dialog_set_website_label (dialog, NULL);
gtk_about_dialog_set_license (dialog, NULL);
gtk_about_dialog_set_wrap_license (dialog, FALSE);
- gtk_about_dialog_set_logo (dialog, pix_zoitechat);
+ GdkPixbuf *about_logo;
+
+ about_logo = gdk_pixbuf_new_from_resource_at_scale ("/icons/zoitechat.svg", 48, 48, TRUE, NULL);
+ if (!about_logo && pix_zoitechat)
+ about_logo = gdk_pixbuf_scale_simple (pix_zoitechat, 48, 48, GDK_INTERP_BILINEAR);
+ gtk_about_dialog_set_logo (dialog, about_logo ? about_logo : pix_zoitechat);
+ if (about_logo)
+ g_object_unref (about_logo);
gtk_about_dialog_set_copyright (dialog, "\302\251 1998-2010 Peter \305\275elezn\303\275\n\302\251 2009-2014 Berke Viktor\n\302\251 2015-2025 Patrick Griffis\n\302\251 2026 deepend");
gtk_about_dialog_set_comments (dialog, comment);
actions = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
diff --git a/src/fe-gtk/meson.build b/src/fe-gtk/meson.build
index 06b71ce0..d80609a7 100644
--- a/src/fe-gtk/meson.build
+++ b/src/fe-gtk/meson.build
@@ -117,9 +117,29 @@ if get_option('plugin')
zoitechat_gtk_sources += 'plugingui.c'
endif
+find_program('magick', required: true)
+
+zoitechat_png_generated = custom_target('zoitechat_resource_png',
+ input: '../../data/icons/zoitechat.svg',
+ output: 'zoitechat.png',
+ command: [find_program('../../data/icons/generate_icons.py'), '@INPUT@', '@OUTPUT@', '--size', '256'],
+)
+
+zoitechat_gresource_conf = configuration_data()
+zoitechat_gresource_conf.set('ZOITECHAT_PNG', 'zoitechat.png')
+zoitechat_gresource_xml = configure_file(
+ input: '../../data/zoitechat.gresource.xml.in',
+ output: 'zoitechat.gresource.xml',
+ configuration: zoitechat_gresource_conf,
+)
+
resources = gnome.compile_resources('resources',
- '../../data/zoitechat.gresource.xml',
- source_dir: '../../data',
+ zoitechat_gresource_xml,
+ source_dir: [
+ meson.current_build_dir(),
+ '../../data',
+ ],
+ dependencies: [zoitechat_png_generated],
c_name: 'zoitechat',
extra_args: ['--manual-register']
)