Skip to content

Commit

Permalink
Ensure all app icons have 32x32 size
Browse files Browse the repository at this point in the history
Ensure all app icons have the correct size by resizing them to 32x32 if
necessary. This is done using the Pillow library, which is added to the
list of runtime dependencies, although technically it's only needed if
YAD is used for the GUI. The library should be found in practically
all Linux distros, however.

Users might substitute their own app icons. If those app icons have a
size other than the 32x32 size used by Steam itself, the app selector's
layout becomes broken.

Ideally, we wouldn't deal with resizing image files at all, but the
custom CSS functionality in YAD doesn't seem to support resizing the
list icons, unfortunately.

Refs #239 (bug mentioned in passing)
  • Loading branch information
Matoking committed Jul 31, 2023
1 parent dae39d5 commit 24ca46a
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Fixed
- Fix crash caused by the Steam shortcut configuration file containing extra data after the VDF section
- Fix differently sized custom app icons breaking the layout in the app selector

## [1.10.3] - 2023-05-06
### Added
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ include_package_data = True
install_requires =
setuptools # Required for pkg_resources
vdf>=3.2
Pillow
setup_requires =
setuptools-scm
python_requires = >=3.6
Expand Down
47 changes: 40 additions & 7 deletions src/protontricks/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@
from subprocess import PIPE, CalledProcessError, run

import pkg_resources
from PIL import Image

from .config import get_config
from .flatpak import get_inaccessible_paths
from .util import get_cache_dir

APP_ICON_SIZE = (32, 32)


__all__ = (
"LocaleError", "get_gui_provider", "select_steam_app_with_gui",
Expand Down Expand Up @@ -60,19 +65,47 @@ def _get_appid2icon(steam_apps, steam_path):
)
)

icon_dir = steam_path / "appcache" / "librarycache"
existing_names = [path.name for path in icon_dir.glob("*")]
steam_icon_dir = steam_path / "appcache" / "librarycache"
existing_names = [path.name for path in steam_icon_dir.glob("*")]

protontricks_icon_dir = get_cache_dir() / "app_icons"
protontricks_icon_dir.mkdir(exist_ok=True)

appid2icon = {}

for app in steam_apps:
# Use library icon for Steam apps, fallback to placeholder icon
# for non-Steam shortcuts and missing icons
appid2icon[app.appid] = (
icon_dir / f"{app.appid}_icon.jpg"
if f"{app.appid}_icon.jpg" in existing_names
else placeholder_path
)
icon_cache_path = protontricks_icon_dir / f"{app.appid}.jpg"
original_icon_path = steam_icon_dir / f"{app.appid}_icon.jpg"

# What path to actually use for the app selector. Defaults to
# the original icon path
final_icon_path = placeholder_path

icon_exists = f"{app.appid}_icon.jpg" in existing_names
resize_icon = False

# Resize icons that have a non-standard size to ensure they can be
# displayed consistently in the app selector
if icon_exists:
final_icon_path = original_icon_path

with Image.open(original_icon_path) as img:
resize_icon = img.size != APP_ICON_SIZE

# Resize icons that have a non-standard size to ensure they can
# be displayed consistently in the app selector.
if resize_icon:
logger.info(
"App icon %s has unusual size, resizing",
original_icon_path
)
resized_img = img.resize(APP_ICON_SIZE)
resized_img.save(icon_cache_path)
final_icon_path = icon_cache_path

appid2icon[app.appid] = final_icon_path

return appid2icon

Expand Down
41 changes: 39 additions & 2 deletions tests/test_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import pytest
from conftest import MockResult
from PIL import Image

from protontricks.gui import (prompt_filesystem_access,
select_steam_app_with_gui,
Expand Down Expand Up @@ -100,8 +101,9 @@ def test_select_game_icons(
]

# Create icons for game 1 and 3
(steam_dir / "appcache" / "librarycache" / "10_icon.jpg").touch()
(steam_dir / "appcache" / "librarycache" / "30_icon.jpg").touch()
for appid in (10, 30):
Image.new("RGB", (32, 32)).save(
steam_dir / "appcache" / "librarycache" / f"{appid}_icon.jpg")

gui_provider.mock_stdout = "Fake game 2: 20"
select_steam_app_with_gui(steam_apps=steam_apps, steam_path=steam_dir)
Expand All @@ -112,6 +114,41 @@ def test_select_game_icons(
assert b"icon_placeholder.png\nFake game 2" in input_
assert b"librarycache/30_icon.jpg\nFake game 3" in input_

def test_select_game_icons_ensure_resize(
self, gui_provider, steam_app_factory, steam_dir, home_dir):
"""
Select a game using the GUI. Ensure custom icons with sizes other than
32x32 are resized.
"""
steam_apps = [
steam_app_factory(name="Fake game 1", appid=10)
]

Image.new("RGB", (64, 64)).save(
steam_dir / "appcache" / "librarycache" / "10_icon.jpg"
)

gui_provider.mock_stdout = "Fake game 1: 10"
select_steam_app_with_gui(steam_apps=steam_apps, steam_path=steam_dir)

# Resized icon should have been created with the correct size and used
resized_icon_path = \
home_dir / ".cache" / "protontricks" / "app_icons" / "10.jpg"
assert resized_icon_path.is_file()
with Image.open(resized_icon_path) as img:
assert img.size == (32, 32)

input_ = gui_provider.kwargs["input"]

assert f"{resized_icon_path}\nFake game 1".encode("utf-8") in input_

# Any existing icon should be overwritten if it already exists
resized_icon_path.write_bytes(b"not valid")
select_steam_app_with_gui(steam_apps=steam_apps, steam_path=steam_dir)

with Image.open(resized_icon_path) as img:
assert img.size == (32, 32)

def test_select_game_no_choice(
self, gui_provider, steam_app_factory, steam_dir):
"""
Expand Down

0 comments on commit 24ca46a

Please sign in to comment.