Desktop icon improvements (#1201)

This commit is contained in:
Wojtek Mach 2022-05-27 14:45:20 +02:00 committed by GitHub
parent 2fdcc60dd2
commit fc82b55dab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 66 additions and 41 deletions

View file

@ -4,4 +4,11 @@ defmodule AppBuilder do
defdelegate build_mac_app_dmg(release, options), to: AppBuilder.MacOS
defdelegate build_windows_installer(release, options), to: AppBuilder.Windows
def os do
case :os.type() do
{:unix, :darwin} -> :macos
{:win32, _} -> :windows
end
end
end

View file

@ -94,7 +94,7 @@ defmodule AppBuilder.MacOS do
Keyword.validate!(options, [
:name,
:version,
:logo_path,
:icon_path,
:info_plist,
:url_schemes,
:document_types,
@ -125,8 +125,16 @@ defmodule AppBuilder.MacOS do
launcher_src_path
])
logo_path = options[:logo_path] || Application.app_dir(:wx, "examples/demo/erlang.png")
create_logo(app_bundle_path, logo_path)
icon_path = options[:icon_path] || Application.app_dir(:wx, "examples/demo/erlang.png")
dest_path = Path.join([app_bundle_path, "Contents", "Resources", "AppIcon.icns"])
create_icon(icon_path, dest_path)
for type <- options[:document_types] || [] do
if src_path = type[:icon_path] do
dest_path = Path.join([app_bundle_path, "Contents", "Resources", "#{type.name}Icon.icns"])
create_icon(src_path, dest_path)
end
end
info_plist = options[:info_plist] || info_plist(options)
File.write!(Path.join([app_bundle_path, "Contents", "Info.plist"]), info_plist)
@ -180,15 +188,16 @@ defmodule AppBuilder.MacOS do
"""
end
defp create_logo(app_bundle_path, logo_source_path) do
logo_dest_path = Path.join([app_bundle_path, "Contents", "Resources", "AppIcon.icns"])
defp create_icon(src_path, dest_path) do
src_path = normalize_icon_path(src_path)
if Path.extname(logo_source_path) == ".icns" do
File.cp!(logo_source_path, logo_dest_path)
if Path.extname(src_path) == ".icns" do
File.cp!(src_path, dest_path)
else
logo_dest_tmp_path = "tmp/AppIcon.iconset"
File.rm_rf!(logo_dest_tmp_path)
File.mkdir_p!(logo_dest_tmp_path)
name = Path.basename(dest_path, ".icns")
dest_tmp_path = "tmp/#{name}.iconset"
File.rm_rf!(dest_tmp_path)
File.mkdir_p!(dest_tmp_path)
sizes = for(i <- [16, 32, 64, 128], j <- [1, 2], do: {i, j}) ++ [{512, 1}]
@ -200,12 +209,12 @@ defmodule AppBuilder.MacOS do
end
size = size * scale
out = "#{logo_dest_tmp_path}/icon_#{size}x#{size}#{suffix}.png"
cmd!("sips", ~w(-z #{size} #{size} #{logo_source_path} --out #{out}))
out = "#{dest_tmp_path}/icon_#{size}x#{size}#{suffix}.png"
cmd!("sips", ~w(-z #{size} #{size} #{src_path} --out #{out}))
end
cmd!("iconutil", ~w(-c icns #{logo_dest_tmp_path} -o #{logo_dest_path}))
File.rm_rf!(logo_dest_tmp_path)
cmd!("iconutil", ~w(-c icns #{dest_tmp_path} -o #{dest_path}))
File.rm_rf!(dest_tmp_path)
end
end
@ -297,6 +306,10 @@ defmodule AppBuilder.MacOS do
<string><%= ext %></string>
<% end %>
</array>
<%= if type[:icon_path] do %>
<key>CFBundleTypeIconFile</key>
<string><%= type.name %>Icon</string>
<% end %>
</dict>
<% end %>
</array>

View file

@ -66,4 +66,12 @@ defmodule AppBuilder.Utils do
"""
end
end
def normalize_icon_path(path) when is_binary(path) do
path
end
def normalize_icon_path(path_per_os) when is_list(path_per_os) do
Keyword.fetch!(path_per_os, AppBuilder.os())
end
end

View file

@ -43,7 +43,7 @@ defmodule AppBuilder.Windows do
:version,
:url_schemes,
:document_types,
:logo_path,
:icon_path,
:module
])
@ -52,9 +52,9 @@ defmodule AppBuilder.Windows do
vcredist_path = ensure_vcredistx64()
File.cp!(vcredist_path, Path.join(tmp_dir, "vcredist_x64.exe"))
logo_path = options[:logo_path] || Application.app_dir(:wx, "examples/demo/erlang.png")
icon_path = options[:icon_path] || Application.app_dir(:wx, "examples/demo/erlang.png")
app_icon_path = Path.join(tmp_dir, "app_icon.ico")
copy_image(logo_path, app_icon_path)
create_icon(icon_path, app_icon_path)
erl_exe = Path.join([tmp_dir, "rel", "erts-#{release.erts_version}", "bin", "erl.exe"])
rcedit_path = ensure_rcedit()
@ -254,14 +254,13 @@ defmodule AppBuilder.Windows do
end
defp ensure_magick do
url =
"https://download.imagemagick.org/ImageMagick/download/binaries/ImageMagick-7.1.0-portable-Q16-x64.zip"
sha256 = "b61a726cea1e3bf395b9aeb323fca062f574fbf8f11f4067f88a0e6b984a1391"
AppBuilder.Utils.ensure_executable(url, sha256, "magick.exe")
System.find_executable("magick.exe") ||
raise "couldn't find magick.exe in PATH to automatically convert images to .ico"
end
defp copy_image(src_path, dest_path) do
defp create_icon(src_path, dest_path) do
src_path = normalize_icon_path(src_path)
if Path.extname(src_path) == ".ico" do
File.cp!(src_path, dest_path)
else

View file

@ -8,16 +8,10 @@ if Mix.target() == :app do
defmacro wxID_OSX_HIDE, do: 5250
defmacro wxBITMAP_TYPE_PNG, do: 15
def os do
case :os.type() do
{:unix, :darwin} -> :macos
{:win32, _} -> :windows
end
end
def taskbar(title, icon, menu_items) do
pid = self()
options = if os() == :macos, do: [iconType: 1], else: []
os = AppBuilder.os()
options = if os == :macos, do: [iconType: 1], else: []
# skip keyboard shortcuts
menu_items =
@ -35,7 +29,7 @@ if Mix.target() == :app do
# For some reason, on macOS the menu event must be handled in another process
# but on Windows it must be either the same process OR we use the callback.
case os() do
case os do
:macos ->
env = :wx.get_env()
@ -92,7 +86,7 @@ if Mix.target() == :app do
def menubar(app_name, menus) do
menubar = :wxMenuBar.new()
if os() == :macos, do: fixup_macos_menubar(menubar, app_name)
if AppBuilder.os() == :macos, do: fixup_macos_menubar(menubar, app_name)
for {title, menu_items} <- menus do
true = :wxMenuBar.append(menubar, menu(menu_items), title)
@ -125,13 +119,13 @@ if Mix.target() == :app do
GenServer.start_link(__MODULE__, arg, name: @name)
end
taskbar_icon_path = "rel/app/taskbar_icon.png"
taskbar_icon_path = "rel/app/icon.png"
@external_resource taskbar_icon_path
@taskbar_icon File.read!(taskbar_icon_path)
@impl true
def init(_) do
os = os()
os = AppBuilder.os()
wx = :wx.new()
AppBuilder.Wx.subscribe_to_app_events(@name)
@ -161,7 +155,7 @@ if Mix.target() == :app do
# 1. MIX_TARGET=app mix phx.server
# 2. mix app
# 3. mix release app
taskbar_icon_path = Path.join(System.tmp_dir!(), "taskbar_icon.png")
taskbar_icon_path = Path.join(System.tmp_dir!(), "icon.png")
File.write!(taskbar_icon_path, @taskbar_icon)
icon = :wxIcon.new(taskbar_icon_path, type: wxBITMAP_TYPE_PNG())

14
mix.exs
View file

@ -175,7 +175,10 @@ defmodule Livebook.MixProject do
@app_options [
name: "Livebook",
version: @version,
logo_path: "rel/app/mac-icon.png",
icon_path: [
macos: "rel/app/icon-macos.png",
windows: "rel/app/icon.ico"
],
additional_paths: [
"/rel/erts-#{:erlang.system_info(:version)}/bin",
"/rel/vendor/elixir/bin"
@ -185,6 +188,10 @@ defmodule Livebook.MixProject do
%{
name: "LiveMarkdown",
extensions: ["livemd"],
icon_path: [
macos: "rel/app/icon.png",
windows: "rel/app/icon.ico"
],
# macos specific
role: "Editor"
}
@ -218,10 +225,7 @@ defmodule Livebook.MixProject do
end
defp build_windows_installer(release) do
options =
Keyword.take(@app_options, [:name, :version, :url_schemes, :document_types]) ++
[module: LivebookApp, logo_path: "static/images/logo.png"]
options = Keyword.drop(@app_options, [:additional_paths]) ++ [module: LivebookApp]
AppBuilder.build_windows_installer(release, options)
end
end

View file

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

BIN
rel/app/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View file

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB