Skip to content

Commit

Permalink
Library: Move image loading from RareCore to the GameWidget
Browse files Browse the repository at this point in the history
Instead of loading images in the showEvent of the MainWindow,
load them in the showEvent of each widget. It seems to reduce
the startup stuttering this way. With some more work
we can only load the images for the widgets that are currently
visible and reduce the stutter even more.

At the same time, reduce the number of concurrent downloads
in the image manager and add a timeout so we won't halt.
The exception from the timeout is just logged at this point,
and the download is not requeued.
  • Loading branch information
loathingKernel committed Sep 14, 2023
1 parent 56b52a8 commit dcd4f70
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 39 deletions.
9 changes: 0 additions & 9 deletions rare/components/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,15 +143,6 @@ def center_window(self):
self.resize(window_size)
self.move(screen_rect.center() - self.rect().adjusted(0, 0, decor_width, decor_height).center())

# lk: For the gritty details see `RareCore.load_pixmaps()` method
# Just before the window is shown, fire a timer to load game icons
# This is by nature a little iffy because we don't really know if the
# has been shown, and it might make the window delay as widgets being are updated.
# Still better than showing a hanged window frame for a few seconds.
def showEvent(self, a0: QShowEvent) -> None:
if not self._window_launched:
QTimer.singleShot(100, self.rcore.load_pixmaps)

@pyqtSlot()
def show(self) -> None:
super(MainWindow, self).show()
Expand Down
10 changes: 8 additions & 2 deletions rare/components/tabs/games/game_widgets/game_widget.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import platform
import random
from logging import getLogger

from PyQt5.QtCore import pyqtSignal, Qt, pyqtSlot, QObject, QEvent
from PyQt5.QtGui import QMouseEvent
from PyQt5.QtCore import pyqtSignal, Qt, pyqtSlot, QObject, QEvent, QTimer
from PyQt5.QtGui import QMouseEvent, QShowEvent
from PyQt5.QtWidgets import QMessageBox, QAction

from rare.models.game import RareGame
Expand Down Expand Up @@ -105,6 +106,11 @@ def __init__(self, rgame: RareGame, parent=None):
# lk: attributes as `GameWidgetUi` class
__slots__ = "ui"

def showEvent(self, a0: QShowEvent) -> None:
if self.rgame.pixmap.isNull():
QTimer.singleShot(random.randrange(50, 250, 10), self.rgame.load_pixmap)
super().showEvent(a0)

@pyqtSlot()
def update_state(self):
if self.rgame.is_idle:
Expand Down
10 changes: 7 additions & 3 deletions rare/shared/image_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def __init__(self, signals: GlobalSignals, core: LegendaryCore):
self.device = ImageSize.Preset(1, QApplication.instance().devicePixelRatio())

self.threadpool = QThreadPool()
self.threadpool.setMaxThreadCount(8)
self.threadpool.setMaxThreadCount(6)

def __img_dir(self, app_name: str) -> Path:
return self.image_dir.joinpath(app_name)
Expand Down Expand Up @@ -182,8 +182,12 @@ def __download(self, updates, json_data, game, use_async: bool = False) -> bool:
logger.info(f"Downloading {image['type']} for {game.app_name} ({game.app_title})")
json_data[image["type"]] = image["md5"]
payload = {"resize": 1, "w": ImageSize.Image.size.width(), "h": ImageSize.Image.size.height()}
# cache_data[image["type"]] = requests.get(image["url"], params=payload, timeout=2).content
cache_data[image["type"]] = requests.get(image["url"], params=payload).content
try:
# cache_data[image["type"]] = requests.get(image["url"], params=payload).content
cache_data[image["type"]] = requests.get(image["url"], params=payload, timeout=10).content
except Exception as e:
logger.error(e)
return False

self.__convert(game, cache_data)
# lk: don't keep the cache if there is no logo (kept for me)
Expand Down
29 changes: 4 additions & 25 deletions rare/shared/rare_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,31 +336,6 @@ def __post_init(self) -> None:
# self.fetch_entitlements()
self.resolve_origin()

def load_pixmaps(self) -> None:
"""
Load pixmaps for all games
This exists here solely to fight signal and possibly threading issues.
The initial image loading at startup should not be done in the RareGame class
for two reasons. It will delay startup due to widget updates and the image
might become availabe before the UI is brought up. In case of the second, we
will get both a long queue of signals to be serviced and some of them might
be not connected yet so the widget won't be updated. So do the loading here
by calling this after the MainWindow has finished initializing.
@return: None
"""
def __load_pixmaps() -> None:
# time.sleep(0.1)
for rgame in self.__library.values():
# self.__image_manager.download_image(rgame.game, rgame.set_pixmap, 0, False)
rgame.load_pixmap()
# lk: activity perception delay
time.sleep(0.0005)

pixmap_worker = QRunnable.create(__load_pixmaps)
QThreadPool.globalInstance().start(pixmap_worker)

@property
def games_and_dlcs(self) -> Iterator[RareGame]:
for app_name in self.__library:
Expand All @@ -378,6 +353,10 @@ def installed_games(self) -> Iterator[RareGame]:
def origin_games(self) -> Iterator[RareGame]:
return self.__filter_games(lambda game: game.is_origin and not game.is_dlc)

@property
def ubisoft_games(self) -> Iterator[RareGame]:
return self.__filter_games(lambda game: game.is_ubisoft and not game.is_dlc)

@property
def game_list(self) -> Iterator[Game]:
for game in self.games:
Expand Down

0 comments on commit dcd4f70

Please sign in to comment.