mirror of
https://github.com/aclist/dztui.git
synced 2026-10-26 20:52:44 +01:00
Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f97be9352d | ||
|
|
b092a809f4 | ||
|
|
2cc7710807 | ||
|
|
5fb10d9758 | ||
|
|
100cb43afc | ||
|
|
7e2a585812 | ||
|
|
c1181435b3 | ||
|
|
22a7814ce4 | ||
|
|
b030da5c65 | ||
|
|
3c0acdd068 | ||
|
|
25ae2052e4 | ||
|
|
1b1777117f | ||
|
|
3e6bd95285 | ||
|
|
f4be9a31e9 | ||
|
|
a6282e4401 | ||
|
|
a9ae5f59b5 | ||
|
|
97ee2b7307 | ||
|
|
ff6edb6181 | ||
|
|
4c22263fb5 | ||
|
|
141f96fb9f |
No files matched your search
@@ -17,7 +17,7 @@ DZGUI follows a specific set of guidelines, enumerated below:
|
||||
- Provide a free and open-source tool under GPL
|
||||
- Do not use undocumented, third-party servers to aggregate data; no central "DZGUI" server
|
||||
- All connections go to Steam and DayZ servers directly; the tool should function in perpetuity without intermediary endpoints
|
||||
- Target Linux desktop and Steam deck specifically; not a cross-platform tool
|
||||
- Target Linux desktop and Steam Deck specifically; not a cross-platform tool
|
||||
|
||||
## Setup and usage
|
||||
|
||||
@@ -35,6 +35,8 @@ Geolocation records from [DB-IP](https://db-ip.com) under [CC 4.0 license](https
|
||||
Executable versions of DZGUI published as release binaries ship with various runtime dependencies and the Python interpreter built in.
|
||||
Users wishing to review the licenses to these components can inspect the `LICENSE` file located in the release tarball.
|
||||
|
||||
Steam and the Steam logo are trademarks and/or registered trademarks of Valve Corporation in the U.S. and/or other countries.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
DZGUI is beta-quality software and is provided as-is.
|
||||
@@ -173,11 +173,12 @@ class Shortcuts:
|
||||
self.save_shortcuts()
|
||||
|
||||
def save_shortcuts(self) -> None:
|
||||
try:
|
||||
backup = self.shortcuts_path.with_suffix(".vdf.bak")
|
||||
shutil.copy(self.shortcuts_path, backup)
|
||||
except Exception as e:
|
||||
logger.critical(e)
|
||||
if self.shortcuts_path.is_file():
|
||||
try:
|
||||
backup = self.shortcuts_path.with_suffix(".vdf.bak")
|
||||
shutil.copy(self.shortcuts_path, backup)
|
||||
except Exception as e:
|
||||
logger.critical(e)
|
||||
try:
|
||||
with open(self.shortcuts_path, "wb") as f:
|
||||
vdf.binary_dump(self.shortcuts, f)
|
||||
|
||||
+5
-4
@@ -13,7 +13,7 @@ from warnings import deprecated
|
||||
|
||||
from dzgui.api.acf import ACF
|
||||
from dzgui.init.prereqs import has_any_client
|
||||
from dzgui.init.proc import has_cmd
|
||||
from dzgui.init.prereqs import has_flatpak_client, has_steam_client
|
||||
from dzgui.const.constants import (
|
||||
APPID_DAYZ,
|
||||
APPID_DAYZ_EXP,
|
||||
@@ -23,11 +23,10 @@ from dzgui.const.constants import (
|
||||
DEBIAN_STEAM_PATH,
|
||||
DEFAULT_STEAM_PATH,
|
||||
DOWNLOADS_PATH,
|
||||
FLATPAK_CMD,
|
||||
FLATPAK_STEAM_PATH,
|
||||
LIBRARYFOLDERS_PATH,
|
||||
UBUNTU_STEAM_PATH,
|
||||
REQUEST_TIMEOUT,
|
||||
UBUNTU_STEAM_PATH,
|
||||
VDF_PATH,
|
||||
)
|
||||
from dzgui.const.endpoints import (
|
||||
@@ -84,7 +83,9 @@ def get_steam_paths() -> list[tuple[Path, str]]:
|
||||
}
|
||||
|
||||
for path in DEFAULT_PATH, FLATPAK_PATH, UBUNTU_PATH, DEBIAN_PATH:
|
||||
if path is FLATPAK_PATH and has_cmd(FLATPAK_CMD) is False:
|
||||
if path is FLATPAK_PATH and has_flatpak_client() is False:
|
||||
continue
|
||||
if path is not FLATPAK_PATH and has_steam_client() is False:
|
||||
continue
|
||||
if path.joinpath(VDF_PATH).is_file():
|
||||
paths.append((path, human[path]))
|
||||
|
||||
+21
-16
@@ -2,12 +2,17 @@ import logging
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from importlib import resources
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
from warnings import deprecated
|
||||
|
||||
|
||||
from dzgui.const.constants import APP_NAME, STEAM_ICON, STEAM_ICONS_PATH
|
||||
from dzgui.const.constants import (
|
||||
APP_NAME,
|
||||
APP_NAME_LOWER,
|
||||
FLATPAK_ROOT_PATH,
|
||||
ICONS_PATH,
|
||||
)
|
||||
from dzgui.const.enum import Preferences
|
||||
from dzgui.config.query import lookup
|
||||
from dzgui.config.userprefs import UserPrefs
|
||||
@@ -18,7 +23,7 @@ from dzgui.init.migrate import (
|
||||
migrate_cols_file,
|
||||
)
|
||||
from dzgui.init.flock import lock_acquire
|
||||
from dzgui.init.prereqs import has_any_client
|
||||
from dzgui.init.prereqs import has_flatpak_client, has_steam_client
|
||||
from dzgui.strings import boot
|
||||
|
||||
from dzgui.util.deck import is_steam_deck, is_game_mode
|
||||
@@ -26,7 +31,7 @@ from dzgui.util.dirs import make_parents
|
||||
from dzgui.util.localize import set_locale
|
||||
from dzgui.util.map_count import test_map_count
|
||||
from dzgui.util.redact import RedactionFilter, REDACTION_PATTERNS
|
||||
from dzgui.util.strings import init, steam_icon_missing
|
||||
from dzgui.util.strings import init
|
||||
|
||||
from dzgui.views.base import App
|
||||
from dzgui.views.dialogs.boot import BootWindow
|
||||
@@ -99,26 +104,21 @@ def copy_bare_configs(config: "Path", resolution: "Path") -> tuple[bool, bool]:
|
||||
return (config_changed, state_changed)
|
||||
|
||||
|
||||
@deprecated("Currently unused")
|
||||
def load_steam_icon(config: Path) -> None:
|
||||
def load_steam_icon() -> None:
|
||||
import gi
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk # noqa
|
||||
|
||||
default = lookup(config, Preferences.DEFAULT)
|
||||
icon_path = Path(default).joinpath(STEAM_ICONS_PATH)
|
||||
try:
|
||||
traversable = resources.files(APP_NAME_LOWER).joinpath(ICONS_PATH)
|
||||
icons = Path(str(traversable))
|
||||
|
||||
theme = Gtk.IconTheme.get_default()
|
||||
paths = theme.get_search_path()
|
||||
theme.set_search_path(paths + [str(icon_path)])
|
||||
paths = theme.get_search_path()
|
||||
icons = theme.list_icons(None)
|
||||
if STEAM_ICON not in icons:
|
||||
logger.warning(steam_icon_missing)
|
||||
theme.set_search_path(paths + [str(icons)])
|
||||
except Exception as e:
|
||||
print(e)
|
||||
logger.warning(e)
|
||||
logger.critical(e)
|
||||
|
||||
|
||||
def load_gui(version: str, is_debug: bool) -> None:
|
||||
@@ -161,7 +161,11 @@ def load_gui(version: str, is_debug: bool) -> None:
|
||||
# TODO: sudo escalation dialog
|
||||
# count = get_map_count()
|
||||
# TODO: move into module
|
||||
if has_any_client() is False:
|
||||
if FLATPAK_ROOT_PATH in lookup(XDG.config, Preferences.DEFAULT):
|
||||
has_client = has_flatpak_client()
|
||||
else:
|
||||
has_client = has_steam_client()
|
||||
if has_client is False:
|
||||
EarlyAlertDialog(init.requires_steam)
|
||||
|
||||
bootwin = BootWindow(XDG, version)
|
||||
@@ -180,5 +184,6 @@ def load_gui(version: str, is_debug: bool) -> None:
|
||||
use_miles=use_miles,
|
||||
)
|
||||
print(boot.all_ok)
|
||||
load_steam_icon()
|
||||
app = App(prefs)
|
||||
app.run(None)
|
||||
@@ -51,7 +51,7 @@ INPUT_KEYBOARD = "input-keyboard-symbolic"
|
||||
LIST_ADD = "list-add-symbolic"
|
||||
REFRESH_ICON = "view-refresh-symbolic"
|
||||
SEARCH_ICON = "system-search-symbolic"
|
||||
STEAM_ICON = "steam_tray_mono"
|
||||
STEAM_ICON = "steam-tray-symbolic"
|
||||
VIEW_CONCEAL = "view-conceal-symbolic"
|
||||
VIEW_REVEAL = "view-reveal-symbolic"
|
||||
WARNING = "dialog-warning-symbolic"
|
||||
@@ -80,6 +80,7 @@ DEBUG_LOG = f"{APP_NAME}_DEBUG.LOG"
|
||||
SYSTEM_LOG = f"{APP_NAME}_SYSTEM.LOG"
|
||||
CHANGELOG_PATH = "data/CHANGELOG.md"
|
||||
IMAGES_PATH = "data/images"
|
||||
ICONS_PATH = "data/images/gtk"
|
||||
|
||||
HERO_PATH = "data/images/_hero.png"
|
||||
CSS_PATH = "data/app.css"
|
||||
@@ -89,7 +90,6 @@ FLATPAK_ROOT_PATH = ".var/app/com.valvesoftware.Steam"
|
||||
FLATPAK_STEAM_PATH = FLATPAK_ROOT_PATH + "/data/Steam"
|
||||
UBUNTU_STEAM_PATH = ".steam/steam"
|
||||
DEBIAN_STEAM_PATH = ".steam/debian-installation"
|
||||
STEAM_ICONS_PATH = "public"
|
||||
|
||||
LOG_FILTERS = ("CRITICAL", "WARNING", "INFO", "DEBUG")
|
||||
|
||||
|
||||
@@ -111,6 +111,10 @@ class Emitter(GObject.GObject):
|
||||
def check_toggled(self, label: str, state: bool) -> None:
|
||||
pass
|
||||
|
||||
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=())
|
||||
def servers_timed_out(self) -> None:
|
||||
pass
|
||||
|
||||
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(object,))
|
||||
def servers_loaded(self, tag: "ServerTab") -> None:
|
||||
pass
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.3.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M568 320C568 457 456.8 568 319.6 568C205.8 568 110 491.7 80.6 387.6L175.8 426.9C182.2 459 210.7 483.3 244.7 483.3C283.9 483.3 316.6 450.9 314.9 409.8L399.4 349.6C451.5 350.9 495.2 308.7 495.2 256.1C495.2 204.5 453.2 162.6 401.5 162.6C349.8 162.6 307.8 204.6 307.8 256.1L307.8 257.3L248.6 343C233.1 342.1 217.9 346.4 205.1 355.1L72 300.1C82.2 172.4 189.1 72 319.6 72C456.8 72 568 183 568 320zM227.7 448.3L197.2 435.7C202.8 447.3 212.5 456.5 224.4 461.5C251.3 472.7 282.2 459.9 293.4 433.1C298.8 420.1 298.9 405.8 293.5 392.8C288.1 379.8 278 369.6 265 364.2C252.1 358.8 238.3 359 226.1 363.6L257.6 376.6C277.4 384.8 286.8 407.5 278.5 427.3C270.2 447.2 247.5 456.5 227.7 448.3zM401.5 193.8C435.9 193.8 463.8 221.7 463.8 256.1C463.8 290.5 435.9 318.4 401.5 318.4C367.1 318.4 339.2 290.5 339.2 256.1C339.2 221.7 367.1 193.8 401.5 193.8zM401.6 302.8C427.4 302.8 448.4 281.8 448.4 256C448.4 230.2 427.4 209.2 401.6 209.2C375.8 209.2 354.8 230.2 354.8 256C354.8 281.8 375.8 302.8 401.6 302.8z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -3,11 +3,14 @@ import shutil
|
||||
import subprocess
|
||||
|
||||
from dzgui.const.constants import APP_NAME, FLATPAK_APPID, FLATPAK_CMD, STEAM_CMD
|
||||
from dzgui.init.proc import is_sandboxed
|
||||
|
||||
logger = logging.getLogger(APP_NAME)
|
||||
|
||||
|
||||
def has_flatpak_client() -> bool:
|
||||
if is_sandboxed():
|
||||
return True
|
||||
try:
|
||||
res = subprocess.run(
|
||||
[FLATPAK_CMD, "list", "--columns=application"],
|
||||
|
||||
@@ -92,6 +92,7 @@ class ServerModelManager:
|
||||
job = Servers.query_api
|
||||
params = Servers.params
|
||||
servers = []
|
||||
|
||||
with ThreadPoolExecutor() as executor:
|
||||
futures = [executor.submit(job, key, APPID_DAYZ, param) for param in params]
|
||||
for future in as_completed(futures):
|
||||
@@ -414,6 +415,8 @@ class ServerModelManager:
|
||||
# TODO: disable map, keyword, and filter widgets if model is None
|
||||
# signal driven (servers_empty, servers_failed_to_load)
|
||||
|
||||
self.emitter.emit("servers_timed_out")
|
||||
|
||||
if self.preserve_on_fail is False:
|
||||
self.tv.set_model(None)
|
||||
filter_man = self.tv.get_filter_man()
|
||||
|
||||
@@ -19,7 +19,7 @@ desc_flatpak_path = (
|
||||
desc_ubuntu_path = "This is the default Steam path on <b>Ubuntu-based systems</b>."
|
||||
desc_debian_path = "This is the default Steam path on <b>Debian-based systems</b>."
|
||||
no_valid_paths = (
|
||||
"No valid Steam paths found on system. Please install Steam to continue."
|
||||
"No valid Steam path or Steam command found on system. Please install Steam to continue."
|
||||
)
|
||||
button_scan = "Scan for Steam"
|
||||
|
||||
|
||||
@@ -297,7 +297,7 @@ class Options:
|
||||
init = Init(
|
||||
is_steam_running="Is Steam running? DZGUI must be run on top of Steam.",
|
||||
is_dayz_running="Is DayZ already running? DZGUI cannot launch DayZ if another process is using it.",
|
||||
requires_steam="DZGUI requires that Steam or Flatpak Steam be installed on the system.",
|
||||
requires_steam="Your chosen client (Steam/Flatpak Steam) must be installed on the system.",
|
||||
)
|
||||
|
||||
mod_panel = ModPanelStrings(
|
||||
|
||||
@@ -163,18 +163,24 @@ class RefreshButton(IconTextButton):
|
||||
self.set_tooltip_text(atomic_buttons.refresh_tooltip)
|
||||
|
||||
self.connect("clicked", self._on_refresh_clicked)
|
||||
emitter.connect("servers_loaded", self.start_decrement)
|
||||
emitter.connect("servers_loaded", self._on_load)
|
||||
emitter.connect("servers_timed_out", self._on_timeout)
|
||||
|
||||
def _on_timeout(self, emitter: "Emitter") -> None:
|
||||
self.is_clicked = True
|
||||
self.start_decrement()
|
||||
|
||||
def _on_load(self, emitter: "Emitter", tab: "ServerTab") -> None:
|
||||
self.start_decrement()
|
||||
|
||||
def _on_refresh_clicked(self, button: Self) -> None:
|
||||
"""Spawned in a thread"""
|
||||
if self.controller.get_active_treeview().is_loaded() is False:
|
||||
return
|
||||
self.is_clicked = True
|
||||
self.controller.refresh_tree()
|
||||
# TODO: get server tab enum
|
||||
# if LAN tab, reload existing entries in place
|
||||
|
||||
def start_decrement(self, emitter: "Emitter", tab: "ServerTab") -> None:
|
||||
def start_decrement(self) -> None:
|
||||
if self.is_clicked is False:
|
||||
return
|
||||
if self.loading:
|
||||
|
||||
+2
-1
@@ -110,10 +110,11 @@ config-settings-package = { pygobject-stubs = { config = "Gtk3,Gdk3,Soup2" } }
|
||||
markers = [
|
||||
"apitest: checks remote endpoints",
|
||||
"config: config file keys/values",
|
||||
"realconfig: depends on actual generated local config file",
|
||||
"flatpak: depends on local flatpak installation",
|
||||
"mods: tests mod metadata/link creation",
|
||||
"pefile: validate PE files",
|
||||
"post_install: requires a completed installation",
|
||||
"realconfig: depends on actual generated local config file",
|
||||
"redact: log redaction mechanisms",
|
||||
"slow: long-running tests",
|
||||
"webtest: depends on remote endpoint",
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import configparser
|
||||
import pytest
|
||||
|
||||
from dzgui.const.constants import FLATPAK_APPID, GTK_APP_ID
|
||||
from dzgui.config.xdg import get_xdg_paths
|
||||
from dzgui.util.flatpak import apply_overrides
|
||||
|
||||
PATHS_KEY = "Context"
|
||||
PATHS_SUBKEY = "filesystems"
|
||||
BUS_KEY = "Session Bus Policy"
|
||||
|
||||
pytestmark = pytest.mark.flatpak
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def xdg_paths() -> dict[str, str]:
|
||||
return get_xdg_paths()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def override(xdg_paths) -> None:
|
||||
apply_overrides(xdg_paths)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def config(xdg_paths) -> configparser.ConfigParser:
|
||||
conf_path = xdg_paths["XDG_DATA_HOME"].parent.joinpath(
|
||||
f"flatpak/overrides/{FLATPAK_APPID}"
|
||||
)
|
||||
config = configparser.ConfigParser()
|
||||
config.read(conf_path)
|
||||
return config
|
||||
|
||||
|
||||
def test_session_bus(override, config) -> None:
|
||||
bus = config[BUS_KEY][GTK_APP_ID]
|
||||
assert bus == "own"
|
||||
|
||||
|
||||
def test_paths(override, xdg_paths, config) -> None:
|
||||
expect = xdg_paths
|
||||
paths = config[PATHS_KEY][PATHS_SUBKEY].split(";")
|
||||
assert all(str(path) in paths for path in expect.values())
|
||||
@@ -1,3 +1,5 @@
|
||||
import pytest
|
||||
|
||||
from dzgui.api.servers import Details
|
||||
from dzgui.views.dialogs.servers import ServerDetailsDialog
|
||||
|
||||
@@ -21,6 +23,7 @@ class MockController:
|
||||
return None
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
|
||||
def test_html_escaping() -> None:
|
||||
name = "Test server"
|
||||
desc = "<Server description> Game & mods"
|
||||
@@ -31,5 +34,7 @@ def test_html_escaping() -> None:
|
||||
controller = MockController()
|
||||
dialog = ServerDetailsDialog(controller, details)
|
||||
dialog.destroy()
|
||||
while Gtk.events_pending():
|
||||
Gtk.main_iteration()
|
||||
|
||||
assert dialog.description.get_text() == desc
|
||||
@@ -1,3 +1,4 @@
|
||||
import pytest
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
@@ -9,6 +10,8 @@ from dzgui.const.constants import (
|
||||
)
|
||||
from dzgui.init import proc
|
||||
|
||||
pytestmark = pytest.mark.flatpak
|
||||
|
||||
|
||||
class TestSteamDetection(unittest.TestCase):
|
||||
def test_flatpak_detection_with_multiple_running_apps(self):
|
||||
|
||||
Reference in new issue
Block a user