Repository: lutris/lutris

Issue:
Copy dgvoodoo2 config file to the prefix
Lutris needs to copy/symlink the dgVoodoo.conf file from inside the version package into \AppData\Roaming\dgVoodoo\ so that there's no watermark in-game.


Discussion:

Resolving patch:
diff --git a/lutris/util/wine/dgvoodoo2.py b/lutris/util/wine/dgvoodoo2.py
--- a/lutris/util/wine/dgvoodoo2.py
+++ b/lutris/util/wine/dgvoodoo2.py
@@ -9,4 +9,5 @@ class dgvoodoo2Manager(DLLManager):
     base_dir = os.path.join(RUNTIME_DIR, "dgvoodoo2")
     versions_path = os.path.join(base_dir, "dgvoodoo2_versions.json")
     managed_dlls = ("d3dimm", "ddraw", "glide", "glide2x", "glide3x", )
+    managed_appdata_files = ["dgVoodoo/dgVoodoo.conf"]
     releases_url = "https://api.github.com/repos/lutris/dgvoodoo2/releases"
diff --git a/lutris/util/wine/dll_manager.py b/lutris/util/wine/dll_manager.py
--- a/lutris/util/wine/dll_manager.py
+++ b/lutris/util/wine/dll_manager.py
@@ -8,6 +8,7 @@
 from lutris.util.extract import extract_archive
 from lutris.util.http import download_file
 from lutris.util.log import logger
+from lutris.util.wine.prefix import WinePrefixManager
 
 
 class DLLManager:
@@ -15,6 +16,7 @@ class DLLManager:
     component = NotImplemented
     base_dir = NotImplemented
     managed_dlls = NotImplemented
+    managed_appdata_files = []  # most managers have none
     versions_path = NotImplemented
     releases_url = NotImplemented
     archs = {
@@ -154,6 +156,35 @@ def disable_dll(self, system_dir, _arch, dll):  # pylint: disable=unused-argumen
                 os.remove(wine_dll_path)
             shutil.move(wine_dll_path + ".orig", wine_dll_path)
 
+    def enable_user_file(self, appdata_dir, file_path, source_path):
+        if system.path_exists(source_path):
+            wine_file_path = os.path.join(appdata_dir, file_path)
+            wine_file_dir = os.path.dirname(wine_file_path)
+            if system.path_exists(wine_file_path):
+                if not os.path.islink(wine_file_path):
+                    # Backing up original version (may not be needed)
+                    shutil.move(wine_file_path, wine_file_path + ".orig")
+                else:
+                    os.remove(wine_file_path)
+
+            if not os.path.isdir(wine_file_dir):
+                os.makedirs(wine_file_dir)
+
+            try:
+                os.symlink(source_path, wine_file_path)
+            except OSError:
+                logger.error("Failed linking %s to %s", source_path, wine_file_path)
+        else:
+            self.disable_user_file(appdata_dir, file_path)
+
+    def disable_user_file(self, appdata_dir, file_path):
+        wine_file_path = os.path.join(appdata_dir, file_path)
+        # We only create a symlink; if it is a real file, it mus tbe user data.
+        if system.path_exists(wine_file_path) and os.path.islink(wine_file_path):
+            os.remove(wine_file_path)
+            if system.path_exists(wine_file_path + ".orig"):
+                shutil.move(wine_file_path + ".orig", wine_file_path)
+
     def _iter_dlls(self):
         windows_path = os.path.join(self.prefix, "drive_c/windows")
         if self.wine_arch == "win64":
@@ -168,6 +199,14 @@ def _iter_dlls(self):
             for dll in self.managed_dlls:
                 yield system_dir, arch, dll
 
+    def _iter_appdata_files(self):
+        if self.managed_appdata_files:
+            prefix_manager = WinePrefixManager(self.prefix)
+            appdata_dir = prefix_manager.appdata_dir
+            for file in self.managed_appdata_files:
+                filename = os.path.basename(file)
+                yield appdata_dir, file, filename
+
     def enable(self):
         """Enable Dlls for the current prefix"""
         if not self.is_available():
@@ -178,11 +217,16 @@ def enable(self):
         for system_dir, arch, dll in self._iter_dlls():
             dll_path = os.path.join(self.path, arch, "%s.dll" % dll)
             self.enable_dll(system_dir, arch, dll_path)
+        for appdata_dir, file, filename in self._iter_appdata_files():
+            source_path = os.path.join(self.path, filename)
+            self.enable_user_file(appdata_dir, file, source_path)
 
     def disable(self):
         """Disable DLLs for the current prefix"""
         for system_dir, arch, dll in self._iter_dlls():
             self.disable_dll(system_dir, arch, dll)
+        for appdata_dir, file, _filename in self._iter_appdata_files():
+            self.disable_user_file(appdata_dir, file)
 
     def fetch_versions(self):
         """Get releases from GitHub"""
diff --git a/lutris/util/wine/prefix.py b/lutris/util/wine/prefix.py
--- a/lutris/util/wine/prefix.py
+++ b/lutris/util/wine/prefix.py
@@ -48,6 +48,28 @@ def __init__(self, path):
             logger.warning("No path specified for Wine prefix")
         self.path = path
 
+    @property
+    def user_dir(self):
+        """Returns the directory that contains the current user's profile in the WINE prefix."""
+        user = os.getenv("USER") or 'lutrisuser'
+        return os.path.join(self.path, "drive_c/users/", user)
+
+    @property
+    def appdata_dir(self):
+        """Returns the app-data directory for the user; this depends on a registry key."""
+        user_dir = self.user_dir
+        folder = self.get_registry_key(
+            self.hkcu_prefix + "/Software/Microsoft/Windows/CurrentVersion/Explorer/Shell Folders",
+            "AppData",
+        )
+
+        # Don't try to resolve the WIndows path we get- there's
+        # just two options, the Vista-and later option and the
+        # XP-and-earlier option.
+        if folder.lower().endswith("\\application data"):
+            return os.path.join(user_dir, "Application Data")  # Windows XP
+        return os.path.join(user_dir, "AppData/Roaming")  # Vista
+
     def setup_defaults(self):
         """Sets the defaults for newly created prefixes"""
         for dll, value in DEFAULT_DLL_OVERRIDES.items():
@@ -121,8 +143,7 @@ def desktop_integration(self, desktop_dir=None, restore=False):  # noqa: C901
         """Overwrite desktop integration"""
         # pylint: disable=too-many-branches
         # TODO: reduce complexity (18)
-        user = os.getenv("USER") or 'lutrisuser'
-        user_dir = os.path.join(self.path, "drive_c/users/", user)
+        user_dir = self.user_dir
         desktop_folders = self.get_desktop_folders()
         desktop_dir = os.path.expanduser(desktop_dir) if desktop_dir else user_dir
 


Test patch: