3 Commits

Author SHA1 Message Date
e0a2f27265 chore(changelog): update
All checks were successful
Code and build check / Check code (push) Successful in 1m41s
Code and build check / Build with uv (push) Successful in 53s
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-06-24 16:10:50 +05:00
86d2d4d9d8 chore(readme): add contributors section
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-06-24 15:41:03 +05:00
0550d443f7 feat(dialogs, context-menu): use generate_thumbnail for 128x128 icons from exe
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-06-24 15:28:28 +05:00
4 changed files with 64 additions and 35 deletions

View File

@@ -14,6 +14,8 @@
- Удалены сборки для Fedora 40 - Удалены сборки для Fedora 40
- Перенесены параметры анимации GameCard в `styles.py` с подробной документацией для поддержки кастомизации тем. - Перенесены параметры анимации GameCard в `styles.py` с подробной документацией для поддержки кастомизации тем.
- Статус выделения и наведения на карточки теперь взаимоисключают друг друга - Статус выделения и наведения на карточки теперь взаимоисключают друг друга
- Все desktop файлы создаются с коментарием "Запустить игру {название} через PortProton"
- Заполнители в переводах теперь стали более осмысленными
### Fixed ### Fixed
- Дублирование обводки выделения карточек при быстром перемешении мыши - Дублирование обводки выделения карточек при быстром перемешении мыши
@@ -21,6 +23,7 @@
- Использование системной палитры в темах - Использование системной палитры в темах
- Ошибки темы в нативном пакете - Ошибки темы в нативном пакете
- Ошибки темы в Gamescope - Ошибки темы в Gamescope
- Размер иконок для desktop файлов теперь 128x128
### Contributors ### Contributors
- @Dervart - @Dervart

View File

@@ -108,9 +108,13 @@ pre-commit run --all-files
## Авторы ## Авторы
* [Boria138](https://git.linux-gaming.ru/Boria138) - Программист * [Boria138](https://git.linux-gaming.ru/Boria138) - Основной разработчик
* [BlackSnaker](https://github.com/BlackSnaker) - Дизайнер - программист * [BlackSnaker](https://git.linux-gaming.ru/BlackSnaker) - Автор идеи, а так же начальной реализации проекта
* [Mikhail Tergoev(Castro-Fidel)](https://git.linux-gaming.ru/CastroFidel) - Автор оригинального проекта PortProton * [Mikhail Tergoev (Castro-Fidel)](https://git.linux-gaming.ru/CastroFidel) - Автор оригинального проекта PortProton
### Контрибьюторы
Мы благодарим всех, кто внёс вклад в развитие PortProtonQt, включая тех, кто участвует через коммиты, а также тех, кто помогает другими способами (тестирование, идеи, переводы, документация и т.д.). Полный список участников, можно найти в [списке активности репозитория](https://git.linux-gaming.ru/Boria138/PortProtonQt/activity/contributors). Дополнительные участники также перечислены в файле [CHANGELOG.md](CHANGELOG.md). Если вы внесли вклад, но не указаны, свяжитесь с основными разработчиками, чтобы мы могли вас отметить!
## Зависимости и лицензии ## Зависимости и лицензии

View File

@@ -15,7 +15,7 @@ from portprotonqt.localization import _
from portprotonqt.config_utils import parse_desktop_entry, read_favorites, save_favorites from portprotonqt.config_utils import parse_desktop_entry, read_favorites, save_favorites
from portprotonqt.steam_api import is_game_in_steam, add_to_steam, remove_from_steam, get_steam_home, get_last_steam_user, convert_steam_id from portprotonqt.steam_api import is_game_in_steam, add_to_steam, remove_from_steam, get_steam_home, get_last_steam_user, convert_steam_id
from portprotonqt.egs_api import add_egs_to_steam, get_egs_executable from portprotonqt.egs_api import add_egs_to_steam, get_egs_executable
from portprotonqt.dialogs import AddGameDialog from portprotonqt.dialogs import AddGameDialog, generate_thumbnail
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -378,23 +378,33 @@ class ContextMenuManager:
_("start.sh not found at {path}").format(path=start_sh_path) _("start.sh not found at {path}").format(path=start_sh_path)
) )
return False return False
image_folder = os.path.join( icon_path = os.path.join(self.portproton_location, "data", "img", f"{game_name}.png")
os.getenv("XDG_CACHE_HOME", os.path.join(os.path.expanduser("~"), ".cache")), os.makedirs(os.path.dirname(icon_path), exist_ok=True)
"PortProtonQt", "images"
) # Generate 128x128 icon from exe only
cover_path = os.path.join(image_folder, f"{app_name}.jpg") exe_path = get_egs_executable(app_name, self.legendary_config_path)
icon_path = cover_path if os.path.exists(cover_path) else "" if exe_path and os.path.exists(exe_path):
if not generate_thumbnail(exe_path, icon_path, size=128):
logger.error(f"Failed to generate thumbnail from exe: {exe_path}")
icon_path = ""
else:
logger.error(f"No executable found for EGS game: {app_name}")
icon_path = ""
egs_desktop_dir = os.path.join(self.portproton_location, "egs_desktops") egs_desktop_dir = os.path.join(self.portproton_location, "egs_desktops")
os.makedirs(egs_desktop_dir, exist_ok=True) os.makedirs(egs_desktop_dir, exist_ok=True)
desktop_path = self._get_egs_desktop_path(game_name) desktop_path = self._get_egs_desktop_path(game_name)
comment = _('Launch game "{name}" with PortProton').format(name=game_name)
desktop_entry = f"""[Desktop Entry] desktop_entry = f"""[Desktop Entry]
Type=Application Type=Application
Name={game_name} Name={game_name}
Exec="{self.legendary_path}" launch {app_name} --no-wine --wrapper "env START_FROM_STEAM=1 {wrapper}" Comment={comment}
Icon={icon_path} Terminal=false
Terminal=false StartupNotify=true
Categories=Game Exec="{self.legendary_path}" launch {app_name} --no-wine --wrapper "env START_FROM_STEAM=1 {wrapper}"
""" Icon={icon_path}
Categories=Game
"""
try: try:
with open(desktop_path, "w", encoding="utf-8") as f: with open(desktop_path, "w", encoding="utf-8") as f:
f.write(desktop_entry) f.write(desktop_entry)
@@ -687,8 +697,9 @@ Categories=Game
Args: Args:
game_name: The display name of the game. game_name: The display name of the game.
exec_line: The executable command line for the game. exec_line: The executable command line.
""" """
if not self._check_portproton(): if not self._check_portproton():
return return
desktop_path = self._get_desktop_path(game_name) desktop_path = self._get_desktop_path(game_name)
@@ -698,6 +709,18 @@ Categories=Game
_("No .desktop file found for '{game_name}'").format(game_name=game_name) _("No .desktop file found for '{game_name}'").format(game_name=game_name)
) )
return return
# Ensure icon exists
exec_line = self._get_exec_line(game_name, exec_line)
if not exec_line:
return
exe_path = self._parse_exe_path(exec_line, game_name)
if not exe_path:
return
icon_path = os.path.join(self.portproton_location, "data", "img", f"{game_name}.png")
if not os.path.exists(icon_path):
if not generate_thumbnail(exe_path, icon_path, size=128):
logger.error(f"Failed to generate thumbnail for {exe_path}")
desktop_dir = subprocess.check_output(['xdg-user-dir', 'DESKTOP']).decode('utf-8').strip() desktop_dir = subprocess.check_output(['xdg-user-dir', 'DESKTOP']).decode('utf-8').strip()
os.makedirs(desktop_dir, exist_ok=True) os.makedirs(desktop_dir, exist_ok=True)
dest_path = os.path.join(desktop_dir, f"{game_name}.desktop") dest_path = os.path.join(desktop_dir, f"{game_name}.desktop")

View File

@@ -1,5 +1,4 @@
import os import os
import shutil
import tempfile import tempfile
from PySide6.QtGui import QPixmap from PySide6.QtGui import QPixmap
@@ -229,25 +228,25 @@ class AddGameDialog(QDialog):
desktop_path = os.path.join(portproton_path, f"{name}.desktop") desktop_path = os.path.join(portproton_path, f"{name}.desktop")
working_dir = os.path.join(base_path, "scripts") working_dir = os.path.join(base_path, "scripts")
user_cover_path = self.coverEdit.text().strip() os.makedirs(os.path.dirname(icon_path), exist_ok=True)
if os.path.isfile(user_cover_path):
shutil.copy(user_cover_path, icon_path) # Generate thumbnail (128x128) from exe
else: if not generate_thumbnail(exe_path, icon_path, size=128):
os.makedirs(os.path.dirname(icon_path), exist_ok=True) logger.error(f"Failed to generate thumbnail from exe: {exe_path}")
os.system(f'exe-thumbnailer "{exe_path}" "{icon_path}"') icon_path = "" # Set empty icon if generation fails
comment = _('Launch game "{name}" with PortProton').format(name=name) comment = _('Launch game "{name}" with PortProton').format(name=name)
desktop_entry = f"""[Desktop Entry] desktop_entry = f"""[Desktop Entry]
Name={name} Name={name}
Comment={comment} Comment={comment}
Exec={exec_str} Exec={exec_str}
Terminal=false Terminal=false
Type=Application Type=Application
Categories=Game; Categories=Game;
StartupNotify=true StartupNotify=true
Path={working_dir} Path={working_dir}
Icon={icon_path} Icon={icon_path}
""" """
return desktop_entry, desktop_path return desktop_entry, desktop_path