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'] )