feat: FlatpakOverridePage WIP

This commit is contained in:
aclist committed 2026-10-23 11:23:28 +09:00
1 parent e286f02342
commit 01b3babdf5
6 files changed
+108 -19

No files matched your search

+1
View File
@@ -198,6 +198,7 @@ def load_to_menu(client: str, appid: int, name: str, mods: list[str]) -> int:
"""Loads to the menu screen with the selected mods; used for AFK/pre-joining""" """Loads to the menu screen with the selected mods; used for AFK/pre-joining"""
concat = concat_mods(mods) concat = concat_mods(mods)
client_args = concat_bash_args(client) client_args = concat_bash_args(client)
logger.debug(f"Setting client arguments to: {client_args}")
params = [ params = [
"-applaunch", "-applaunch",
str(appid), str(appid),
+10 -2
View File
@@ -3,7 +3,13 @@ import os
from pathlib import Path from pathlib import Path
from dataclasses import dataclass from dataclasses import dataclass
from dzgui.const.constants import APP_NAME_LOWER, DEBUG_LOG, SYSTEM_LOG from dzgui.const.constants import (
APP_NAME_LOWER,
DEBUG_LOG,
FLATPAK_ROOT_PATH,
SYSTEM_LOG,
)
from dzgui.init.proc import is_sandboxed
@dataclass @dataclass
@@ -53,10 +59,12 @@ def get_xdg_paths() -> dict:
"XDG_DATA_HOME": home / ".local" / "share", "XDG_DATA_HOME": home / ".local" / "share",
"XDG_CACHE_HOME": home / ".cache", "XDG_CACHE_HOME": home / ".cache",
} }
resolved_paths = {} resolved_paths = {}
for path in xdg_paths: for path in xdg_paths:
real_path = os.environ.get(path) real_path = os.environ.get(path)
if is_sandboxed():
search_string = FLATPAK_ROOT_PATH + "/"
real_path = real_path.replace(search_string, "")
if real_path is not None and is_writeable(real_path): if real_path is not None and is_writeable(real_path):
new_path = Path(real_path) new_path = Path(real_path)
else: else:
+11 -3
View File
@@ -1,7 +1,8 @@
import psutil
import subprocess
import shutil
import logging import logging
import os
import psutil
import shutil
import subprocess
from dzgui.const.constants import ( from dzgui.const.constants import (
APP_NAME, APP_NAME,
@@ -26,7 +27,14 @@ def is_steam_running(cmd: str) -> bool:
raise TypeError("Not a valid Steam client selection") raise TypeError("Not a valid Steam client selection")
def is_sandboxed() -> bool:
logger.debug("Inside Flatpak sandbox")
return bool(os.environ.get("FLATPAK_ID"))
def is_flatpak_steam_running() -> bool: def is_flatpak_steam_running() -> bool:
if is_sandboxed():
return True
if has_cmd(FLATPAK_CMD) is False: if has_cmd(FLATPAK_CMD) is False:
return False return False
proc = subprocess.check_output( proc = subprocess.check_output(
+2
View File
@@ -3,6 +3,8 @@ title_intro = "Welcome"
blurb_intro = """ blurb_intro = """
This wizard will help you set up some common config options before launching the application. This wizard will help you set up some common config options before launching the application.
""" """
error_sandbox = "Setup cannot be run from inside Flatpak sandbox.\nPlease launch the application directly."
welcome = "Welcome to {0}!"
### SteamPathPage ### SteamPathPage
heading_steam_path = "Steam path" heading_steam_path = "Steam path"
+7
View File
@@ -1,5 +1,12 @@
import shlex import shlex
from dzgui.const.constants import STEAM_CMD
from dzgui.init.proc import is_sandboxed
def concat_bash_args(command: str) -> list[str]: def concat_bash_args(command: str) -> list[str]:
# NOTE: NSGs spawned from sandbox cannot access host application commands,
# so fallback to Steam internal URIs
if is_sandboxed():
return [STEAM_CMD]
return shlex.split(command) return shlex.split(command)
+77 -14
View File
@@ -12,13 +12,13 @@ from dzgui.const.constants import (
APP_NAME, APP_NAME,
APP_NAME_LOWER, APP_NAME_LOWER,
HERO_PATH, HERO_PATH,
FLATPAK_STEAM_PATH, FLATPAK_ROOT_PATH,
LEGACY_CONFIG_PATH, LEGACY_CONFIG_PATH,
) )
from dzgui.const.boilerplate import config_boilerplate from dzgui.const.boilerplate import config_boilerplate
from dzgui.const.endpoints import STEAM_API_SETUP from dzgui.const.endpoints import STEAM_API_SETUP
from dzgui.config import freedesktop from dzgui.config import freedesktop
from dzgui.init.proc import path_to_steam_cmd from dzgui.init.proc import is_sandboxed, path_to_steam_cmd
from dzgui.init.migrate import migrate_legacy_conf from dzgui.init.migrate import migrate_legacy_conf
from dzgui.managers.threading import call_on_thread, StoredFunc, ThreadingManager from dzgui.managers.threading import call_on_thread, StoredFunc, ThreadingManager
from dzgui.strings import wizard from dzgui.strings import wizard
@@ -45,7 +45,8 @@ class PageNum(Enum):
STEAM_API = 4 STEAM_API = 4
USER_PREFS = 5 USER_PREFS = 5
SHORTCUTS = 6 SHORTCUTS = 6
FINAL = 7 FLATPAK = 7
FINAL = 8
class OptionalPageMixin: class OptionalPageMixin:
@@ -144,7 +145,7 @@ class NotificationFrame(Gtk.Frame):
margin_start=50, margin_start=50,
margin_end=50, margin_end=50,
) )
wrapped = textwrap.fill(label, width=80) wrapped = textwrap.fill(label, width=60)
self.label = Gtk.Label( self.label = Gtk.Label(
label=wrapped, label=wrapped,
justify=Gtk.Justification.CENTER, justify=Gtk.Justification.CENTER,
@@ -158,7 +159,7 @@ class NotificationFrame(Gtk.Frame):
add_class(self, "error-frame") add_class(self, "error-frame")
def set_text(self, text: str) -> None: def set_text(self, text: str) -> None:
wrapped = textwrap.fill(text, width=80) wrapped = textwrap.fill(text, width=60)
self.label.set_markup(wrapped) self.label.set_markup(wrapped)
@@ -243,12 +244,23 @@ class IntroductionPage(EnumeratedWizardPage):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__( super().__init__(
enum=PageNum.INTRO, enum=PageNum.INTRO,
heading=f"Welcome to {APP_NAME}!", heading=wizard.welcome.format(APP_NAME),
description=wizard.blurb_intro, description=wizard.blurb_intro,
) )
self.page_type = Gtk.AssistantPageType.INTRO self.page_type = Gtk.AssistantPageType.INTRO
self.set_title(wizard.title_intro) self.set_title(wizard.title_intro)
self.error_box = NotificationFrame(wizard.error_sandbox, error=True)
self.add_start(self.error_box)
self.connect("map", self._on_map)
def _on_map(self, page: "EnumeratedWizardPage") -> None:
self.error_box.hide()
if is_sandboxed():
self.error_box.show()
EMITTER.emit("step_pending")
class Heading(Gtk.Label): class Heading(Gtk.Label):
def __init__(self, label: str): def __init__(self, label: str):
@@ -405,6 +417,43 @@ class PreferencesPage(EnumeratedWizardPage):
EMITTER.emit("step_complete") EMITTER.emit("step_complete")
class FlatpakOverridePage(EnumeratedWizardPage):
def __init__(self, xdg: "Xdg") -> None:
# TODO: strings
super().__init__(
enum=PageNum.FLATPAK,
heading="Flatpak overrides",
description="Enable overrides",
)
self.xdg = xdg
self.page_type = Gtk.AssistantPageType.INTRO
# TODO: labels, blurbs
# You chose to add a DZGUI shortcut directly to Steam.
# Your Steam client selection is Flatpak Steam.
# To launch DZGUI from Flatpak's sandbox, you must
# grant permission for the sandbox to read from and write to the
# following locations.
# Click below to whitelist these paths and enable Steam to register the DZGUI application.
# XDG.config, XDG.share, XDG.state, /tmp?
self.label = Gtk.Label(label="Whitelist")
self.authorize_button = Gtk.Button(
label="Grant permissions", halign=Gtk.Align.CENTER
)
self.authorize_button.connect("clicked", self._on_authorize)
for el in self.label, self.authorize_button:
self.add_start(el)
def _on_authorize(self, button: Gtk.Button) -> None:
# TODO: apply flatpak overrides via module
print(self.xdg)
EMITTER.emit("step_complete")
class CompletionPage(EnumeratedWizardPage): class CompletionPage(EnumeratedWizardPage):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__( super().__init__(
@@ -437,6 +486,7 @@ class Assistant(Gtk.Assistant):
self.page_api = SteamValidationPage() self.page_api = SteamValidationPage()
self.page_prefs = PreferencesPage() self.page_prefs = PreferencesPage()
self.page_shortcuts = ShortcutCreationPage(XDG.shortcut) self.page_shortcuts = ShortcutCreationPage(XDG.shortcut)
self.page_flatpak = FlatpakOverridePage(XDG)
self.page_completion = CompletionPage() self.page_completion = CompletionPage()
self.set_forward_page_func(self._advance_page) self.set_forward_page_func(self._advance_page)
@@ -456,6 +506,7 @@ class Assistant(Gtk.Assistant):
self.page_api, self.page_api,
self.page_prefs, self.page_prefs,
self.page_shortcuts, self.page_shortcuts,
self.page_flatpak,
self.page_completion, self.page_completion,
): ):
# NOTE: skip config migration page if no legacy config file # NOTE: skip config migration page if no legacy config file
@@ -476,7 +527,10 @@ class Assistant(Gtk.Assistant):
def write_config(self, config: dict[str, Any]) -> None: def write_config(self, config: dict[str, Any]) -> None:
write_json(config, self.config_path) write_json(config, self.config_path)
def get_final_page(self) -> int: def get_completion_page(self) -> int:
return self.pages[self.page_completion]
def get_shortcut_page(self) -> int:
return self.pages[self.page_shortcuts] return self.pages[self.page_shortcuts]
def _advance_page(self, index: int) -> int: def _advance_page(self, index: int) -> int:
@@ -489,7 +543,7 @@ class Assistant(Gtk.Assistant):
sp = page.migrated_conf["default_steam_path"] sp = page.migrated_conf["default_steam_path"]
self.page_shortcuts.set_steam_path(sp) self.page_shortcuts.set_steam_path(sp)
self.config_values = self.page_migration.migrated_conf self.config_values = self.page_migration.migrated_conf
return self.get_final_page() return self.get_shortcuts_page()
case SteamPathPage(): case SteamPathPage():
path = page.get_path_from_radio() path = page.get_path_from_radio()
self.config_values["default_steam_path"] = path self.config_values["default_steam_path"] = path
@@ -506,10 +560,22 @@ class Assistant(Gtk.Assistant):
) )
case ShortcutCreationPage(): case ShortcutCreationPage():
page.create_shortcuts() page.create_shortcuts()
if not self.needs_flatpak_override():
return self.get_completion_page()
case FlatpakOverridePage():
pass
case _: case _:
raise AttributeError("Trying to advance a non-canonical page") raise AttributeError("Trying to advance a non-canonical page")
return index + 1 return index + 1
def needs_flatpak_override(self) -> None:
if (
self.page_shortcuts.is_steam_checkbox_active()
and FLATPAK_ROOT_PATH in self.config_values["default_steam_path"]
):
return True
return False
def is_setup_complete(self) -> bool: def is_setup_complete(self) -> bool:
return self.setup_complete return self.setup_complete
@@ -625,12 +691,6 @@ class ShortcutCreationPage(OptionalPageMixin, EnumeratedWizardPage): # type: ig
self.add_start(self.checks_area) self.add_start(self.checks_area)
self.show_all() self.show_all()
self.connect("map", self._on_map) self.connect("map", self._on_map)
self.connect("map", self._toggle_checkbox)
def _toggle_checkbox(self, page: "EnumeratedWizardPage") -> None:
if FLATPAK_STEAM_PATH in str(self.steam_path):
self.steam_checkbox.set_active(False)
self.steam_checkbox.set_sensitive(False)
def _on_start_menu_toggled(self, button: Gtk.CheckButton) -> None: def _on_start_menu_toggled(self, button: Gtk.CheckButton) -> None:
state = button.get_active() state = button.get_active()
@@ -641,6 +701,9 @@ class ShortcutCreationPage(OptionalPageMixin, EnumeratedWizardPage): # type: ig
def set_steam_path(self, path: Path) -> None: def set_steam_path(self, path: Path) -> None:
self.steam_path = path self.steam_path = path
def is_steam_checkbox_active(self) -> None:
return self.steam_checkbox.get_active()
def create_shortcuts(self) -> None: def create_shortcuts(self) -> None:
# NOTE: best-effort, permissive even on failure (page is already marked as complete) # NOTE: best-effort, permissive even on failure (page is already marked as complete)
if self.steam_checkbox.get_active(): if self.steam_checkbox.get_active():