sync current state
This commit is contained in:
@@ -2,6 +2,7 @@ py.install_sources(
|
|||||||
'components.py',
|
'components.py',
|
||||||
'proton_downloader.py',
|
'proton_downloader.py',
|
||||||
'shortcut.py',
|
'shortcut.py',
|
||||||
|
'shortcut_utils.py',
|
||||||
'config_manager.py',
|
'config_manager.py',
|
||||||
'path_manager.py',
|
'path_manager.py',
|
||||||
'language_config.py',
|
'language_config.py',
|
||||||
|
|||||||
32
faugus/shortcut_utils.py
Normal file
32
faugus/shortcut_utils.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def get_shortcut_icon_path(gameid, icons_dir, fallback_icon):
|
||||||
|
icon_png = os.path.join(icons_dir, f"{gameid}.png")
|
||||||
|
if os.path.exists(icon_png):
|
||||||
|
return icon_png
|
||||||
|
|
||||||
|
icon_ico = os.path.join(icons_dir, f"{gameid}.ico")
|
||||||
|
if os.path.exists(icon_ico):
|
||||||
|
return icon_ico
|
||||||
|
|
||||||
|
return fallback_icon
|
||||||
|
|
||||||
|
|
||||||
|
def build_desktop_entry(name, exec_command, icon_path, game_directory, startup_wm_class=""):
|
||||||
|
entry = [
|
||||||
|
"[Desktop Entry]",
|
||||||
|
f"Name={name}",
|
||||||
|
f"Exec={exec_command}",
|
||||||
|
f"Icon={icon_path}",
|
||||||
|
"Type=Application",
|
||||||
|
"Categories=Game;",
|
||||||
|
f"Path={game_directory}",
|
||||||
|
]
|
||||||
|
|
||||||
|
if startup_wm_class:
|
||||||
|
entry.append(f"StartupWMClass={startup_wm_class}")
|
||||||
|
|
||||||
|
return "\n".join(entry) + "\n"
|
||||||
@@ -25,6 +25,7 @@ from gi.repository import Gtk, Gdk, GdkPixbuf, GLib, AyatanaAppIndicator3, Gio,
|
|||||||
from PIL import Image
|
from PIL import Image
|
||||||
from faugus.config_manager import *
|
from faugus.config_manager import *
|
||||||
from faugus.dark_theme import *
|
from faugus.dark_theme import *
|
||||||
|
from faugus.shortcut_utils import build_desktop_entry, get_shortcut_icon_path
|
||||||
from faugus.steam_setup import *
|
from faugus.steam_setup import *
|
||||||
|
|
||||||
VERSION = "1.15.1"
|
VERSION = "1.15.1"
|
||||||
@@ -1456,7 +1457,8 @@ class Main(Gtk.ApplicationWindow):
|
|||||||
game_data.get("playtime", 0),
|
game_data.get("playtime", 0),
|
||||||
game_data.get("hidden", False),
|
game_data.get("hidden", False),
|
||||||
game_data.get("prevent_sleep", False),
|
game_data.get("prevent_sleep", False),
|
||||||
game_data.get("favorite", False)
|
game_data.get("favorite", False),
|
||||||
|
game_data.get("startup_wm_class", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
if not self.show_hidden and game.hidden:
|
if not self.show_hidden and game.hidden:
|
||||||
@@ -1491,7 +1493,7 @@ class Main(Gtk.ApplicationWindow):
|
|||||||
else:
|
else:
|
||||||
hbox.get_style_context().add_class("hbox-normal")
|
hbox.get_style_context().add_class("hbox-normal")
|
||||||
|
|
||||||
game_icon = f'{icons_dir}/{game.gameid}.ico'
|
game_icon = get_shortcut_icon_path(game.gameid, icons_dir, faugus_png)
|
||||||
game_label = Gtk.Label.new(game.title)
|
game_label = Gtk.Label.new(game.title)
|
||||||
|
|
||||||
if self.interface_mode in ("Blocks", "Banners"):
|
if self.interface_mode in ("Blocks", "Banners"):
|
||||||
@@ -1499,9 +1501,6 @@ class Main(Gtk.ApplicationWindow):
|
|||||||
game_label.set_max_width_chars(1)
|
game_label.set_max_width_chars(1)
|
||||||
game_label.set_justify(Gtk.Justification.CENTER)
|
game_label.set_justify(Gtk.Justification.CENTER)
|
||||||
|
|
||||||
if not os.path.isfile(game_icon):
|
|
||||||
game_icon = faugus_png
|
|
||||||
|
|
||||||
self.flowbox_child = Gtk.FlowBoxChild()
|
self.flowbox_child = Gtk.FlowBoxChild()
|
||||||
|
|
||||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file(game_icon)
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file(game_icon)
|
||||||
@@ -2063,12 +2062,11 @@ class Main(Gtk.ApplicationWindow):
|
|||||||
def set_image_shortcut_icon(self, title, icons_path, icon_temp):
|
def set_image_shortcut_icon(self, title, icons_path, icon_temp):
|
||||||
title_formatted = format_title(title)
|
title_formatted = format_title(title)
|
||||||
|
|
||||||
# Check if the icon file exists
|
icon_path = get_shortcut_icon_path(title_formatted, icons_path, faugus_png)
|
||||||
icon_path = os.path.join(icons_path, f"{title_formatted}.ico")
|
|
||||||
|
|
||||||
if os.path.exists(icon_path):
|
if icon_path != faugus_png:
|
||||||
shutil.copyfile(icon_path, icon_temp)
|
shutil.copyfile(icon_path, icon_temp)
|
||||||
if not os.path.exists(icon_path):
|
else:
|
||||||
icon_temp = faugus_png
|
icon_temp = faugus_png
|
||||||
|
|
||||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file(icon_temp)
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file(icon_temp)
|
||||||
@@ -2278,9 +2276,11 @@ class Main(Gtk.ApplicationWindow):
|
|||||||
playtime = 0
|
playtime = 0
|
||||||
hidden = False
|
hidden = False
|
||||||
favorite = False
|
favorite = False
|
||||||
|
startup_wm_class = ""
|
||||||
|
|
||||||
if add_game_dialog.combobox_launcher.get_active() == 3:
|
if add_game_dialog.combobox_launcher.get_active() == 3:
|
||||||
path = f"{prefix}/drive_c/Program Files (x86)/Battle.net/Battle.net.exe"
|
path = f"{prefix}/drive_c/Program Files (x86)/Battle.net/Battle.net.exe"
|
||||||
|
startup_wm_class = "battle.net.exe"
|
||||||
if add_game_dialog.combobox_launcher.get_active() == 4:
|
if add_game_dialog.combobox_launcher.get_active() == 4:
|
||||||
path = f"{prefix}/drive_c/Program Files/Electronic Arts/EA Desktop/EA Desktop/EALauncher.exe"
|
path = f"{prefix}/drive_c/Program Files/Electronic Arts/EA Desktop/EA Desktop/EALauncher.exe"
|
||||||
if add_game_dialog.combobox_launcher.get_active() == 5:
|
if add_game_dialog.combobox_launcher.get_active() == 5:
|
||||||
@@ -2346,6 +2346,7 @@ class Main(Gtk.ApplicationWindow):
|
|||||||
hidden,
|
hidden,
|
||||||
prevent_sleep,
|
prevent_sleep,
|
||||||
favorite,
|
favorite,
|
||||||
|
startup_wm_class,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Determine the state of the shortcut checkbox
|
# Determine the state of the shortcut checkbox
|
||||||
@@ -2354,7 +2355,7 @@ class Main(Gtk.ApplicationWindow):
|
|||||||
steam_shortcut_state = add_game_dialog.checkbox_shortcut_steam.get_active()
|
steam_shortcut_state = add_game_dialog.checkbox_shortcut_steam.get_active()
|
||||||
|
|
||||||
icon_temp = os.path.expanduser(add_game_dialog.icon_temp)
|
icon_temp = os.path.expanduser(add_game_dialog.icon_temp)
|
||||||
icon_final = f'{add_game_dialog.icons_path}/{title_formatted}.ico'
|
icon_final = f'{add_game_dialog.icons_path}/{title_formatted}.png'
|
||||||
|
|
||||||
def check_internet_connection():
|
def check_internet_connection():
|
||||||
try:
|
try:
|
||||||
@@ -2414,6 +2415,7 @@ class Main(Gtk.ApplicationWindow):
|
|||||||
"hidden": hidden,
|
"hidden": hidden,
|
||||||
"prevent_sleep": prevent_sleep,
|
"prevent_sleep": prevent_sleep,
|
||||||
"favorite": favorite,
|
"favorite": favorite,
|
||||||
|
"startup_wm_class": startup_wm_class,
|
||||||
}
|
}
|
||||||
|
|
||||||
games = []
|
games = []
|
||||||
@@ -2729,9 +2731,13 @@ class Main(Gtk.ApplicationWindow):
|
|||||||
game.runner = "Linux-Native"
|
game.runner = "Linux-Native"
|
||||||
if edit_game_dialog.combobox_launcher.get_active() == 2:
|
if edit_game_dialog.combobox_launcher.get_active() == 2:
|
||||||
game.runner = "Steam"
|
game.runner = "Steam"
|
||||||
|
if edit_game_dialog.combobox_launcher.get_active() == 3:
|
||||||
|
game.startup_wm_class = "battle.net.exe"
|
||||||
|
elif getattr(game, "startup_wm_class", "") == "battle.net.exe":
|
||||||
|
game.startup_wm_class = ""
|
||||||
|
|
||||||
icon_temp = os.path.expanduser(edit_game_dialog.icon_temp)
|
icon_temp = os.path.expanduser(edit_game_dialog.icon_temp)
|
||||||
icon_final = f'{edit_game_dialog.icons_path}/{title_formatted}.ico'
|
icon_final = f'{edit_game_dialog.icons_path}/{title_formatted}.png'
|
||||||
|
|
||||||
# Determine the state of the shortcut checkbox
|
# Determine the state of the shortcut checkbox
|
||||||
desktop_shortcut_state = edit_game_dialog.checkbox_shortcut_desktop.get_active()
|
desktop_shortcut_state = edit_game_dialog.checkbox_shortcut_desktop.get_active()
|
||||||
@@ -2787,34 +2793,27 @@ class Main(Gtk.ApplicationWindow):
|
|||||||
if os.path.isfile(os.path.expanduser(icon_temp)):
|
if os.path.isfile(os.path.expanduser(icon_temp)):
|
||||||
os.rename(os.path.expanduser(icon_temp), icon_final)
|
os.rename(os.path.expanduser(icon_temp), icon_final)
|
||||||
|
|
||||||
# Check if the icon file exists
|
new_icon_path = get_shortcut_icon_path(game.gameid, icons_dir, faugus_png)
|
||||||
new_icon_path = f"{icons_dir}/{game.gameid}.ico"
|
|
||||||
if not os.path.exists(new_icon_path):
|
|
||||||
new_icon_path = faugus_png
|
|
||||||
|
|
||||||
# Get the directory containing the executable
|
# Get the directory containing the executable
|
||||||
game_directory = os.path.dirname(game.path)
|
game_directory = os.path.dirname(game.path)
|
||||||
|
|
||||||
# Create a .desktop file
|
# Create a .desktop file
|
||||||
if IS_FLATPAK:
|
if IS_FLATPAK:
|
||||||
desktop_file_content = (
|
desktop_file_content = build_desktop_entry(
|
||||||
f'[Desktop Entry]\n'
|
game.title,
|
||||||
f'Name={game.title}\n'
|
f"flatpak run --command={faugus_run} io.github.Faugus.faugus-launcher --game {game.gameid}",
|
||||||
f'Exec=flatpak run --command={faugus_run} io.github.Faugus.faugus-launcher --game {game.gameid}\n'
|
new_icon_path,
|
||||||
f'Icon={new_icon_path}\n'
|
game_directory,
|
||||||
f'Type=Application\n'
|
getattr(game, "startup_wm_class", ""),
|
||||||
f'Categories=Game;\n'
|
|
||||||
f'Path={game_directory}\n'
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
desktop_file_content = (
|
desktop_file_content = build_desktop_entry(
|
||||||
f'[Desktop Entry]\n'
|
game.title,
|
||||||
f'Name={game.title}\n'
|
f"{faugus_run} --game {game.gameid}",
|
||||||
f'Exec={faugus_run} --game {game.gameid}\n'
|
new_icon_path,
|
||||||
f'Icon={new_icon_path}\n'
|
game_directory,
|
||||||
f'Type=Application\n'
|
getattr(game, "startup_wm_class", ""),
|
||||||
f'Categories=Game;\n'
|
|
||||||
f'Path={game_directory}\n'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if the destination directory exists and create if it doesn't
|
# Check if the destination directory exists and create if it doesn't
|
||||||
@@ -2967,10 +2966,7 @@ class Main(Gtk.ApplicationWindow):
|
|||||||
if os.path.isfile(os.path.expanduser(icon_temp)):
|
if os.path.isfile(os.path.expanduser(icon_temp)):
|
||||||
os.rename(os.path.expanduser(icon_temp), icon_final)
|
os.rename(os.path.expanduser(icon_temp), icon_final)
|
||||||
|
|
||||||
# Check if the icon file exists
|
new_icon_path = get_shortcut_icon_path(game.gameid, icons_dir, faugus_png)
|
||||||
new_icon_path = f"{icons_dir}/{game.gameid}.ico"
|
|
||||||
if not os.path.exists(new_icon_path):
|
|
||||||
new_icon_path = faugus_png
|
|
||||||
|
|
||||||
# Get the directory containing the executable
|
# Get the directory containing the executable
|
||||||
game_directory = os.path.dirname(game.path)
|
game_directory = os.path.dirname(game.path)
|
||||||
@@ -3007,11 +3003,14 @@ class Main(Gtk.ApplicationWindow):
|
|||||||
|
|
||||||
def remove_banner_icon(self, game):
|
def remove_banner_icon(self, game):
|
||||||
banner_file_path = f"{banners_dir}/{game.gameid}.png"
|
banner_file_path = f"{banners_dir}/{game.gameid}.png"
|
||||||
icon_file_path = f"{icons_dir}/{game.gameid}.ico"
|
icon_file_path_png = f"{icons_dir}/{game.gameid}.png"
|
||||||
|
icon_file_path_ico = f"{icons_dir}/{game.gameid}.ico"
|
||||||
if os.path.exists(banner_file_path):
|
if os.path.exists(banner_file_path):
|
||||||
os.remove(banner_file_path)
|
os.remove(banner_file_path)
|
||||||
if os.path.exists(icon_file_path):
|
if os.path.exists(icon_file_path_png):
|
||||||
os.remove(icon_file_path)
|
os.remove(icon_file_path_png)
|
||||||
|
if os.path.exists(icon_file_path_ico):
|
||||||
|
os.remove(icon_file_path_ico)
|
||||||
|
|
||||||
def remove_shortcut(self, game, shortcut):
|
def remove_shortcut(self, game, shortcut):
|
||||||
applications_shortcut_path = f"{app_dir}/{game.gameid}.desktop"
|
applications_shortcut_path = f"{app_dir}/{game.gameid}.desktop"
|
||||||
@@ -3097,6 +3096,7 @@ class Main(Gtk.ApplicationWindow):
|
|||||||
"hidden": hidden,
|
"hidden": hidden,
|
||||||
"prevent_sleep": game.prevent_sleep,
|
"prevent_sleep": game.prevent_sleep,
|
||||||
"favorite": game.favorite,
|
"favorite": game.favorite,
|
||||||
|
"startup_wm_class": game.startup_wm_class,
|
||||||
}
|
}
|
||||||
|
|
||||||
new_games_data.append(game_data)
|
new_games_data.append(game_data)
|
||||||
@@ -4596,6 +4596,7 @@ class Game:
|
|||||||
hidden,
|
hidden,
|
||||||
prevent_sleep,
|
prevent_sleep,
|
||||||
favorite,
|
favorite,
|
||||||
|
startup_wm_class="",
|
||||||
):
|
):
|
||||||
self.gameid = gameid
|
self.gameid = gameid
|
||||||
self.title = title
|
self.title = title
|
||||||
@@ -4622,6 +4623,7 @@ class Game:
|
|||||||
self.hidden = hidden
|
self.hidden = hidden
|
||||||
self.prevent_sleep = prevent_sleep
|
self.prevent_sleep = prevent_sleep
|
||||||
self.favorite = favorite
|
self.favorite = favorite
|
||||||
|
self.startup_wm_class = startup_wm_class
|
||||||
|
|
||||||
|
|
||||||
class DuplicateDialog(Gtk.Dialog):
|
class DuplicateDialog(Gtk.Dialog):
|
||||||
@@ -4804,7 +4806,7 @@ class AddGame(Gtk.Dialog):
|
|||||||
self.icons_path = icons_dir
|
self.icons_path = icons_dir
|
||||||
self.icon_extracted = os.path.expanduser(f'{self.icons_path}/icon_temp/icon.ico')
|
self.icon_extracted = os.path.expanduser(f'{self.icons_path}/icon_temp/icon.ico')
|
||||||
self.icon_converted = os.path.expanduser(f'{self.icons_path}/icon_temp/icon.png')
|
self.icon_converted = os.path.expanduser(f'{self.icons_path}/icon_temp/icon.png')
|
||||||
self.icon_temp = f'{self.icons_path}/icon_temp.ico'
|
self.icon_temp = f'{self.icons_path}/icon_temp.png'
|
||||||
|
|
||||||
self.box = self.get_content_area()
|
self.box = self.get_content_area()
|
||||||
self.box.set_margin_start(0)
|
self.box.set_margin_start(0)
|
||||||
@@ -6767,6 +6769,10 @@ def update_games_and_config():
|
|||||||
game["runner"] = "Proton-GE Latest"
|
game["runner"] = "Proton-GE Latest"
|
||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
|
if title == "Battle.net" and game.get("startup_wm_class", "") != "battle.net.exe":
|
||||||
|
game["startup_wm_class"] = "battle.net.exe"
|
||||||
|
changed = True
|
||||||
|
|
||||||
if changed:
|
if changed:
|
||||||
with open(games_json, "w", encoding="utf-8") as f:
|
with open(games_json, "w", encoding="utf-8") as f:
|
||||||
json.dump(games, f, indent=4, ensure_ascii=False)
|
json.dump(games, f, indent=4, ensure_ascii=False)
|
||||||
|
|||||||
58
tests/test_shortcut_utils.py
Normal file
58
tests/test_shortcut_utils.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from faugus.shortcut_utils import build_desktop_entry, get_shortcut_icon_path
|
||||||
|
|
||||||
|
|
||||||
|
class ShortcutUtilsTest(unittest.TestCase):
|
||||||
|
def test_get_shortcut_icon_path_prefers_png(self):
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
png = os.path.join(tmpdir, "battlenet.png")
|
||||||
|
ico = os.path.join(tmpdir, "battlenet.ico")
|
||||||
|
with open(png, "wb") as f:
|
||||||
|
f.write(b"png")
|
||||||
|
with open(ico, "wb") as f:
|
||||||
|
f.write(b"ico")
|
||||||
|
|
||||||
|
path = get_shortcut_icon_path("battlenet", tmpdir, "/fallback.png")
|
||||||
|
self.assertEqual(path, png)
|
||||||
|
|
||||||
|
def test_get_shortcut_icon_path_falls_back_to_ico(self):
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
ico = os.path.join(tmpdir, "battlenet.ico")
|
||||||
|
with open(ico, "wb") as f:
|
||||||
|
f.write(b"ico")
|
||||||
|
|
||||||
|
path = get_shortcut_icon_path("battlenet", tmpdir, "/fallback.png")
|
||||||
|
self.assertEqual(path, ico)
|
||||||
|
|
||||||
|
def test_get_shortcut_icon_path_uses_fallback(self):
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
path = get_shortcut_icon_path("battlenet", tmpdir, "/fallback.png")
|
||||||
|
self.assertEqual(path, "/fallback.png")
|
||||||
|
|
||||||
|
def test_build_desktop_entry_includes_startup_wm_class(self):
|
||||||
|
entry = build_desktop_entry(
|
||||||
|
"Battle.net",
|
||||||
|
"faugus-run --game battlenet",
|
||||||
|
"/icons/battlenet.png",
|
||||||
|
"/games",
|
||||||
|
"battle.net.exe",
|
||||||
|
)
|
||||||
|
self.assertIn("StartupWMClass=battle.net.exe\n", entry)
|
||||||
|
self.assertIn("Icon=/icons/battlenet.png\n", entry)
|
||||||
|
|
||||||
|
def test_build_desktop_entry_omits_empty_startup_wm_class(self):
|
||||||
|
entry = build_desktop_entry(
|
||||||
|
"Game",
|
||||||
|
"faugus-run --game game",
|
||||||
|
"/icons/game.png",
|
||||||
|
"/games",
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
self.assertNotIn("StartupWMClass=", entry)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user