mirror of
https://github.com/aclist/dztui.git
synced 2026-10-29 22:22:52 +01:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4eec00e8e7 | ||
|
|
09ef3e446a |
No files matched your search
+8
-20
@@ -255,28 +255,16 @@ class PeFileError(Exception):
|
|||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def parse_version_number(data: BinaryIO) -> FileVersion:
|
def parse_version_number(data: BinaryIO) -> FileVersion:
|
||||||
# https://learn.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
|
# https://learn.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
|
||||||
"""
|
minor = struct.unpack("<L", data.read(4))[0] >> 16 & 0xFFFF
|
||||||
Note: structure differs from standard VS_FIXEDFILEINFO
|
major = struct.unpack("<L", data.read(4))[0] >> 0 & 0xFFFF
|
||||||
Major: lower 16 bits of first DWORD
|
build = struct.unpack("<L", data.read(4))[0] >> 0 & 0xFFFF
|
||||||
Minor: upper 16 bits of first DWORD
|
# NOTE: 0-pad revision number
|
||||||
Build: lower 16 bits of third DWORD
|
revision = str(struct.unpack("<L", data.read(4))[0] >> 16 & 0xFFFF)
|
||||||
Revision: upper 16 bits of second DWORD, zero-padded
|
offset = 3 - len(revision)
|
||||||
Lower 16 bits of revision DWORD appear unused.
|
padded = "0" * offset + revision
|
||||||
"""
|
return FileVersion(major, minor, build, padded)
|
||||||
major_minor = struct.unpack("<I", data.read(4))[0]
|
|
||||||
revision_pair = struct.unpack("<I", data.read(4))[0]
|
|
||||||
build_dword = struct.unpack("<I", data.read(4))[0]
|
|
||||||
|
|
||||||
major = major_minor & 0xFFFF
|
|
||||||
minor = (major_minor >> 16) & 0xFFFF
|
|
||||||
build = build_dword & 0xFFFF
|
|
||||||
revision = (revision_pair >> 16) & 0xFFFF
|
|
||||||
revision = f"{revision:03d}"
|
|
||||||
|
|
||||||
return FileVersion(major, minor, build, revision)
|
|
||||||
|
|
||||||
|
|
||||||
def seek_to_hex(address: str, data: BinaryIO) -> None:
|
def seek_to_hex(address: str, data: BinaryIO) -> None:
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ def get_details(record: Record) -> Details | None:
|
|||||||
dlc = strings.dlc_none
|
dlc = strings.dlc_none
|
||||||
case 2:
|
case 2:
|
||||||
dlc = strings.dlc_frostline
|
dlc = strings.dlc_frostline
|
||||||
case 4:
|
case 3:
|
||||||
dlc = strings.dlc_badlands
|
dlc = strings.dlc_badlands
|
||||||
case _:
|
case _:
|
||||||
dlc = strings.unspecified
|
dlc = strings.unspecified
|
||||||
|
|||||||
+6
-6
@@ -11,7 +11,7 @@ from typing import Any, Union
|
|||||||
from warnings import deprecated
|
from warnings import deprecated
|
||||||
|
|
||||||
from dzgui.api.acf import ACF
|
from dzgui.api.acf import ACF
|
||||||
from dzgui.init.prereqs import has_steam_client
|
from dzgui.init.prereqs import has_any_client
|
||||||
from dzgui.const.constants import (
|
from dzgui.const.constants import (
|
||||||
APPID_DAYZ,
|
APPID_DAYZ,
|
||||||
APPID_DAYZ_EXP,
|
APPID_DAYZ_EXP,
|
||||||
@@ -59,7 +59,7 @@ class VDFLoadError(Exception):
|
|||||||
|
|
||||||
def get_steam_paths() -> list[tuple[Path, str]]:
|
def get_steam_paths() -> list[tuple[Path, str]]:
|
||||||
paths = []
|
paths = []
|
||||||
if has_steam_client():
|
if has_any_client():
|
||||||
HOME = Path.home()
|
HOME = Path.home()
|
||||||
env = os.environ.get("XDG_DATA_HOME")
|
env = os.environ.get("XDG_DATA_HOME")
|
||||||
if env is not None:
|
if env is not None:
|
||||||
@@ -245,9 +245,9 @@ def find_user_id(path: Path) -> str | None:
|
|||||||
last_user = str(next(iter(users)))
|
last_user = str(next(iter(users)))
|
||||||
if len(users) == 1:
|
if len(users) == 1:
|
||||||
return last_user
|
return last_user
|
||||||
last_stamp = int(users[last_user]["timestamp"])
|
last_stamp = int(users[last_user]["Timestamp"])
|
||||||
for user in users:
|
for user in users:
|
||||||
stamp = int(users[user]["timestamp"])
|
stamp = int(users[user]["Timestamp"])
|
||||||
if stamp > last_stamp:
|
if stamp > last_stamp:
|
||||||
last_stamp = stamp
|
last_stamp = stamp
|
||||||
last_user = user
|
last_user = user
|
||||||
@@ -265,12 +265,12 @@ def find_user_id_32(path: Path) -> int:
|
|||||||
|
|
||||||
|
|
||||||
class SteamAPIKeyError(Exception):
|
class SteamAPIKeyError(Exception):
|
||||||
def __init__(self, msg: str | None = None):
|
def __init__(self, msg: str | None = None) -> None:
|
||||||
super().__init__(msg or api_validation_error)
|
super().__init__(msg or api_validation_error)
|
||||||
|
|
||||||
|
|
||||||
class SteamWorkshopEndpointError(Exception):
|
class SteamWorkshopEndpointError(Exception):
|
||||||
def __init__(self, msg: str | None = None):
|
def __init__(self, msg: str | None = None) -> None:
|
||||||
super().__init__(msg or workshop_endpoint_error)
|
super().__init__(msg or workshop_endpoint_error)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -15,7 +15,7 @@ from dzgui.init.migrate import (
|
|||||||
migrate_cols_file,
|
migrate_cols_file,
|
||||||
)
|
)
|
||||||
from dzgui.init.flock import lock_acquire
|
from dzgui.init.flock import lock_acquire
|
||||||
from dzgui.init.prereqs import has_steam_client
|
from dzgui.init.prereqs import has_any_client
|
||||||
from dzgui.strings import boot
|
from dzgui.strings import boot
|
||||||
|
|
||||||
from dzgui.util.deck import is_steam_deck, is_game_mode
|
from dzgui.util.deck import is_steam_deck, is_game_mode
|
||||||
@@ -136,7 +136,7 @@ def load_gui(version: str, is_debug: bool) -> None:
|
|||||||
# TODO: sudo escalation dialog
|
# TODO: sudo escalation dialog
|
||||||
# count = get_map_count()
|
# count = get_map_count()
|
||||||
# TODO: move into module
|
# TODO: move into module
|
||||||
if has_steam_client() is False:
|
if has_any_client() is False:
|
||||||
EarlyAlertDialog(init.requires_steam)
|
EarlyAlertDialog(init.requires_steam)
|
||||||
|
|
||||||
bootwin = BootWindow(XDG, version)
|
bootwin = BootWindow(XDG, version)
|
||||||
|
|||||||
+20
-7
@@ -7,19 +7,32 @@ from dzgui.const.constants import APP_NAME, FLATPAK_APPID, FLATPAK_CMD, STEAM_CM
|
|||||||
logger = logging.getLogger(APP_NAME)
|
logger = logging.getLogger(APP_NAME)
|
||||||
|
|
||||||
|
|
||||||
def has_steam_client() -> bool:
|
def has_flatpak_client() -> bool:
|
||||||
if shutil.which(STEAM_CMD):
|
|
||||||
return True
|
|
||||||
if not shutil.which(FLATPAK_CMD):
|
|
||||||
return False
|
|
||||||
try:
|
try:
|
||||||
res = subprocess.run(
|
res = subprocess.run(
|
||||||
[FLATPAK_CMD, "list"], capture_output=True, text=True, check=True
|
[FLATPAK_CMD, "list", "--columns=application"],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=True,
|
||||||
)
|
)
|
||||||
if FLATPAK_APPID in res.stdout:
|
if FLATPAK_APPID in res.stdout:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
except subprocess.CalledProcessError as e:
|
except Exception as e:
|
||||||
logger.critical(e)
|
logger.critical(e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def has_steam_client() -> bool:
|
||||||
|
if shutil.which(STEAM_CMD):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def has_any_client() -> bool:
|
||||||
|
if shutil.which(STEAM_CMD):
|
||||||
|
return True
|
||||||
|
if not shutil.which(FLATPAK_CMD):
|
||||||
|
return False
|
||||||
|
return has_flatpak_client()
|
||||||
@@ -3,6 +3,8 @@ from dzgui.strings import options
|
|||||||
from dzgui.views.components.box import HBox
|
from dzgui.views.components.box import HBox
|
||||||
from dzgui.views.components.buttons import Icon
|
from dzgui.views.components.buttons import Icon
|
||||||
|
|
||||||
|
from typing import Self
|
||||||
|
from dzgui.init.prereqs import has_steam_client, has_flatpak_client
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
|
|
||||||
@@ -14,36 +16,55 @@ class ClientCombo(Gtk.ComboBox):
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.client_store = Gtk.ListStore(str, str)
|
has_steam = has_steam_client()
|
||||||
|
has_flatpak = has_flatpak_client()
|
||||||
|
self.client_store = Gtk.ListStore(str, str, bool)
|
||||||
self.clients = (
|
self.clients = (
|
||||||
(
|
(
|
||||||
options.steam_combo,
|
options.steam_combo,
|
||||||
STEAM_CMD,
|
STEAM_CMD,
|
||||||
|
has_steam,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
options.flatpak_combo,
|
options.flatpak_combo,
|
||||||
FLATPAK_RUN_CMD,
|
FLATPAK_RUN_CMD,
|
||||||
|
has_flatpak,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
options.flatpak_container_combo,
|
options.flatpak_container_combo,
|
||||||
FLATPAK_SANDBOX,
|
FLATPAK_SANDBOX,
|
||||||
|
has_flatpak,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
for client in self.clients:
|
for client in self.clients:
|
||||||
self.client_store.append(client)
|
self.client_store.append(client)
|
||||||
|
|
||||||
self.set_model(self.client_store)
|
self.set_model(self.client_store)
|
||||||
renderer_text = Gtk.CellRendererText()
|
renderer_text = Gtk.CellRendererText()
|
||||||
self.pack_start(renderer_text, True)
|
self.pack_start(renderer_text, True)
|
||||||
self.add_attribute(renderer_text, "text", 0)
|
self.add_attribute(renderer_text, "text", 0)
|
||||||
self.set_active(0)
|
self.set_active(0)
|
||||||
|
|
||||||
|
self.set_cell_data_func(self.get_cells()[0], self.data_func)
|
||||||
|
|
||||||
|
def data_func(
|
||||||
|
self,
|
||||||
|
combo: Self,
|
||||||
|
cell: Gtk.CellRendererText,
|
||||||
|
model: Gtk.ListStore,
|
||||||
|
_iter: Gtk.TreeIter,
|
||||||
|
) -> None:
|
||||||
|
sens = model[_iter][2]
|
||||||
|
cell.set_property("sensitive", sens)
|
||||||
|
|
||||||
def get_client_human_readable(self, cmd: str) -> str:
|
def get_client_human_readable(self, cmd: str) -> str:
|
||||||
for client in self.clients:
|
for client in self.clients:
|
||||||
human, command = client
|
human, command, sens = client
|
||||||
if command == cmd:
|
if command == cmd:
|
||||||
return human
|
return human
|
||||||
raise TypeError("Not a valid Steam client selection")
|
raise TypeError("Not a valid Steam client selection")
|
||||||
|
|
||||||
|
|
||||||
class ErrorPopover(Gtk.Popover):
|
class ErrorPopover(Gtk.Popover):
|
||||||
def __init__(self, relative_to: Gtk.Widget, position: Gtk.PositionType) -> None:
|
def __init__(self, relative_to: Gtk.Widget, position: Gtk.PositionType) -> None:
|
||||||
super().__init__(relative_to=relative_to, position=position)
|
super().__init__(relative_to=relative_to, position=position)
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ description = "DayZ server browser and mod manager for Linux"
|
|||||||
authors = [
|
authors = [
|
||||||
{name = "aclist"}
|
{name = "aclist"}
|
||||||
]
|
]
|
||||||
version = "7.0.0b28"
|
version = "7.0.0b26"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|||||||
+1
-1
@@ -8,6 +8,6 @@
|
|||||||
"WantsOfflineMode" "0"
|
"WantsOfflineMode" "0"
|
||||||
"SkipOfflineModeWarning" "0"
|
"SkipOfflineModeWarning" "0"
|
||||||
"AutoLogin" "1"
|
"AutoLogin" "1"
|
||||||
"timestamp" "0"
|
"Timestamp" "0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -8,7 +8,7 @@
|
|||||||
"WantsOfflineMode" "0"
|
"WantsOfflineMode" "0"
|
||||||
"SkipOfflineModeWarning" "0"
|
"SkipOfflineModeWarning" "0"
|
||||||
"AutoLogin" "1"
|
"AutoLogin" "1"
|
||||||
"timestamp" "1787904411"
|
"Timestamp" "1787904411"
|
||||||
}
|
}
|
||||||
"1"
|
"1"
|
||||||
{
|
{
|
||||||
@@ -18,6 +18,6 @@
|
|||||||
"WantsOfflineMode" "0"
|
"WantsOfflineMode" "0"
|
||||||
"SkipOfflineModeWarning" "0"
|
"SkipOfflineModeWarning" "0"
|
||||||
"AutoLogin" "1"
|
"AutoLogin" "1"
|
||||||
"timestamp" "1787904647"
|
"Timestamp" "1787904647"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"WantsOfflineMode" "0"
|
"WantsOfflineMode" "0"
|
||||||
"SkipOfflineModeWarning" "0"
|
"SkipOfflineModeWarning" "0"
|
||||||
"AutoLogin" "1"
|
"AutoLogin" "1"
|
||||||
"timestamp" "1797904411"
|
"Timestamp" "1797904411"
|
||||||
}
|
}
|
||||||
"1"
|
"1"
|
||||||
{
|
{
|
||||||
@@ -18,6 +18,6 @@
|
|||||||
"WantsOfflineMode" "0"
|
"WantsOfflineMode" "0"
|
||||||
"SkipOfflineModeWarning" "0"
|
"SkipOfflineModeWarning" "0"
|
||||||
"AutoLogin" "1"
|
"AutoLogin" "1"
|
||||||
"timestamp" "1787904647"
|
"Timestamp" "1787904647"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -9,6 +9,6 @@
|
|||||||
"SkipOfflineModeWarning" "0"
|
"SkipOfflineModeWarning" "0"
|
||||||
"AllowAutoLogin" "1"
|
"AllowAutoLogin" "1"
|
||||||
"MostRecent" "1"
|
"MostRecent" "1"
|
||||||
"timestamp" "0"
|
"Timestamp" "0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
"SkipOfflineModeWarning" "0"
|
"SkipOfflineModeWarning" "0"
|
||||||
"AllowAutoLogin" "1"
|
"AllowAutoLogin" "1"
|
||||||
"MostRecent" "0"
|
"MostRecent" "0"
|
||||||
"timestamp" "0"
|
"Timestamp" "0"
|
||||||
}
|
}
|
||||||
"1"
|
"1"
|
||||||
{
|
{
|
||||||
@@ -20,6 +20,6 @@
|
|||||||
"SkipOfflineModeWarning" "0"
|
"SkipOfflineModeWarning" "0"
|
||||||
"AllowAutoLogin" "1"
|
"AllowAutoLogin" "1"
|
||||||
"MostRecent" "1"
|
"MostRecent" "1"
|
||||||
"timestamp" "10"
|
"Timestamp" "10"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ gi.require_version("Gtk", "3.0")
|
|||||||
from gi.repository import Gtk, Gio, GLib # noqa
|
from gi.repository import Gtk, Gio, GLib # noqa
|
||||||
|
|
||||||
|
|
||||||
class DummyWidget(ColorAwareApp, Gtk.Button):
|
class TestWidget(ColorAwareApp, Gtk.Button):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
@@ -22,10 +22,11 @@ class DummyWidget(ColorAwareApp, Gtk.Button):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def widget() -> DummyWidget:
|
def widget() -> TestWidget:
|
||||||
return DummyWidget()
|
return TestWidget()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.integration
|
||||||
@pytest.mark.parametrize("key, expect", [("default", False), ("prefer-dark", True)])
|
@pytest.mark.parametrize("key, expect", [("default", False), ("prefer-dark", True)])
|
||||||
def test_light_mode(widget, key: str, expect: bool) -> None:
|
def test_light_mode(widget, key: str, expect: bool) -> None:
|
||||||
local_pref = subprocess.run(
|
local_pref = subprocess.run(
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import pytest
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from dzgui.api.steam import find_user_id
|
from dzgui.api.steam import find_user_id
|
||||||
from dzgui.const.constants import DEFAULT_STEAM_PATH
|
|
||||||
from tests.fixtures import fixture_path
|
from tests.fixtures import fixture_path
|
||||||
|
|
||||||
pytestmark = pytest.mark.apitest
|
pytestmark = pytest.mark.apitest
|
||||||
@@ -26,11 +25,3 @@ def test_loginusers(monkeypatch, fixture: str, expect: int) -> None:
|
|||||||
monkeypatch.setattr("dzgui.api.steam.find_loginusers", mock_loginusers)
|
monkeypatch.setattr("dzgui.api.steam.find_loginusers", mock_loginusers)
|
||||||
uid = find_user_id(Path(""))
|
uid = find_user_id(Path(""))
|
||||||
assert int(uid) == expect
|
assert int(uid) == expect
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.realconfig
|
|
||||||
def test_live_loginusers() -> None:
|
|
||||||
"""Added on 2026-10-17 following changes to VDF keys"""
|
|
||||||
steam = Path.home().joinpath(DEFAULT_STEAM_PATH)
|
|
||||||
uid = find_user_id(steam)
|
|
||||||
assert uid is not None
|
|
||||||
Reference in new issue
Block a user